Skip to content

E2E: per-test store isolation with automatic teardown#7279

Open
phyllis-sy-wu wants to merge 2 commits intopsyw-0413-E2E-temporary-time-limit-bumpfrom
psyw-0413-E2E-store-isolation
Open

E2E: per-test store isolation with automatic teardown#7279
phyllis-sy-wu wants to merge 2 commits intopsyw-0413-E2E-temporary-time-limit-bumpfrom
psyw-0413-E2E-store-isolation

Conversation

@phyllis-sy-wu
Copy link
Copy Markdown
Contributor

@phyllis-sy-wu phyllis-sy-wu commented Apr 13, 2026

Addressed #7269

WHY are these changes introduced?

E2E tests currently share a single pre-existing dev store configured via E2E_STORE_FQDN. This causes:

  • Shared state: earlier test failures can leave installed apps or modified config that affect later tests
  • No isolation: tests can't run independently — one test's side effects leak into the next
  • Fragile teardown: the old teardownApp silently skips steps, doesn't verify success, and a single failure blocks later cleanup

This PR also lays the foundation for parallel workers (future PR), where shared stores would be impossible since multiple tests run simultaneously.

WHAT is this pull request doing?

Per-test store isolation:

  • Tests that need a dev store (app dev, hot reload, multi-config dev, toml-config dev) create a fresh store via browser automation on admin.shopify.com/store-create/organization/{orgId}
  • Each test gets its own isolated store — no shared state between tests
  • Store is created in test setup and cleaned up in teardown

Robust teardown with escalating retry (setup/teardown.ts):

Three independent phases — failure in one never blocks the next:

  • Phase 1: Uninstall app from store (3 attempts)

    • Navigates to store admin /settings/apps, finds app by name, clicks uninstall
    • Verifies app is gone (checks immediately, reloads once if still visible)
    • Dismisses Dev Console panel via h2:has-text("Dev Console")button[aria-label="hide"]
  • Phase 2: Delete store (3 attempts)

    • Navigates to /settings/apps to check state
    • Detects if store already deleted (access_account redirect)
    • Verifies no apps installed via isStoreAppsEmpty (reloads once if stale)
    • Navigates to /settings/plan, clicks delete, checkbox, confirm
    • Verifies deletion via access_account URL
  • Phase 3: Delete app from dashboard (3 attempts, always runs)

    • Searches dev dashboard with pagination for app by name
    • Clicks delete on settings page, confirms via button.critical[type="submit"]
    • Handles 500/502 errors: refreshIfPageError detects error pages and refreshes
    • Detects 404 after refresh as confirmation of successful deletion

Server error handling (setup/browser.ts):

  • refreshIfPageError(page) detects 500/502 error pages and auto-refreshes
  • Used across dashboard navigation, pagination, and app deletion retry loops

Tagged logging (setup/env.ts):

  • createLogger(tag) produces [e2e][w0][browser], [e2e][w0][cli] format
  • e2eSection() prints section headers: ----- SETUP: store ... -----, ----- TEARDOWN: app ... -----
  • Clear per-attempt failure messages with specific reasons

Exported building blocks (setup/store.ts):

  • uninstallAppFromStore(page, storeSlug, appName) → boolean
  • deleteStore(page, storeSlug) → boolean
  • isStoreAppsEmpty(page) → boolean (pure page checker, caller navigates)
  • dismissDevConsole(page) → void

Files changed:

File Change
setup/store.ts New: store creation, deletion, uninstall, fixtures, helpers
setup/teardown.ts New: teardownAll() orchestrator with 3-phase teardown
setup/app.ts Extract findAppOnDevDashboard() (with pagination), deleteAppFromDevDashboard()
setup/env.ts Add createLogger(), e2eSection(), workerIndex
setup/cli.ts Worker-tagged logging for exec/spawn
setup/browser.ts Add refreshIfPageError()
All test files Switch to teardownAll, store-dependent tests use storeTestFixture

How to test your changes?

# Run all tests with debug output
DEBUG=1 pnpm --filter e2e exec playwright test

# Run headed to watch store creation/teardown
E2E_HEADED=1 DEBUG=1 pnpm --filter e2e exec playwright test

# Skip teardown for debugging (clean up manually after)
E2E_SKIP_CLEANUP=1 pnpm --filter e2e exec playwright test

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've considered possible documentation changes
  • I've considered analytics changes to measure impact
  • The change is user-facing, so I've added a changelog entry with pnpm changeset add

Copy link
Copy Markdown
Contributor Author

phyllis-sy-wu commented Apr 13, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@phyllis-sy-wu phyllis-sy-wu changed the base branch from psyw-0413-E2E-one-time-auth to graphite-base/7279 April 13, 2026 23:38
@phyllis-sy-wu phyllis-sy-wu force-pushed the psyw-0413-E2E-store-isolation branch from a47982f to d6a4e19 Compare April 13, 2026 23:38
@phyllis-sy-wu phyllis-sy-wu changed the base branch from graphite-base/7279 to psyw-0413-E2E-improve-error-context-in-assertions April 13, 2026 23:38
@phyllis-sy-wu phyllis-sy-wu force-pushed the psyw-0413-E2E-store-isolation branch from d6a4e19 to 9659cf3 Compare April 14, 2026 00:01
@phyllis-sy-wu phyllis-sy-wu force-pushed the psyw-0413-E2E-improve-error-context-in-assertions branch from 94f4908 to d872975 Compare April 14, 2026 00:01
@phyllis-sy-wu phyllis-sy-wu changed the base branch from psyw-0413-E2E-improve-error-context-in-assertions to graphite-base/7279 April 14, 2026 02:45
@phyllis-sy-wu phyllis-sy-wu force-pushed the psyw-0413-E2E-store-isolation branch from 9659cf3 to 2bb6ce4 Compare April 14, 2026 02:45
@phyllis-sy-wu phyllis-sy-wu changed the base branch from graphite-base/7279 to psyw-0413-E2E-temporary-time-limit-bump April 14, 2026 02:45
@phyllis-sy-wu phyllis-sy-wu force-pushed the psyw-0413-E2E-store-isolation branch 2 times, most recently from e5289d3 to 5c0d260 Compare April 14, 2026 04:50
@phyllis-sy-wu phyllis-sy-wu force-pushed the psyw-0413-E2E-temporary-time-limit-bump branch from 77e5ea0 to 5765d59 Compare April 14, 2026 04:50
@phyllis-sy-wu phyllis-sy-wu changed the base branch from psyw-0413-E2E-temporary-time-limit-bump to graphite-base/7279 April 14, 2026 17:11
@phyllis-sy-wu phyllis-sy-wu force-pushed the psyw-0413-E2E-store-isolation branch from 5c0d260 to 0e615ef Compare April 15, 2026 02:07
@phyllis-sy-wu phyllis-sy-wu changed the base branch from graphite-base/7279 to psyw-0413-E2E-temporary-time-limit-bump April 15, 2026 02:07
@phyllis-sy-wu phyllis-sy-wu force-pushed the psyw-0413-E2E-store-isolation branch 2 times, most recently from c7ad615 to 75f05bf Compare April 15, 2026 03:26
@phyllis-sy-wu phyllis-sy-wu force-pushed the psyw-0413-E2E-temporary-time-limit-bump branch from f45019e to 16b2f4d Compare April 15, 2026 03:26
@phyllis-sy-wu phyllis-sy-wu force-pushed the psyw-0413-E2E-store-isolation branch from 75f05bf to dbcae8d Compare April 15, 2026 13:56
@phyllis-sy-wu phyllis-sy-wu force-pushed the psyw-0413-E2E-temporary-time-limit-bump branch from 16b2f4d to e673884 Compare April 15, 2026 13:56
@phyllis-sy-wu phyllis-sy-wu mentioned this pull request Apr 15, 2026
4 tasks
@phyllis-sy-wu phyllis-sy-wu force-pushed the psyw-0413-E2E-store-isolation branch from dbcae8d to 898e174 Compare April 15, 2026 14:33
@phyllis-sy-wu phyllis-sy-wu force-pushed the psyw-0413-E2E-temporary-time-limit-bump branch from e673884 to dffff76 Compare April 15, 2026 14:33
@phyllis-sy-wu phyllis-sy-wu force-pushed the psyw-0413-E2E-temporary-time-limit-bump branch from dffff76 to 6ee7257 Compare April 15, 2026 17:05
@phyllis-sy-wu phyllis-sy-wu force-pushed the psyw-0413-E2E-store-isolation branch from 898e174 to fd1b216 Compare April 15, 2026 17:05
@github-actions
Copy link
Copy Markdown
Contributor

Differences in type declarations

We detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:

  • Some seemingly private modules might be re-exported through public modules.
  • If the branch is behind main you might see odd diffs, rebase main into this branch.

New type declarations

We found no new type declarations in this PR

Existing type declarations

packages/cli-kit/dist/private/node/analytics.d.ts
@@ -23,7 +23,6 @@ interface EnvironmentData {
     env_auth_method: string;
     env_is_wsl: boolean;
     env_build_repository: string;
-    env_auto_upgrade_enabled: boolean | null;
 }
 export declare function getEnvironmentData(config: Interfaces.Config): Promise<EnvironmentData>;
 export declare function getSensitiveEnvironmentData(config: Interfaces.Config): Promise<{
packages/cli-kit/dist/public/node/metadata.d.ts
@@ -34,7 +34,7 @@ export type SensitiveSchema<T> = T extends RuntimeMetadataManager<infer _TPublic
  * @returns A container for the metadata.
  */
 export declare function createRuntimeMetadataContainer<TPublic extends AnyJson, TSensitive extends AnyJson = Record<string, never>>(defaultPublicMetadata?: Partial<TPublic>): RuntimeMetadataManager<TPublic, TSensitive>;
-type CmdFieldsFromMonorail = PickByPrefix<MonorailEventPublic, 'cmd_all_'> & PickByPrefix<MonorailEventPublic, 'cmd_app_'> & PickByPrefix<MonorailEventPublic, 'cmd_create_app_'> & PickByPrefix<MonorailEventPublic, 'cmd_theme_'> & PickByPrefix<MonorailEventPublic, 'store_'> & PickByPrefix<MonorailEventPublic, 'env_auto_upgrade_'>;
+type CmdFieldsFromMonorail = PickByPrefix<MonorailEventPublic, 'cmd_all_'> & PickByPrefix<MonorailEventPublic, 'cmd_app_'> & PickByPrefix<MonorailEventPublic, 'cmd_create_app_'> & PickByPrefix<MonorailEventPublic, 'cmd_theme_'> & PickByPrefix<MonorailEventPublic, 'store_'>;
 declare const coreData: RuntimeMetadataManager<CmdFieldsFromMonorail, {
     commandStartOptions: {
         startTime: number;
packages/cli-kit/dist/public/node/monorail.d.ts
@@ -2,7 +2,7 @@ import { JsonMap } from '../../private/common/json.js';
 import { DeepRequired } from '../common/ts/deep-required.js';
 export { DeepRequired };
 type Optional<T> = T | null;
-export declare const MONORAIL_COMMAND_TOPIC = "app_cli3_command/1.21";
+export declare const MONORAIL_COMMAND_TOPIC = "app_cli3_command/1.20";
 export interface Schemas {
     [MONORAIL_COMMAND_TOPIC]: {
         sensitive: {
@@ -46,10 +46,6 @@ export interface Schemas {
             cmd_all_timing_network_ms?: Optional<number>;
             cmd_all_timing_prompts_ms?: Optional<number>;
             cmd_all_timing_active_ms?: Optional<number>;
-            env_auto_upgrade_enabled?: Optional<boolean>;
-            env_auto_upgrade_accepted?: Optional<boolean>;
-            env_auto_upgrade_skipped_reason?: Optional<string>;
-            env_auto_upgrade_success?: Optional<boolean>;
             cmd_extensions_binary_from_source?: Optional<boolean>;
             cmd_scaffold_required_auth?: Optional<boolean>;
             cmd_scaffold_template_custom?: Optional<boolean>;
packages/cli-kit/dist/public/node/upgrade.d.ts
@@ -2,7 +2,7 @@
  * Utility function for generating an install command for the user to run
  * to install an updated version of Shopify CLI.
  *
- * @returns A string with the command to run, or undefined if the package manager cannot be determined.
+ * @returns A string with the command to run.
  */
 export declare function cliInstallCommand(): string | undefined;
 /**

@phyllis-sy-wu phyllis-sy-wu marked this pull request as ready for review April 15, 2026 18:57
@phyllis-sy-wu phyllis-sy-wu requested a review from a team as a code owner April 15, 2026 18:57
@phyllis-sy-wu phyllis-sy-wu changed the title E2E: per-test store isolation with robust teardown E2E: per-test store isolation with automatic teardown Apr 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

E2E: Improve error log E2E: Per-test store isolation for robust parallel execution

1 participant