Skip to content

Commit 5add5e5

Browse files
Fix/maestro flow races (#569)
2 parents eda1e26 + 0d6c575 commit 5add5e5

73 files changed

Lines changed: 494 additions & 105 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/NativePipeline.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ jobs:
751751
# truncated — at 20 min several shards (accordion, background-image, bottom-sheet,
752752
# color-picker, safe-area-view) were cancelled mid-flow. If a shard still hits 30 the cause
753753
# is real app instability, not the cap.
754-
timeout-minutes: 35
754+
timeout-minutes: 30
755755
strategy:
756756
max-parallel: 4
757757
matrix:

maestro/helpers/helpers.sh

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,48 @@ cleanup_xctest_processes() {
9292
}
9393

9494
# Function to restart the iOS simulator
95+
#
96+
# This is the recovery path taken when the Maestro/XCTest driver wedges ("iOS driver not
97+
# ready in time"), so it has to ACTUALLY restart the device. It previously did not: the
98+
# shutdown result was discarded with `|| true`, and the following prepare_ios.sh reported
99+
#
100+
# Monitoring boot status for iPhone 17 Pro (...).
101+
# Device already booted, nothing to do.
102+
#
103+
# i.e. the device never went down and the shard only got an app reinstall on top of the
104+
# same wedged runtime. So we now verify the device reaches Shutdown and say so loudly if
105+
# it doesn't, rather than silently continuing with a half-reset simulator.
95106
restart_simulator() {
96107
echo "🔄 Restarting iOS Simulator..."
97-
# Clean up XCTest processes first
108+
# Kill the XCTest runner FIRST: while it holds the device, shutdown can fail.
98109
cleanup_xctest_processes
99-
# Shut down whatever is booted; the device is auto-selected in prepare_ios.sh,
100-
# so we don't depend on a hardcoded device name here.
101-
xcrun simctl shutdown all || true
102-
sleep 10
110+
111+
# Target the device prepare_ios.sh selected when we know it; `all` otherwise (first
112+
# call in a shard, where SIMULATOR_DEVICE_ID isn't exported into this shell yet).
113+
local target="${SIMULATOR_DEVICE_ID:-all}"
114+
echo "Shutting down simulator ($target)..."
115+
if ! xcrun simctl shutdown "$target" 2>&1; then
116+
# Already-shutdown is a benign error, so don't fail here — the poll below is what
117+
# decides whether the device is actually down.
118+
echo "shutdown reported an error; verifying device state anyway"
119+
fi
120+
121+
# `simctl shutdown <udid>` is synchronous (measured ~3s), but poll rather than trust
122+
# it: this replaces a blind `sleep 10` that padded every retry whether or not it was
123+
# needed. Bounded so a stuck device surfaces as a warning instead of hanging.
124+
local deadline=$((SECONDS + 30))
125+
while [ "$SECONDS" -lt "$deadline" ]; do
126+
if [ -n "${SIMULATOR_DEVICE_ID:-}" ]; then
127+
xcrun simctl list devices | grep -q "$SIMULATOR_DEVICE_ID.*Shutdown" && break
128+
else
129+
xcrun simctl list devices | grep -q "(Booted)" || break
130+
fi
131+
sleep 1
132+
done
133+
if [ "$SECONDS" -ge "$deadline" ]; then
134+
echo "::warning::Simulator did not reach Shutdown within 30s; the driver may still be wedged after this restart"
135+
fi
136+
103137
bash ./maestro/helpers/prepare_ios.sh
104138
}
105139

packages/pluggableWidgets/background-gradient-native/e2e/specs/maestro/BackgroundGradient.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ appId: "${APP_ID}"
55
file: "../../../../../../maestro/Precondition.yaml"
66
- tapOn:
77
text: "B"
8+
# Tapping the alphabet index re-renders the widget list; wait for the
9+
# entry before tapping it, otherwise the tap races that render.
10+
- extendedWaitUntil:
11+
visible: "Background gradient"
12+
timeout: 10000
813
- tapOn:
914
text: "Background gradient"
1015
- extendedWaitUntil:

packages/pluggableWidgets/background-image-native/e2e/specs/maestro/BgImage_clickable_container.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ appId: "${APP_ID}"
44
file: "../../../../../../maestro/Precondition.yaml"
55
- tapOn:
66
text: "B"
7+
# Tapping the alphabet index re-renders the widget list; wait for the
8+
# entry before tapping it, otherwise the tap races that render.
9+
- extendedWaitUntil:
10+
visible: "Background image"
11+
timeout: 10000
712
- tapOn:
813
text: "Background image"
914
- tapOn:

packages/pluggableWidgets/background-image-native/e2e/specs/maestro/BgImage_conditional_visibility.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ appId: "${APP_ID}"
44
file: "../../../../../../maestro/Precondition.yaml"
55
- tapOn:
66
text: "B"
7+
# Tapping the alphabet index re-renders the widget list; wait for the
8+
# entry before tapping it, otherwise the tap races that render.
9+
- extendedWaitUntil:
10+
visible: "Background image"
11+
timeout: 10000
712
- tapOn:
813
text: "Background image"
914
- tapOn:

packages/pluggableWidgets/background-image-native/e2e/specs/maestro/BgImage_dynamic_image.yaml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ appId: "${APP_ID}"
44
file: "../../../../../../maestro/Precondition.yaml"
55
- tapOn:
66
text: "B"
7+
# Tapping the alphabet index re-renders the widget list; wait for the
8+
# entry before tapping it, otherwise the tap races that render.
9+
- extendedWaitUntil:
10+
visible: "Background image"
11+
timeout: 10000
712
- tapOn:
813
text: "Background image"
914
- tapOn:
1015
text: "Dynamic image"
11-
# Because the image loading can take some time due to resources on emulator, we need to wait for the image to be visible
12-
- extendedWaitUntil:
13-
visible: randText # Any random text that does not exist in the UI
14-
optional: true # This should be true so that the test won't fail
15-
timeout: 30000 # 15 seconds
16+
# Wait for the screen to stop changing (image decode / sheet animation)
17+
# rather than sleeping a fixed time: this returns as soon as the UI
18+
# settles, and still caps at 30s.
19+
- waitForAnimationToEnd:
20+
timeout: 30000
1621
- takeScreenshot:
1722
path: "maestro/images/actual/${PLATFORM}/bg_image_dynamic_image"
1823
- assertScreenshot:

packages/pluggableWidgets/background-image-native/e2e/specs/maestro/BgImage_dynamic_svg.yaml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ appId: "${APP_ID}"
44
file: "../../../../../../maestro/Precondition.yaml"
55
- tapOn:
66
text: "B"
7+
# Tapping the alphabet index re-renders the widget list; wait for the
8+
# entry before tapping it, otherwise the tap races that render.
9+
- extendedWaitUntil:
10+
visible: "Background image"
11+
timeout: 10000
712
- tapOn:
813
text: "Background image"
914
- tapOn:
1015
text: "Dynamic SVG image"
11-
# Because the image loading can take some time due to resources on emulator, we need to wait for the image to be visible
12-
- extendedWaitUntil:
13-
visible: randText # Any random text that does not exist in the UI
14-
optional: true # This should be true so that the test won't fail
15-
timeout: 15000 # 15 seconds
16+
# Wait for the screen to stop changing (image decode / sheet animation)
17+
# rather than sleeping a fixed time: this returns as soon as the UI
18+
# settles, and still caps at 15s.
19+
- waitForAnimationToEnd:
20+
timeout: 15000
1621
- takeScreenshot:
1722
path: "maestro/images/actual/${PLATFORM}/bg_image_dynamic_svg"
1823
- assertScreenshot:

packages/pluggableWidgets/background-image-native/e2e/specs/maestro/BgImage_layout_grid.yaml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,21 @@ appId: "${APP_ID}"
44
file: "../../../../../../maestro/Precondition.yaml"
55
- tapOn:
66
text: "B"
7+
# Tapping the alphabet index re-renders the widget list; wait for the
8+
# entry before tapping it, otherwise the tap races that render.
9+
- extendedWaitUntil:
10+
visible: "Background image"
11+
timeout: 10000
712
- tapOn:
813
text: "Background image"
914
- tapOn:
1015
text: "Layout grid"
1116
- assertVisible: "Layout grid"
12-
# Because the image loading can take some time due to resources on emulator, we need to wait for the image to be visible
13-
- extendedWaitUntil:
14-
visible: randText # Any random text that does not exist in the UI
15-
optional: true # This should be true so that the test won't fail
16-
timeout: 15000 # 15 seconds
17+
# Wait for the screen to stop changing (image decode / sheet animation)
18+
# rather than sleeping a fixed time: this returns as soon as the UI
19+
# settles, and still caps at 15s.
20+
- waitForAnimationToEnd:
21+
timeout: 15000
1722
- takeScreenshot:
1823
path: "maestro/images/actual/${PLATFORM}/bg_image_layout_grid"
1924
- assertScreenshot:

packages/pluggableWidgets/background-image-native/e2e/specs/maestro/BgImage_nested.yaml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,21 @@ appId: "${APP_ID}"
44
file: "../../../../../../maestro/Precondition.yaml"
55
- tapOn:
66
text: "B"
7+
# Tapping the alphabet index re-renders the widget list; wait for the
8+
# entry before tapping it, otherwise the tap races that render.
9+
- extendedWaitUntil:
10+
visible: "Background image"
11+
timeout: 10000
712
- tapOn:
813
text: "Background image"
914
- tapOn:
1015
text: "Nested"
1116
- assertVisible: "Nested"
12-
# Because the image loading can take some time due to resources on emulator, we need to wait for the image to be visible
13-
- extendedWaitUntil:
14-
visible: randText # Any random text that does not exist in the UI
15-
optional: true # This should be true so that the test won't fail
16-
timeout: 15000 # 15 seconds
17+
# Wait for the screen to stop changing (image decode / sheet animation)
18+
# rather than sleeping a fixed time: this returns as soon as the UI
19+
# settles, and still caps at 15s.
20+
- waitForAnimationToEnd:
21+
timeout: 15000
1722
- takeScreenshot:
1823
path: "maestro/images/actual/${PLATFORM}/bg_image_nested"
1924
- assertScreenshot:

packages/pluggableWidgets/background-image-native/e2e/specs/maestro/BgImage_static_images.yaml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,22 @@ appId: "${APP_ID}"
44
file: "../../../../../../maestro/Precondition.yaml"
55
- tapOn:
66
text: "B"
7+
# Tapping the alphabet index re-renders the widget list; wait for the
8+
# entry before tapping it, otherwise the tap races that render.
9+
- extendedWaitUntil:
10+
visible: "Background image"
11+
timeout: 10000
712
- tapOn:
813
text: "Background image"
914
- tapOn:
1015
text: "Static images"
1116
- assertVisible:
1217
text: "Static images"
13-
# Because the image loading can take some time due to resources on emulator, we need to wait for the image to be visible
14-
- extendedWaitUntil:
15-
visible: randText # Any random text that does not exist in the UI
16-
optional: true # This should be true so that the test won't fail
17-
timeout: 10000 # 10 seconds
18+
# Wait for the screen to stop changing (image decode / sheet animation)
19+
# rather than sleeping a fixed time: this returns as soon as the UI
20+
# settles, and still caps at 10s.
21+
- waitForAnimationToEnd:
22+
timeout: 10000
1823
- takeScreenshot:
1924
path: "maestro/images/actual/${PLATFORM}/bg_image_static_images"
2025
- assertScreenshot:

0 commit comments

Comments
 (0)