UI suite audit and CI¶
Interval 2B extends the History correction journey to assert Home's authoritative earnings, recent shift detail navigation and refresh after correction. The new AX5 journey checks the exact synthetic weekly earnings ($206.25), paired hourly rate ($25.78), two-of-three coverage, scrolling and Money. All earlier lifecycle and financial assertions remain. Screenshot capture uses these journeys rather than adding screenshot-only tests.
Interval 3 retains the 37 existing journeys and adds one Money AX5 journey, for 38 total. Existing journeys now also verify Home cold launch, Work recovery and Home start, workspace and Settings access, foreground selection retention, capture growth across tab navigation, Undo from Home, and AX5 controls above the native tab bar. Historical fixture helpers explicitly enter Work; financial helpers enter Money. The older test names below are retained so CI identifiers remain stable.
Interval 4A retains all 38 journeys and adds default-size and AX5 Insights journeys, for 40 total.
DashPilot's UI suite is 40 essential journeys, and every pull request runs all of them after the build and the whole domain suite. This page records why the suite has that shape: what the red runs before it had in common, how each of the 82 journeys it replaced was classified, which product risk each remaining journey covers and which domain or integration suite covers the rest, and the CI that runs it. The rules for writing a journey are on Testing.
What the red runs had in common¶
Every full run of the previous 82-journey suite failed one journey, and never the same one:
| Run | Journey | What the result bundle showed | Cause |
|---|---|---|---|
| PR #72 (CI 37406553879) | testCorrectingGroupingOnARunningShift |
The split-out delivery's offer was assumed to be Offer 2; offers renumber by acceptance time, so a tie decided it | Incorrect test assumption, fixed by reading the number |
main after #73 (37418449153) |
two History journeys | A 5 s wait spent on one 4.2 s reading and its retry; an alert's Cancel tapped and the screen behind it read before the alert had closed | One slow accessibility reading against a short budget |
main after #74 (37478065976) |
testDeletingACompletedShiftIsConfirmed |
One reading of the History row took 25 s of an 8 s still-frame wait | One slow reading against a short budget |
| PR #75 (CI 37525485173) | testActiveDeliveriesBlockEndingUntilEachIsResolved |
Cancel Delivery 2 tapped at the centre of its frame (201, 489) on a dialog up for twenty seconds; the recording shows the dialog still up to the end. The query before the tap took 16.6 s |
A synthesized tap the app never received, under load |
v0.1.1 tag (37614136154) |
testDeletingAndAddingPauses |
The time wheels' popover closed at the first tap (recording), then the wait's only reading of it took 14.3 s of its 15 s budget, and the wait failed | One slow reading against a short budget |
The same commit, df08e48, ran the full suite green on main (37525515201, 6,268 s) and red on the
tag (37614136154, 5,895 s). Nothing in the product differed between them.
The systemic cause is the simulator's own background work, multiplied by the number of steps. In
run 37614136154 the 82 journeys made 8,849 XCTest steps, of which 93 took 5 s or more; the stalls
clustered at run positions 1 to 10 and 31 to 40, and the failing journey was position 33. The
bundle's system log shows mediaanalysisd busy from 12:19 to 12:24 UTC, which is exactly the
failing journey's 12:18:56 to 12:23:13; in the PR run, searchd and mediaanalysisd were busy from
20:34 to 20:37, around that failure. The app answered every request promptly throughout: the time
went between the runner and the simulator. Each previous fix strengthened the one helper that
happened to be on screen during a stall, and the next stall found another. The two levers that do
not depend on where the next stall lands are fewer steps, and waits whose verdict cannot rest on one
slow reading.
What was ruled out, on the same evidence: a product regression (every recording shows the app doing the right thing), fixture contamination (each launch builds its own in-memory store), accumulated simulator state (no degradation with run length; failures at positions 2, 22, 32 and 33), and test ordering (XCTest runs alphabetically, and no journey depends on another). Sharding across fresh simulators was rejected: each fresh simulator starts its own first-boot indexing, which is when the first journeys stall.
What changed in the helpers¶
- Every condition wait comes through
waitUntil, whose verdict rests on at least two readings, the second begun after the first returned. A slow reading no longer fails a wait; a condition that is still false when looked at again still does. It only reads the screen and never taps again.waitForExistence(timeout: 5)becameappears(), under the same rule and the sameconditionTimeoutevery other condition wait already had. - Every confirmation tap goes through
tapClosingDialog, which waits for the dialog to close and fails there, naming the button, when iOS did not act on the tap. It does not tap again: a second tap would hide the thing the run has to report. - A failing assertion attaches the screen at that moment to the issue itself, so a red run is read at the failing step rather than by scrubbing a recording.
None of these is a sleep, a retry of an action, or a looser assertion.
How each journey was classified¶
| Class | Meaning | What happened to it |
|---|---|---|
| A. Essential UI automation | Needs a running app: a flow across screens and sheets, a confirmation guarding a write, navigation, persistence across a relaunch, onboarding, the Live Activity, the largest text size on a critical surface | Kept, or merged where two journeys drove the same setup |
| B. Better tested below the UI | A figure, rule, wording or state transition a domain or integration test pins | Removed, with the suite that pins it named below; added to the domain suite where nothing did |
| C. Redundant or low-value | Repeats another journey's navigation or interaction, or measures a layout detail of one screen | Removed, with the journey that still exercises the interaction named |
A journey's duration is its median over the last four full runs on the runner (37418449153, 37478065976, 37525515201, 37614136154).
Journey by journey¶
| Journey | Class | CI s | Outcome | Unique risk, or where it is covered |
|---|---|---|---|---|
testAPickupPlaceIsNamedReusedChangedAndRemoved |
A | 76 | Kept | Pickup place entry, reuse, change and removal |
testARecordedRouteGrowsFreezesWhilePausedAndLeavesTheBreakOut |
A | 111 | Kept | The real capture pipeline wired to the panel, through a pause |
testARunningShiftOffersOnlyWhatItsStateAllows |
A | 28 | Kept | No correction, export or deletion offered while driving |
testAShiftExportsAsJSONOrCSV |
A | 43 | Kept | The user-initiated export flow; file contents are ShiftExportJSONTests and ShiftExportCSVTests |
testActiveDeliveriesBlockEndingUntilEachIsResolved |
A | 145 | Kept | Ending refused while work runs; cancelling one delivery |
testAddsAnAdditionalTipToAFinishedDelivery |
A | 133 | Merged | Into testAddsAndEditsDeliveryEarningsAndATipFromDetail |
testAddsAndEditsDeliveryEarningsFromDetail |
A | 99 | Merged | Into testAddsAndEditsDeliveryEarningsAndATipFromDetail, which drives the delivery once |
testAddsAndEditsEarningsFromDetail |
A | 90 | Kept | Shift money recorded only after driving |
testCorrectingAHistoricalCompletionToACancellation |
A | 54 | Kept | A historical correction behind a confirmation |
testCorrectingGroupingOnARunningShift |
A | 50 | Kept | Grouping corrections and their confirmations |
testCreatesEditsAndSelectsVehicles |
A | 70 | Kept | Settings navigation and vehicle create, edit and select |
testDeletingACompletedShiftIsConfirmed |
A | 96 | Kept | The destructive confirmation and backing out |
testDeletingAndAddingPauses |
A | 143 | Kept | Deleting a pause behind a confirmation, and adding one |
testEditStackMarksSeparateDeliveriesSamePickupWithoutRecreatingThem |
A | 45 | Kept | Editing a stack: the October 3 correction |
testExpensesAreRecordedRefusedCorrectedAndSummarised |
A | 66 | Kept | Expense create, refuse, edit and delete, and the cost reaching a day with no shift |
testFirstLaunchShowsTheWelcomeOnceAndFinishingItPersists |
A | 25 | Kept | First-launch onboarding and its persistence across a relaunch; when it is shown is OnboardingPolicyTests |
testHistoryShowsThisWeekWithItsOwnFiguresAndFollowsAnEdit |
A | 100 | Kept | History's week, its figures following an edit, and Export All History |
testHomeNamesTheNextShiftsVehicleAndTheShiftKeepsItsOwn |
A | 98 | Kept | Settings reach the next shift and never the running one, read off the screen; snapshot rules are ShiftVehicleContextTests and NextShiftVehicleContextTests |
testLaunchesIntoShiftScreen |
A | 9 | Kept | The on-disk store opens and the app does not land on the persistence failure screen; only a real launch shows it |
testLiveActivityLeadsWithParkOnlyUnderTheWorkflow |
A | 78 | Kept | The Live Activity's controls through the activity's own content path |
testMonthsHoldTheirDaysStepBackAndSurviveLeavingTheApp |
A | 28 | Kept | Switching and stepping periods, and the selection surviving leaving the app |
testOlderWeeksAreGroupedSummarisedAndOpen |
A | 31 | Kept | Navigation into Older Weeks and to an older shift |
testOpensTheDetailOfTheTappedShift |
A | 29 | Kept | Tapping a row opens that shift |
testParkAndPauseAreDistinctStatesOfTheRunningShift |
A | 87 | Kept | Park against Pause on the running shift |
testParkAndResumeRecordThePickupAndUndoTakesEachBack |
A | 86 | Kept | The Park and Resume pickup workflow and its Undo |
testRecordsADeliveryThroughItsLifecycle |
A | 54 | Kept | The delivery lifecycle, one tap per event |
testRecoveredStackedDeliveriesStayDistinctAndSurviveLeavingTheApp |
A | 27 | Kept | Relaunch recovery of stacked work and its cards |
testRemindersStateTheirEvidenceAndAnswerOnlyTheirOwnDelivery |
A | 25 | Kept | A reminder answered from its own card advances only that delivery; staleness is DeliveryProgressAssistanceTests |
testReopeningADeliveredDeliveryFromTheShiftsRecord |
A | 18 | Kept | Reopening behind a confirmation |
testStartsASecondDeliveryWhileTheFirstIsRunning |
A | 21 | Kept | Stacked deliveries as separate cards |
testStartsAndEndsAShift |
A | 16 | Kept | The shift lifecycle from Home to History |
testTheDaySummaryStatesEachFigureWithItsCoverage |
A | 29 | Kept, and now also exports the day | The period summary reached and read with its coverage wording; the period export check replaces testEachPeriodExportsItsOwnRecords |
testTheOfferSheetRecordsOneOfferOrNothing |
A | 46 | Kept | The several-delivery sheet records one offer or nothing |
testTheRunningShiftAtTheLargestTextSize |
A | 54 | Kept | The driving surface at AX5 |
testTheShiftEndIsCorrectedOnceTheDeliveryBlockingItIs |
A | 198 | Kept | The real recovery: delivery times, then the end, with the route trimmed |
testTheWelcomeReopensFromSettingsAtTheLargestTextSize |
A | 54 | Kept | Reopening the welcome at AX5; found a real presentation defect (a cover on a lazily loaded row) |
testUndoingADeliveryMarkedDeliveredByMistake |
A | 18 | Kept | The immediate Undo of Delivered |
testACompletedShiftsDeliveriesPlacesAndGrouping |
B | 119 | Removed | DeliveryWordingTests, OfferCorrectionServiceTests (finished shifts allowed); the grouping sheet stays in testCorrectingGroupingOnARunningShift |
testADayIsComparedWithTheDayBeforeIt |
B | 80 | Removed | PeriodComparisonTests (percentage rules, an empty previous period stated, no estimate compared) |
testADeliveryAmountCancelledOrRemovedLeavesNothingInvented |
B | 59 | Removed | DeliveryEarningsTests (removed is missing, not zero) |
testAHistoricalShiftKeepsTheVehicleItRecorded |
B | 75 | Removed | RecordedShiftVehicleTests, FuelAssumptionPersistenceTests |
testALongHistoryIsNewestFirstAndItsOldestShiftIsReachable |
B | 176 | Removed | HistoryFetchScopeTests (order and partition); performance is HistoryFetchScopeMeasurementTests, which a simulator journey cannot measure. 176 s |
testAShiftThatRecordedNothingInventsNoFigures |
B | 22 | Removed | CompletedShiftWordingTests, ShiftMetricsTests (every unavailable reason) |
testAStackedOfferReadsAsOneOfferOfIndependentDeliveries |
B | 46 | Removed | DeliveryGroupingTests, StackedDeliveryStateTests |
testAnEmptyCurrentWeekSaysSoAndKeepsTheOlderWeeksReachable |
B | 23 | Removed | HistoryWeekTests (a current week holding nothing is still the current week) |
testAnOfferIsIndependentUnlessMarkedSamePickupAndDropOff |
B | 49 | Removed | SharedStopTests; the offer sheet stays in testTheOfferSheetRecordsOneOfferOrNothing |
testCorrectingAShiftThatDashPilotRecordedAsEndingLate |
B | 118 | Removed | ShiftEndCorrectionTests, ShiftEndCorrectionServiceTests; the end editor and its route confirmation stay in testTheShiftEndIsCorrectedOnceTheDeliveryBlockingItIs |
testCorrectingAndRefusingAPauseInTheEditor |
B | 115 | Removed | ShiftPauseCorrectionTests, ShiftPauseCorrectionServiceTests; the pause editor stays in testDeletingAndAddingPauses |
testCorrectingPickupPlacesRenamesRefusesAndMerges |
B | 101 | Removed | PickupPlaceCorrectionTests, PickupPlaceServiceTests |
testCorrectingTheRunningShiftsVehicle |
B | 79 | Removed | RunningShiftFuelCorrectionTests (one correction, before any distance, Settings untouched) |
testCorrectingWhichDeliveriesShareAPickup |
B | 31 | Removed | SharedStopTests (one alone refused); Edit Stack stays |
testCorrectionReadsAnOfferHoldingNoDeliveries |
B | 16 | Removed | OfferCorrectionInvarianceTests, DeliveryGroupingTests (an empty offer read and stated) |
testDefaultsAreRecordedAtStartAndNeverReachARecordedShift |
B | 420 | Removed | FuelAssumptionPersistenceTests, HourlyTargetTests (snapshot at start, settings never reach a recorded shift), VehicleSettingsTests (use current defaults); the editor's seed order is new FuelAssumptionsSeedTests. The slowest journey (420 s) |
testDeliveringWithoutExpectedPayRaisesNoConfirmation |
B | 30 | Removed | ExpectedDeliveryEarningsTests (no expectation, nothing unconfirmed) |
testEachDeliveryKeepsItsOwnAmountAndRate |
B | 109 | Removed | DeliveryEarningsTests (stacked deliveries' independent amounts and rates), DeliveryEarningsRate suites |
testEachPeriodExportsItsOwnRecords |
B | 212 | Removed | MonthAndRangeExportTests (records per scope); the day export moved into the day summary journey. 212 s |
testEditingAndDeletingAnOlderShiftRefreshesItsWeek |
B | 54 | Removed | HistoryWeekRefreshTests; a week following an edit stays in testHistoryShowsThisWeekWithItsOwnFiguresAndFollowsAnEdit |
testExpectedPayIsAnExpectationUntilTheDriverRecordsEarnings |
B | 133 | Removed | ExpectedDeliveryEarningsTests (hasUnconfirmedExpectedEarnings, counted by nothing). The confirmation sheet itself is no longer driven; see the limitations |
testFuelAssumptionsOnAFinishedShift |
B | 90 | Removed | FuelEstimateTests, FuelAssumptionTests, ShiftProfitabilityTests |
testFuelAssumptionsSeedTheNextShiftAndItsNetNamesMissingEarnings |
B | 69 | Removed | New FuelAssumptionsSeedTests (the seed order, which lived only in the view), FuelAssumptionTests (mostRecentFuelAssumptions) |
testOlderWeekSummariesStateTheirFuelCoverageInOrder |
B | 27 | Removed | HistoryWeekSummaryTests, PeriodFuelMetricsTests |
testPickedUpWhileParkedResumesDrivingAndUndoParksAgain |
B | 63 | Removed | ParkedProgressTests, ParkedProgressPersistenceTests |
testPickupAndParkingSettingsAreOffAndKeptAsChosen |
B | 39 | Removed | ParkResumePickupWorkflowTests, ParkedProgressTests (off by default, inert alone); the switch is driven by testParkAndResumeRecordThePickupAndUndoTakesEachBack |
testPickupWaitHistoryIsPerPlaceAndStatesItsSample |
B | 57 | Removed | PickupWaitMetricsTests and the pickup wait wording suite |
testRecordingParkingAndResumingSayWhatTheyDo |
B | 40 | Removed | LocationTrackingServiceTests, RouteSuspensionTests, ActiveShiftRouteServiceTests; Park and Resume stay in testParkAndPauseAreDistinctStatesOfTheRunningShift |
testSamePickupMovesTogetherAndUndoesTogether |
B | 114 | Removed | SharedPickupWorkflowTests (one write, one Undo) |
testSettingsStatesItsDefaultsAndRecordsTheGasPrice |
B | 73 | Removed | VehicleSettingsTests (price recorded, corrected, removed, zero not missing); the wording is now CurrentGasPriceWording in new FuelAssumptionsSeedTests; Settings navigation stays in testCreatesEditsAndSelectsVehicles |
testShiftEarningsRefuseWhatCannotBeReadAndInventNoPerMileRate |
B | 38 | Removed | MoneyInputTests, ShiftEarningsTests, ShiftMetricsTests |
testTheRecordedShiftsDetailStatesItsTimesRatesAndRoute |
B | 50 | Removed | ShiftMetricsTests, DeliveryActiveTimeTests, CompletedShiftWordingTests |
testTheShiftPanelReadsInOrderAndBorrowsNothing |
B | 78 | Removed | NextShiftVehicleContextTests, ShiftVehicleContextTests, ActiveShiftMetricsTests; the panel is read by every running-shift journey |
testTheTipsSheetKeepsEachTipItsOwnRecord |
B | 121 | Removed | DeliveryTipTests, DeliveryTipServiceTests, DeliveryTipMetricsTests; the tips sheet stays in the merged money journey |
testTheVehicleEditorLabelsItsFieldsAndRefusesWhatItCannotDivideBy |
B | 28 | Removed | VehicleSettingsTests (no economy and zero refused, nothing written) |
testTheWeekSummaryStatesItsEarningsAndPickupWaitWithTheirBasis |
B | 57 | Removed | PeriodMetricsTests, PickupWaitMetricsTests; switching periods stays in testMonthsHoldTheirDaysStepBackAndSurviveLeavingTheApp |
testACompletedShiftAtTheLargestTextSize |
C | 243 | Removed | AX5 layout of the detail (243 s); represented by the running shift and the welcome |
testACustomRangeIsChosenCancelledAndKept |
C | 39 | Removed | MonthAndCustomPeriodTests holds the range; cancelling a sheet is exercised by every editor journey |
testALongVehicleNameAtTheLargestTextSize |
C | 59 | Removed | Text wrapping of one name at AX5; AX5 is represented by the running shift and the welcome |
testCompletedDeliveryOffersEveryCorrectionWithRoomToReadIt |
C | 89 | Removed | Width measurements of one grid; each control in it is tapped by the journey for its own correction |
testDeliveredUndoLeavingMovesNoDeliveryCard |
C | 37 | Removed | A layout measurement of one transition; Undo itself stays in testUndoingADeliveryMarkedDeliveredByMistake |
testDeliveryEntryStaysReachableWhileHomeScrolls |
C | 63 | Removed | Every delivery journey reaches the pinned entry bar from a scrolled Home |
testHistoryAtTheLargestTextSize |
C | 198 | Removed | Five AX5 cards and a long scroll (198 s); AX5 is represented by the running shift and the welcome |
testTheEntryBarsCoverNothingAtTheLargestTextSize |
C | 79 | Removed | AX5 layout; the running shift at AX5 stays |
testThePeriodSummarySurvivesTheLargestTextSize |
C | 66 | Removed | AX5 layout; the footers' length is bounded by PeriodSummaryExplanationTests |
| New domain coverage. Two rules lived only in SwiftUI views and were read only by removed journeys, | ||||
so they moved into the domain and are pinned by the new FuelAssumptionsSeedTests: the order a |
||||
finished shift's fuel editor is seeded in (FuelAssumptionsSeed: the shift's own pair, then the |
||||
| current defaults, then the most recent shift's pair, and only the first is not a suggestion), and how | ||||
Settings states the current gas price (CurrentGasPriceWording: Not set for none, $0.00 for a |
||||
| recorded zero). Both views now call them; neither behaviour changed. |
Traceability¶
Each product risk, the journey that drives it through the interface, and the suites that pin its
rules. ContinuousIntegrationWorkflowTests fails if a journey is missing from this section or the
section names one that no longer exists.
Launch, onboarding and persistence¶
| Risk | Journey | Below the UI |
|---|---|---|
| Home states exact weekly earnings and paired hourly coverage at AX5, with Money reachable | testHomeFinancialCoverageAtLargestTextSize |
PeriodDataLoaderTests, PeriodMetricsTests, HourlyTargetTests |
| Money gross coverage, qualified net, category filtering, three Previous Week steps and back to the current week, Last Week, This Month and Custom Range presets at AX5; one-tap Work access | testMoneyFinancialWorkspaceAtLargestTextSize |
MoneyWorkspaceTests, MoneyPeriodSelectionTests, MondayReportingTests |
| The real store opens rather than the failure screen | testLaunchesIntoShiftScreen |
PersistenceTests, every migration suite |
| A new driver is welcomed once, and finishing it persists across a relaunch | testFirstLaunchShowsTheWelcomeOnceAndFinishingItPersists |
OnboardingPolicyTests |
| The welcome reopens from Settings and is usable at the largest text size | testTheWelcomeReopensFromSettingsAtTheLargestTextSize |
OnboardingPolicyTests |
| Running work survives leaving and relaunching the app | testRecoveredStackedDeliveriesStayDistinctAndSurviveLeavingTheApp, testMonthsHoldTheirDaysStepBackAndSurviveLeavingTheApp |
DeliveryPersistenceTests, ShiftServiceTests (relaunch recovery), RealWorldRecoveryTests |
The shift: start, Park, Pause, end¶
| Risk | Journey | Below the UI |
|---|---|---|
| A shift starts, runs and ends into History | testStartsAndEndsAShift |
ShiftTests, ShiftServiceTests |
| Park and Pause stay distinct: parked still runs and takes offers, paused stops working time and deliveries | testParkAndPauseAreDistinctStatesOfTheRunningShift |
RouteSuspensionTests, ShiftPauseServiceTests, ShiftPauseTests |
| The live route grows, freezes while paused, and records no distance from the break | testARecordedRouteGrowsFreezesWhilePausedAndLeavesTheBreakOut |
ActiveShiftRouteServiceTests, LocationTrackingServiceTests, RouteMileageCalculatorTests |
| Nothing a driver should not do at the wheel is offered while a shift runs | testARunningShiftOffersOnlyWhatItsStateAllows |
ShiftPauseCorrectionServiceTests, ShiftEndCorrectionServiceTests, HistoricalDeliveryCancellationServiceTests |
| The driving surface is whole and reachable at the largest text size | testTheRunningShiftAtTheLargestTextSize |
DashTypographyTests |
| Settings reach the next shift and never the one already running | testHomeNamesTheNextShiftsVehicleAndTheShiftKeepsItsOwn |
ShiftVehicleContextTests, NextShiftVehicleContextTests, RecordedShiftVehicleTests, FuelAssumptionPersistenceTests, HourlyTargetTests |
Deliveries and stacked work¶
| Risk | Journey | Below the UI |
|---|---|---|
| A delivery is recorded through its lifecycle, one named step at a time | testRecordsADeliveryThroughItsLifecycle |
DeliveryTests, DeliveryServiceTests, DeliveryWordingTests |
| A second delivery runs beside the first as its own card | testStartsASecondDeliveryWhileTheFirstIsRunning |
StackedDeliveryStateTests, DeliveryActiveTimeTests |
| The several-delivery sheet records one offer or nothing | testTheOfferSheetRecordsOneOfferOrNothing |
DeliveryOfferServiceTests, SharedStopTests |
| An immediate Undo of Delivered, and a reopening behind a confirmation | testUndoingADeliveryMarkedDeliveredByMistake, testReopeningADeliveredDeliveryFromTheShiftsRecord |
DeliveryRecoveryTests, DeliveryRecoveryServiceTests, StackedUndoTests |
| Ending is refused while work runs; a cancellation is confirmed and spares the other delivery | testActiveDeliveriesBlockEndingUntilEachIsResolved |
DeliveryServiceTests (shift-end policy and cancellation) |
| A reminder advances only its own delivery and claims no observation | testRemindersStateTheirEvidenceAndAnswerOnlyTheirOwnDelivery |
DeliveryProgressAssistanceTests |
| Park and Resume record the pickup, and Undo takes each step back | testParkAndResumeRecordThePickupAndUndoTakesEachBack |
ParkResumePickupWorkflowTests, SharedPickupWorkflowTests, AutomatedPickupStepUndoTests, ParkedProgressTests |
| Grouping is corrected on a running shift behind named confirmations | testCorrectingGroupingOnARunningShift |
OfferCorrectionServiceTests, OfferCorrectionInvarianceTests |
| Separate deliveries are marked as one stack without being recreated | testEditStackMarksSeparateDeliveriesSamePickupWithoutRecreatingThem |
StackEditTests, SharedStopTests |
| The Live Activity's controls follow the driver's setting | testLiveActivityLeadsWithParkOnlyUnderTheWorkflow |
ShiftActivityControlPriorityTests, ShiftActivityCardLayoutTests, ShiftActivityContentTests |
| A pickup place is named, reused, changed and removed without moving the lifecycle | testAPickupPlaceIsNamedReusedChangedAndRemoved |
PickupPlaceServiceTests, PickupPlaceNameTests, PickupPlaceCorrectionTests, PickupWaitMetricsTests |
History, detail, corrections and deletion¶
| Risk | Journey | Below the UI |
|---|---|---|
| History shows this week, follows an edit, and exports everything | testHistoryShowsThisWeekWithItsOwnFiguresAndFollowsAnEdit |
HistoryFetchScopeTests, HistoryWeekRefreshTests, HistoryWeekSummaryTests |
| Older weeks are reachable and open their own shifts | testOlderWeeksAreGroupedSummarisedAndOpen |
HistoryWeekTests, HistoryFetchScopeTests |
| A row opens the shift it names | testOpensTheDetailOfTheTappedShift |
ShiftMetricsTests, CompletedShiftWordingTests |
| Deleting a shift is confirmed, and backing out deletes nothing | testDeletingACompletedShiftIsConfirmed |
CompletedShiftDeletionTests |
| A historical completion is corrected to a cancellation behind a confirmation | testCorrectingAHistoricalCompletionToACancellation |
HistoricalDeliveryCancellationTests, HistoricalDeliveryCancellationServiceTests |
| A recorded pause is deleted behind a confirmation, and a missed one added | testDeletingAndAddingPauses |
ShiftPauseCorrectionTests, ShiftPauseCorrectionServiceTests |
| Delivery times and then the shift's end are corrected, and the route is trimmed only once confirmed | testTheShiftEndIsCorrectedOnceTheDeliveryBlockingItIs |
DeliveryTimeCorrectionTests, DeliveryTimeCorrectionServiceTests, ShiftEndCorrectionTests, ShiftEndCorrectionServiceTests |
Money, settings, summaries and export¶
| Risk | Journey | Below the UI |
|---|---|---|
| Insights opens from Money, exposes exact weekly values without chart gestures, opens the selected report and returns to active Work | testInsightsWeeklyValuesAndSelectedReport |
InsightsSeriesTests, InsightsLoaderTests, PeriodDataLoaderTests |
| Insights values, period controls and expense breakdown remain readable at AX5 | testInsightsRemainReadableAtLargestTextSize |
InsightsSeriesTests, PeriodComparisonTests |
| Shift earnings are offered only after driving, recorded and edited | testAddsAndEditsEarningsFromDetail |
ShiftEarningsTests, MoneyInputTests, ShiftEarningsPersistenceTests |
| A delivery's amount and a tip are offered only after driving and keep their own records | testAddsAndEditsDeliveryEarningsAndATipFromDetail |
DeliveryEarningsTests, DeliveryTipTests, DeliveryTipServiceTests, DeliveryTipMetricsTests |
| Expenses are recorded, refused, corrected, deleted and reach the day they belong to | testExpensesAreRecordedRefusedCorrectedAndSummarised |
ExpenseTests, PeriodExpenseMetricsTests, ExpensePersistenceTests |
| Vehicles are created, edited and selected in Settings | testCreatesEditsAndSelectsVehicles |
VehicleSettingsTests, VehicleSettingsPersistenceTests, FuelAssumptionsSeedTests |
| A period summary states each figure with its coverage, and exports its own records | testTheDaySummaryStatesEachFigureWithItsCoverage |
PeriodMetricsTests, PeriodFuelMetricsTests, PeriodComparisonTests, MonthAndRangeExportTests |
| A shift exports as JSON or CSV | testAShiftExportsAsJSONOrCSV |
ShiftExportJSONTests, ShiftExportCSVTests, ShiftExportPrivacyTests |
What the suite no longer drives¶
These are covered below the UI but no journey opens their screen, so a defect in the view alone (a sheet that fails to present, a button wired to the wrong action) would reach a pull request unnoticed. Each was judged worth that trade against its runtime and its rules' domain coverage; add a journey back if one of them changes:
- the expected-pay confirmation raised when a delivery carrying an expected amount is delivered;
- the fuel assumptions editor on a finished shift;
- the pickup wait history sheet and the rename and merge screens;
- the running shift's vehicle correction sheet;
- the custom range picker;
- the largest text size on History, the completed shift and the period summary.
Counts and runtime¶
| Before | After | |
|---|---|---|
| UI journeys | 82 (26 on every pull request, 56 more after merge) | 36, all on every pull request |
| Kept as they were | 35 (one now also exports the day) | |
| Merged | 2 into 1 | |
| Removed, covered below the UI (B) | 36, with 7 new domain tests where nothing pinned the rule | |
| Removed as redundant or low-value (C) | 9 | |
| XCTest steps in a full run (run 37614136154) | 8,849 | about 3,600 |
| Full UI suite on the runner, sum of journey medians | 6,257 s (104 min) | about 2,290 s (38 min) |
The essential suite's measured duration is in Testing.
CI¶
| Workflow | When | What | Budget |
|---|---|---|---|
ci.yml |
Every pull request, pushes to main, Mondays 07:00 UTC, v* tags, manual dispatch |
Build, the whole domain suite, then every UI journey, serially | 90 min |
There is no second UI workflow. The previous ui-regression.yml existed to run the journeys too
slow for every pull request; every journey that was worth that time is now in the suite every pull
request runs, and the rest are pinned below the UI, so a separate regression run would only repeat
it. The weekly and tag runs keep the reason it ran on a schedule: an image or runtime change is
noticed without a pull request.
ContinuousIntegrationWorkflowTests pins the shape: one job, build then the whole domain suite then
the whole UI target, serial, the five triggers, no skip, retry or continue-on-error, the bundles
uploaded under if: always(), a budget above 60 and at most 120 minutes, the suite at most 40
journeys, and this page's traceability naming exactly the suite.
Adding a journey¶
Add one only for a risk the domain suite cannot see: a flow across screens, a confirmation guarding a
write, navigation, state surviving the app's lifecycle, the Live Activity, or a critical surface at
the largest text size. Pin its rules in the domain suite first, add a row to the traceability table,
and raise the ceiling in ContinuousIntegrationWorkflowTests deliberately if it is reached.