Skip to content

Test: Comprehensive JS event tracking for lifecycle states#10008

Open
jellefoks wants to merge 2 commits intoyoutube:26.eapfrom
jellefoks:feature/test-lifecycle-events
Open

Test: Comprehensive JS event tracking for lifecycle states#10008
jellefoks wants to merge 2 commits intoyoutube:26.eapfrom
jellefoks:feature/test-lifecycle-events

Conversation

@jellefoks
Copy link
Copy Markdown
Member

@jellefoks jellefoks commented Apr 13, 2026

This PR enhances the test_lifecycle.sh integration test to actively monitor and verify standard DOM lifecycle events (focus, blur, freeze, and unfreeze/resume) during Starboard OS state transitions.

Key Additions & Robustness

  • Monitoring focus/blur and freeze/unfreeze: Injects a JavaScript event logger (window.event_log) via DevTools to actively record focus, blur, freeze, resume, and visibilitychange events dispatched by the application. This ensures that the web application receives the proper standard Web APIs signaling when the underlying platform transitions between states.
  • Deterministic Event Queuing: Replaces brittle sleep-based timing with a deterministic "pop-from-front" array queue approach. The test explicitly waits for the array to populate and pops each expected event individually, ensuring that the correct sequence of events is fired.
  • Robust Load Environment: The test now relies on a base64-encoded data:text/html URL payload using a simple HTML string. This completely bypasses QuotaDatabase IO locks, ServiceWorker database conflicts, and complex JavaScript garbage collection crashes (often seen when testing against heavy remote origins like YouTube TV), ensuring reliable testing of the underlying event delivery without temporary file conflicts.
  • State Verification: Validates that document.hasFocus() and document.visibilityState accurately reflect the true lifecycle state prior to verifying the individual dispatched events. We're testing more comprehensively and more reliably.

Bug: 448156280

- Injects an event logger array to monitor blur, focus, freeze, resume, and visibilitychange events via DevTools.
- Replaces brittle sleep-based timing with deterministic CDP evaluation checks.
- Verifies that correct Web API events are dispatched during all Starboard suspend state transitions.
@github-actions
Copy link
Copy Markdown
Contributor

🤖 Gemini Suggested Commit Message


test: Verify lifecycle JS event dispatch

This change enhances the lifecycle test script to track and verify
JavaScript events during Starboard lifecycle transitions. It injects
an event logger into the DOM via CDP and uses a robust polling mechanism
to assert the correct dispatch of visibilitychange, focus, blur, freeze,
and resume events.

This improves test coverage and reliability for critical lifecycle
event handling, ensuring Cobalt behaves as expected when responding
to system-level state changes.

Bug: 10008

💡 Pro Tips for a Better Commit Message:

  1. Influence the Result: Want to change the output? You can write custom prompts or instructions directly in the Pull Request description. The model uses that text to generate the message.
  2. Re-run the Generator: Post a comment with: /generate-commit-message

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances the lifecycle testing tools by introducing a more robust event-driven verification mechanism. Key changes include updating cdp_js_helper.py to support remote hosts and polling for readiness, and modifying test_lifecycle.sh to use a local HTTP server and an injected event logger for precise state transition tracking. Feedback focuses on improving time measurement reliability in Python, addressing potential port conflicts and remote testing limitations in the shell scripts, and refining process termination and string matching logic for better stability.

Comment on lines +88 to +89
start_time = asyncio.get_event_loop().time()
while (asyncio.get_event_loop().time() - start_time) < total_wait:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using asyncio.get_event_loop().time() is generally fine within a running loop, but time.monotonic() is the standard and more robust way to measure elapsed time for timeouts in Python, as it is independent of the event loop state and clock adjustments.

echo "[TEST] Starting local Python HTTP server..."
mkdir -p /tmp/cobalt_test_server
echo "<html><body><h1>Test</h1><input autofocus></body></html>" > /tmp/cobalt_test_server/index.html
python3 -m http.server 4000 --directory /tmp/cobalt_test_server > /dev/null 2>&1 &
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The HTTP server is started on a hardcoded port (4000). This can cause conflicts if multiple instances of the test are run on the same machine or if the port is already in use. Additionally, the cleanup logic at the start of the script (lines 25-41) does not check for or terminate stale HTTP server processes from previous failed runs, which could lead to the new server failing to start.

rm -f $LOG_FILE

$EXECUTABLE --remote-debugging-port=$PORT --no-sandbox > $LOG_FILE 2>&1 &
$EXECUTABLE --url="http://127.0.0.1:4000/" --remote-debugging-port=$PORT --no-sandbox > $LOG_FILE 2>&1 &
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The --url is hardcoded to 127.0.0.1. If the test is run against a remote device (by setting TEST_LIFECYCLE_HOST), Cobalt running on that device will attempt to connect to a server on its own loopback interface rather than the machine running this script. Consider using the actual IP address of the host machine or making this configurable to support remote testing scenarios.

echo "FAILURE: Cobalt (PID: $COBALT_PID) did not stop after SIGPWR."
echo "[TEST] Cleaning up Cobalt (PID: $COBALT_PID)..."
kill -9 $COBALT_PID
kill -9 $SERVER_PID 2>/dev/null || true
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using kill -9 (SIGKILL) for the HTTP server is unnecessary as a first resort. It's better to use SIGTERM (the default for kill) to allow the process to exit gracefully. This applies to both instances where the server is terminated (lines 144 and 148).

Suggested change
kill -9 $SERVER_PID 2>/dev/null || true
kill $SERVER_PID 2>/dev/null || true

exit 1
fi

kill -9 $SERVER_PID 2>/dev/null || true
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using kill -9 (SIGKILL) for the HTTP server is unnecessary as a first resort. It's better to use SIGTERM (the default for kill) to allow the process to exit gracefully.

Suggested change
kill -9 $SERVER_PID 2>/dev/null || true
kill $SERVER_PID 2>/dev/null || true

RESULT=$(vpython3 cobalt/tools/cdp_js_helper.py --port $PORT "$EXPR" 2>/dev/null)
if [ "$RESULT" == "$EXPECTED" ]; then
RESULT=$(vpython3 cobalt/tools/cdp_js_helper.py --host $HOST --port $PORT "$EXPR" 2>/dev/null)
if [[ "$RESULT" == *"$EXPECTED"* ]]; then
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The transition from an exact match to a substring match ([[ "$RESULT" == *"$EXPECTED"* ]]) is risky and can lead to false positives. For example, if the expected state is visible, this condition would incorrectly pass if the result is an error message containing that word (e.g., ERROR: visible state not reached). Since cdp_js_helper.py now returns clean string representations of the values, an exact match is safer and more reliable.

Suggested change
if [[ "$RESULT" == *"$EXPECTED"* ]]; then
if [ "$RESULT" == "$EXPECTED" ]; then

@jellefoks jellefoks requested review from a team as code owners April 13, 2026 22:39
@jellefoks jellefoks requested a review from niranjanyardi April 13, 2026 22:39
- Injects an event logger array to monitor blur, focus, freeze, resume, and visibilitychange events via DevTools.
- Replaces brittle sleep-based timing with deterministic CDP evaluation checks.
- Verifies that correct Web API events are dispatched during all Starboard suspend state transitions.
@jellefoks jellefoks force-pushed the feature/test-lifecycle-events branch from 062ce4f to 9542dea Compare April 14, 2026 17:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant