.agents/skills/cypress-to-scout-migration/references/flakiness-risk-patterns.md
Scan Cypress source code for these patterns before migration. Each indicates a risk area that needs specific handling in the Scout rewrite. Check the test file and its imported tasks/screens/objects.
cy.wait(number) (e.g., cy.wait(500), cy.wait(2000))page.waitForTimeout() is forbidden in Scout.expect.poll(), or locator assertions with built-in retry.afterEach/after cleanup; esArchiverLoad without unload; API resources created but never deleted; global mutable state.afterAll/afterEach, defensive cleanup in beforeAll, unique identifiers per worker (scoutSpace.id).{ force: true } on .click(), .type(), .check(), .select(){ force: true } exists because an app bug causes continuous DOM re-rendering (e.g., a useEffect loop triggering table re-fetches), use dispatchEvent('click') to bypass actionability checks without triggering the playwright/no-force-option lint rule. Document the app bug location and consider filing a fix. See migration-best-practices.md → "dispatchEvent for app-level DOM instability".esArchiver for system indicescy.task('esArchiverLoad', ...) targeting system index names (.kibana, .alerts, .fleet, etc.)kbnClient or apiServices to create saved objects and configuration.cy.intercept() + cy.wait('@alias') as sync pointscy.intercept('GET|POST', '/api/...').as('alias') followed by cy.wait('@alias')page.waitForResponse() are fragile.expect(locator).toBeVisible(), expect.poll(), or data-loading indicators.recurse() or retry loopsrecurse(), cy.waitUntil(), manual retry loops, .should() chains wrapping re-tried actionsexpect.poll() or expect(locator).toPass(). Fix the underlying instability if it's an app bug..eq(0), .first(), .last(), :nth-child() without data-test-subjdata-test-subj attributes. If elements are dynamic, filter by text content or unique attributes.beforeEach with UI navigation for setupbeforeEach(() => { cy.visit(URL); ... }) with repeated page navigation or UI-driven data creationbeforeAll (worker fixture). Navigate once, use test.step() for multi-step flows..within() on re-rendering containers.within(() => { ... }) targeting tables, lists, or containers with loading states.within() captures a DOM snapshot that goes stale on re-render. Playwright locator chaining avoids this, but the re-rendering itself signals timing-sensitive UI.page.testSubj.locator('container').locator('child'). Locators auto-retry.cy.request() in test bodycy.request({ method: 'POST', url: '/api/...', ... }) inside it() blocks (not just before/beforeEach)apiServices. Mixing UI and API in the test body makes tests harder to maintain and debug.apiServices or kbnClient calls in setup/teardown.localStorage / sessionStorage manipulationcy.window().then(win => win.localStorage...), storage key referencesspaceTest uses isolated Kibana spaces. Storage keys may differ. Async persistence can race with page reloads.cy.task() for server-side operationscy.task('esArchiverLoad'), cy.task('createSignalsIndex'), custom task pluginskbnClient.request(), esClient, or apiServices.@skipInServerless, @skipInEss, if (isServerless), Cypress.env('IS_SERVERLESS').should() chains.should('be.visible').and('contain', 'text').and('have.attr', 'href', '/path')expect().expect() calls: await expect(locator).toBeVisible(), await expect(locator).toContainText('text').cy.clock() / cy.tick() for time manipulationcy.clock(), cy.tick(), fake timerspage.clock) with different semantics. Direct port is error-prone.page.clock.install() / page.clock.fastForward(), or redesign to avoid fake timers.