agentsclimarketplace

Flaky test reduction

Skill almasumdev/awesome-mobile-testing-agent-skills/.github/skills/automation/flaky-test-reduction

Agent skills for unit, widget, UI, and end-to-end testing of mobile apps across platforms.

Install
npx -y skills add almasumdev/awesome-mobile-testing-agent-skills --skill flaky-test-reduction

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Root-cause and eliminate flaky tests in mobile suites. Use when a test passes sometimes and fails sometimes, when CI reruns are masking real bugs, or when a suite's flake rate is above budget.

SKILL.md

4.9 KB, as published. Nobody here has run it

Flaky Test Reduction

Instructions

Flake is not a test problem — it is usually a design problem in either the test or the code under test. Retrying a flaky test without understanding why makes the suite untrustworthy and slow. This skill is a root-cause checklist and a set of fixes.

1. First Principle: Isolate the Cause

A test is flaky for exactly one of a handful of reasons. Work the list in order; do not skip:

  1. Time (clocks, timeouts, delays).
  2. Concurrency (race conditions, main-thread assumptions).
  3. Shared state (singletons, disk, DB, DI graph reused).
  4. Ordering (test depends on another test's side effects).
  5. External dependency (network, device service, third-party SDK).
  6. Resource pressure (OOM, CPU-starved emulator).
  7. Framework bug (rare; only conclude this last).

2. Kill Time-Based Flake

  • Replace System.currentTimeMillis(), Date(), DateTime.now(), Date.now() with an injected clock.
  • Replace Thread.sleep, Task.sleep, Future.delayed, setTimeout in tests with condition-based waits.
  • Use virtual time for retry/backoff logic:
@Test fun retries_with_backoff() = runTest {
    val dispatcher = StandardTestDispatcher(testScheduler)
    val sut = Sync(dispatcher = dispatcher, clock = FixedClock(T0))
    sut.start()
    testScheduler.advanceTimeBy(5_000) // virtual
    assertEquals(3, sut.attempts)
}

3. Kill Concurrency Flake

  • Use test dispatchers / schedulers (TestDispatcher, TestScheduler, fakeAsync, jest.useFakeTimers).
  • Never assert on state right after launch { } / Task { } / then() without joining or awaiting.
  • In UI tests, use the framework's idling primitive (IdlingResource, waitForExistence, pumpAndSettle, waitFor(...) in Detox).
  • Beware "it works because my laptop is fast" — run the suite under CPU throttling occasionally to surface races.

4. Kill Shared-State Flake

  • Build and tear down per test: DB (in-memory), HTTP server, DI container.
  • Purge global caches in @AfterEach / tearDown.
  • On Android, use @After to reset Dispatchers.setMain / Dispatchers.resetMain.
  • On iOS, reset UserDefaults test suite via removePersistentDomain(forName:).
  • Avoid object/singleton collaborators in production code — inject them so tests get fresh instances.

5. Kill Ordering Flake

Run tests in random order in CI. Most runners support it (-Dspock.configuration.runner.reverseOrder, JUnit5 random, XCTest -randomize-tests, Jest --testSequencer). A test that fails only in some order is leaking state; fix the leak, not the order.

6. Kill External-Dependency Flake

Any dependency on a live backend or third-party SDK will flake. Stub them:

  • Run E2E against a dedicated seeded environment, not shared staging.
  • Replace analytics, push, and crash SDKs with no-op fakes in tests.
  • Pin time-sensitive flows so they do not depend on real wall-clock (holidays, weekends, token expiry).

7. Kill Resource-Pressure Flake

  • Reduce parallelism on under-powered CI runners.
  • Cap emulator animation and transition duration (adb shell settings put global window_animation_scale 0).
  • Pre-boot simulators / emulators before the test phase starts so boot cost is not inside a test timeout.
  • Raise device-farm test timeouts proportionally to device class.

8. Retries — Use Cautiously

Retries hide flake, they do not fix it. Use them only as a bridge:

  • Retry once at the suite level; report the retry count as a metric.
  • Quarantine any test that needs retry to pass more than twice in a week.
  • Never retry inside the test body itself — it masks the root cause.

9. Quarantine and Budget

  • Move flaky tests to a @Flaky / @Tag("flaky") group that still runs but does not fail the build.
  • Set a time box: 30 days to fix or delete.
  • Track flake rate per test; surface the top 10 in a weekly report.

10. Tooling

  • Kotlin: kotlinx-coroutines-test, MockWebServer, runTest.
  • Swift: XCTWaiter, XCTNSPredicateExpectation, Task.yield() when awaiting a state flip.
  • Flutter: fakeAsync, tester.pumpAndSettle(Duration(seconds: 5)) with explicit timeout.
  • RN: jest.useFakeTimers({ advanceTimers: true }), @testing-library/react-native's waitFor.

11. Checklist

  • No real clock, RNG, or wall-clock sleep in tests.
  • Every async assertion is gated by a condition wait, not a fixed delay.
  • Test suite runs in random order in CI.
  • DB, HTTP server, and DI graph are rebuilt per test.
  • External SDKs are replaced with fakes.
  • Retries are a bridge, not a fix; retry counts are tracked.
  • Quarantine has a 30-day fix-or-delete rule.
  • Top-10 flakiest tests are published weekly.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.