From eb0d03adcfb1a8f13141256cdd34d9e4ff72dee7 Mon Sep 17 00:00:00 2001 From: Rob Hogan <2590098+robhogan@users.noreply.github.com> Date: Fri, 13 Nov 2026 19:37:25 +0000 Subject: [PATCH] Wait for RNTester before each visual deep link and retry until it opens RNTester ignores a deep link until its JS has rendered, but `open-example.yml` only waited for animations to end, which happens about 1.4s after relaunch, before RNTester takes links (about 2.7s). Since #59994 sent the link once on iOS, 17 of 25 iOS capture jobs had a flow fail its first attempt this way. The helper now waits for the "Components" tab label, which RNTester's tab bar shows on every screen, then links once. It also takes the ID of an element only that example has, and relaunches and links again until it's visible, up to 3 times, since a relaunch can restore the previous example, which has the same `example-container`. Changelog: [Internal] --- packages/rn-tester/visual-tests/README.md | 7 +-- .../rn-tester/visual-tests/flows/border.yml | 3 ++ .../rn-tester/visual-tests/flows/button.yml | 4 ++ .../rn-tester/visual-tests/flows/image.yml | 2 + .../visual-tests/flows/scroll-view.yml | 3 ++ .../rn-tester/visual-tests/flows/switch.yml | 3 ++ .../visual-tests/flows/text-input.yml | 3 ++ .../flows/text-last-line-clipping.yml | 1 + .../visual-tests/flows/text-width-mode.yml | 1 + .../rn-tester/visual-tests/flows/text.yml | 6 +++ .../visual-tests/flows/touchable.yml | 3 ++ .../visual-tests/flows/transform.yml | 4 ++ .../rn-tester/visual-tests/flows/view.yml | 4 ++ .../visual-tests/helpers/open-example.yml | 47 ++++++++++--------- 14 files changed, 65 insertions(+), 26 deletions(-) diff --git a/packages/rn-tester/visual-tests/README.md b/packages/rn-tester/visual-tests/README.md index 918066d35def..e2d0db53119d 100644 --- a/packages/rn-tester/visual-tests/README.md +++ b/packages/rn-tester/visual-tests/README.md @@ -26,17 +26,14 @@ The baseline for a PR is the one for the commit it's based on, or the nearest ea file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TextExample/textWidthMode - - extendedWaitUntil: - visible: - id: 'text-width-mode-example' - timeout: 15000 + EXAMPLE_ID: text-width-mode-example - takeScreenshot: path: ${VISUAL_OUTPUT_DIR}/text/width-mode/default cropOn: id: 'text-width-mode-example' ``` - `open-example.yml` deep-links to `rntester://example//`. Wait for something that's only visible once the example has rendered, and crop to the example's `testID` so that the status bar and surrounding UI aren't part of the screenshot. + `open-example.yml` deep-links to `rntester://example//` and waits for the element with the `testID` in `EXAMPLE_ID`, relaunching and linking again if it doesn't appear. Use a `testID` that only that example has, not the generic `example-container`, and crop to the example's `testID` so that the status bar and surrounding UI aren't part of the screenshot. 3. Open a PR. The new test has no baseline yet, so the report lists it as new, and like any other difference it needs a maintainer's approval (see below). Once the PR lands, `main` is captured with it and later PRs are compared against that. diff --git a/packages/rn-tester/visual-tests/flows/border.yml b/packages/rn-tester/visual-tests/flows/border.yml index 78778e325f53..38e17e775d36 100644 --- a/packages/rn-tester/visual-tests/flows/border.yml +++ b/packages/rn-tester/visual-tests/flows/border.yml @@ -4,6 +4,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/BorderExample/corner-radii + EXAMPLE_ID: border-test-corner-radii - extendedWaitUntil: visible: id: 'border-test-corner-radii' @@ -18,6 +19,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/BorderExample/child-clipping-radius + EXAMPLE_ID: border-test-child-clipping-radius - extendedWaitUntil: visible: id: 'border-test-child-clipping-radius' @@ -32,6 +34,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/BorderExample/equal-width-borders + EXAMPLE_ID: border-test-equal-width-borders - extendedWaitUntil: visible: id: 'border-test-equal-width-borders' diff --git a/packages/rn-tester/visual-tests/flows/button.yml b/packages/rn-tester/visual-tests/flows/button.yml index a6e03cc2c97b..168a68227cc7 100644 --- a/packages/rn-tester/visual-tests/flows/button.yml +++ b/packages/rn-tester/visual-tests/flows/button.yml @@ -4,6 +4,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/ButtonExample/default-styling + EXAMPLE_ID: button_default_styling - extendedWaitUntil: visible: id: 'example-container' @@ -18,6 +19,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/ButtonExample/disabled + EXAMPLE_ID: disabled_button - extendedWaitUntil: visible: id: 'example-container' @@ -32,6 +34,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/ButtonExample/color-red + EXAMPLE_ID: cancel_button - extendedWaitUntil: visible: id: 'example-container' @@ -46,6 +49,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/ButtonExample/two-buttons-flexbox + EXAMPLE_ID: two_cancel_button - extendedWaitUntil: visible: id: 'example-container' diff --git a/packages/rn-tester/visual-tests/flows/image.yml b/packages/rn-tester/visual-tests/flows/image.yml index 377fe71cb09d..754837178182 100644 --- a/packages/rn-tester/visual-tests/flows/image.yml +++ b/packages/rn-tester/visual-tests/flows/image.yml @@ -4,6 +4,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/ImageExample/static-image + EXAMPLE_ID: image-static - extendedWaitUntil: visible: id: 'image-static' @@ -22,6 +23,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/ImageExample/base64-image + EXAMPLE_ID: image-base64 - extendedWaitUntil: visible: id: 'image-base64' diff --git a/packages/rn-tester/visual-tests/flows/scroll-view.yml b/packages/rn-tester/visual-tests/flows/scroll-view.yml index fef36d4611e0..78df1c589387 100644 --- a/packages/rn-tester/visual-tests/flows/scroll-view.yml +++ b/packages/rn-tester/visual-tests/flows/scroll-view.yml @@ -4,6 +4,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/ScrollViewExample/scrollTo + EXAMPLE_ID: scroll_vertical - extendedWaitUntil: visible: id: 'scroll_vertical' @@ -28,6 +29,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/ScrollViewExample/horizontalScrollTo + EXAMPLE_ID: scroll_horizontal - extendedWaitUntil: visible: id: 'scroll_horizontal' @@ -62,6 +64,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/ScrollViewExample/invertStickyHeaders + EXAMPLE_ID: scroll_sticky_header - extendedWaitUntil: visible: id: 'scroll_sticky_header' diff --git a/packages/rn-tester/visual-tests/flows/switch.yml b/packages/rn-tester/visual-tests/flows/switch.yml index 3aa256fde6ed..2b384773829d 100644 --- a/packages/rn-tester/visual-tests/flows/switch.yml +++ b/packages/rn-tester/visual-tests/flows/switch.yml @@ -4,6 +4,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/SwitchExample/basic + EXAMPLE_ID: on-off-initial-off - extendedWaitUntil: visible: id: 'on-off-initial-off' @@ -38,6 +39,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/SwitchExample/disabled + EXAMPLE_ID: disabled-initial-off - extendedWaitUntil: visible: id: 'example-container' @@ -62,6 +64,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/SwitchExample/custom-colors + EXAMPLE_ID: initial-false-switch - extendedWaitUntil: visible: id: 'initial-false-switch' diff --git a/packages/rn-tester/visual-tests/flows/text-input.yml b/packages/rn-tester/visual-tests/flows/text-input.yml index 95955b0aa6e4..e5bdab2a6255 100644 --- a/packages/rn-tester/visual-tests/flows/text-input.yml +++ b/packages/rn-tester/visual-tests/flows/text-input.yml @@ -4,6 +4,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TextInputExample/clipping + EXAMPLE_ID: textinput-clipping - extendedWaitUntil: visible: id: 'textinput-clipping' @@ -18,6 +19,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TextInputExample/placeholderEllipsizing + EXAMPLE_ID: textinput-placeholder-singleline - extendedWaitUntil: visible: id: 'textinput-placeholder-singleline' @@ -42,6 +44,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TextInputExample/textStyles + EXAMPLE_ID: text-styles - extendedWaitUntil: visible: id: 'text-styles' diff --git a/packages/rn-tester/visual-tests/flows/text-last-line-clipping.yml b/packages/rn-tester/visual-tests/flows/text-last-line-clipping.yml index 8cbdf153ca6b..eca0f84c0a98 100644 --- a/packages/rn-tester/visual-tests/flows/text-last-line-clipping.yml +++ b/packages/rn-tester/visual-tests/flows/text-last-line-clipping.yml @@ -4,6 +4,7 @@ appId: ${APP_ID} # iOS: com.meta.RNTester.localDevelopment | Android: com.facebo file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TextExample/wrappedLastLineClipping + EXAMPLE_ID: last-line-clipping-example - extendedWaitUntil: visible: id: 'last-line-clipping-example' diff --git a/packages/rn-tester/visual-tests/flows/text-width-mode.yml b/packages/rn-tester/visual-tests/flows/text-width-mode.yml index 7a23ad2534d8..859073ff3f75 100644 --- a/packages/rn-tester/visual-tests/flows/text-width-mode.yml +++ b/packages/rn-tester/visual-tests/flows/text-width-mode.yml @@ -4,6 +4,7 @@ appId: ${APP_ID} # iOS: com.meta.RNTester.localDevelopment | Android: com.facebo file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TextExample/textWidthMode + EXAMPLE_ID: text-width-mode-example - extendedWaitUntil: visible: id: 'text-width-mode-example' diff --git a/packages/rn-tester/visual-tests/flows/text.yml b/packages/rn-tester/visual-tests/flows/text.yml index 061dce3519f1..2b0ea1037dbd 100644 --- a/packages/rn-tester/visual-tests/flows/text.yml +++ b/packages/rn-tester/visual-tests/flows/text.yml @@ -4,6 +4,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TextExample/wrap + EXAMPLE_ID: text-wrap - extendedWaitUntil: visible: id: 'text-wrap' @@ -18,6 +19,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TextExample/nested + EXAMPLE_ID: text-test-nested - extendedWaitUntil: visible: id: 'text-test-nested' @@ -32,6 +34,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TextExample/ellipsizeMode + EXAMPLE_ID: text-ellipsize-mode - extendedWaitUntil: visible: id: 'text-ellipsize-mode' @@ -46,6 +49,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TextExample/numberOfLines + EXAMPLE_ID: number-of-lines - extendedWaitUntil: visible: id: 'number-of-lines' @@ -60,6 +64,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TextExample/textDecoration + EXAMPLE_ID: text-text-decoration - extendedWaitUntil: visible: id: 'text-text-decoration' @@ -74,6 +79,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TextExample/textAlign + EXAMPLE_ID: text-align-example - extendedWaitUntil: visible: id: 'text-align-example' diff --git a/packages/rn-tester/visual-tests/flows/touchable.yml b/packages/rn-tester/visual-tests/flows/touchable.yml index b2b16f5c0924..2855b04f6297 100644 --- a/packages/rn-tester/visual-tests/flows/touchable.yml +++ b/packages/rn-tester/visual-tests/flows/touchable.yml @@ -4,6 +4,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TouchableExample/highlight + EXAMPLE_ID: touchable_highlight_text_button - extendedWaitUntil: visible: id: 'touchable_highlight_text_button' @@ -29,6 +30,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TouchableExample/without-feedback + EXAMPLE_ID: touchable_without_feedback_button - extendedWaitUntil: visible: id: 'touchable_without_feedback_button' @@ -54,6 +56,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TouchableExample/feedback-events + EXAMPLE_ID: touchable_feedback_events_button - extendedWaitUntil: visible: id: 'touchable_feedback_events_button' diff --git a/packages/rn-tester/visual-tests/flows/transform.yml b/packages/rn-tester/visual-tests/flows/transform.yml index 3f76be6d858d..226d854badd9 100644 --- a/packages/rn-tester/visual-tests/flows/transform.yml +++ b/packages/rn-tester/visual-tests/flows/transform.yml @@ -4,6 +4,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TransformExample/rotate + EXAMPLE_ID: transform-rotate - extendedWaitUntil: visible: id: 'transform-rotate' @@ -18,6 +19,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TransformExample/rotate-scale + EXAMPLE_ID: transform-rotate-scale - extendedWaitUntil: visible: id: 'transform-rotate-scale' @@ -32,6 +34,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TransformExample/translate-percentage + EXAMPLE_ID: transform-translate-percentage - extendedWaitUntil: visible: id: 'transform-translate-percentage' @@ -46,6 +49,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/TransformExample/string-transform + EXAMPLE_ID: transform-string - extendedWaitUntil: visible: id: 'transform-string' diff --git a/packages/rn-tester/visual-tests/flows/view.yml b/packages/rn-tester/visual-tests/flows/view.yml index 160c37a990a5..81a821a6413c 100644 --- a/packages/rn-tester/visual-tests/flows/view.yml +++ b/packages/rn-tester/visual-tests/flows/view.yml @@ -4,6 +4,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/ViewExample/opacity + EXAMPLE_ID: view-test-opacity - extendedWaitUntil: visible: id: 'view-test-opacity' @@ -18,6 +19,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/ViewExample/overflow + EXAMPLE_ID: view-test-overflow - extendedWaitUntil: visible: id: 'view-test-overflow' @@ -32,6 +34,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/ViewExample/flexgap + EXAMPLE_ID: view-test-flexgap - extendedWaitUntil: visible: id: 'view-test-flexgap' @@ -46,6 +49,7 @@ appId: ${APP_ID} file: ../helpers/open-example.yml env: EXAMPLE_URL: rntester://example/ViewExample/z-index + EXAMPLE_ID: z-index-button - extendedWaitUntil: visible: id: 'z-index-button' diff --git a/packages/rn-tester/visual-tests/helpers/open-example.yml b/packages/rn-tester/visual-tests/helpers/open-example.yml index fdbb6e6fda00..476855ab4cce 100644 --- a/packages/rn-tester/visual-tests/helpers/open-example.yml +++ b/packages/rn-tester/visual-tests/helpers/open-example.yml @@ -1,25 +1,30 @@ appId: ${APP_ID} # iOS: com.meta.RNTester.localDevelopment | Android: com.facebook.react.uiapp --- -- launchApp: - stopApp: true -- waitForAnimationToEnd: - timeout: 30000 -- openLink: ${EXAMPLE_URL} -# On a slow Android emulator, the first link can arrive before the JS Linking -# listener is registered and be dropped, so Android sends it again once settled. -# On iOS, each link raises an "Open in RNTester?" dialog, so it's sent once and -# accepted. A second, unaccepted dialog leaves RNTester on the previous screen. -- runFlow: - when: - platform: Android +# Opens ${EXAMPLE_URL} and waits for the element with ID ${EXAMPLE_ID} in it. +# RNTester ignores links until its JS has rendered. Its tab bar shows +# "Components" on every screen, so that's waited for first. That wait is +# optional, and if the link is still missed, or a relaunch restores the previous +# example instead, this relaunches and links again until the requested +# example's own element is visible. On iOS, the link can raise an "Open in +# RNTester?" dialog, which is accepted. +- retry: + maxRetries: 3 commands: - - waitForAnimationToEnd: - timeout: 15000 - - openLink: ${EXAMPLE_URL} -- runFlow: - when: - platform: iOS - commands: - - tapOn: - text: 'Open' + - launchApp: + stopApp: true + - extendedWaitUntil: + visible: 'Components' + timeout: 30000 optional: true + - openLink: ${EXAMPLE_URL} + - runFlow: + when: + platform: iOS + commands: + - tapOn: + text: 'Open' + optional: true + - extendedWaitUntil: + visible: + id: ${EXAMPLE_ID} + timeout: 15000