{"slug": "run-only-the-playwright-tests-your-change-can-affect", "title": "Run Only the Playwright Tests Your Change Can Affect", "summary": "Developer Alexander Op built feature-shop, a Nuxt demo shop, to test a CI approach that runs only the Playwright end-to-end scenarios affected by a code change, using feature folders, @feature tags, and a dependency map in tools/impact.ts. In four pull requests against the same base commit, a checkout view change ran 4 of 14 browser tests, a search view change ran 5 of 14, a cart view change ran 10 of 14, and a shared CSS change ran all 14, with all runs passing in GitHub Actions. The setup requires Node 24 and pnpm 10, and shared styles, test infrastructure, or unknown files trigger the full suite.", "body_md": "With AI writing more of our code, I keep coming back to the testing discussion. Are unit tests still useful? How much confidence do they give us when an agent writes both the implementation and the tests?\n\nI still want unit tests for business rules. But I also want to open the application, add something to a cart, and complete a checkout. An end-to-end test checks whether those pieces work together, through the interface someone uses.\n\nThe problem is the waiting. If I change checkout validation, do I need to run every search scenario before getting feedback?\n\nLast week I built [feature-shop](https://github.com/alexanderop/feature-shop), a small Nuxt shop, to try a different approach: **run the E2E tests for the changed feature and the features that depend on it.**\n\n## Feature folders give us a starting point\n\nIn the shop, search, product details, cart, and checkout each have their own feature folder. The browser tests follow the same structure.\n\n```\napp/features/\n  search/\n  product-detail/\n  cart/\n  checkout/\ntests/e2e/features/\n  search/\n  product-detail/\n  cart/\n  checkout/\n```\n\nThat makes ownership easier to describe. A change in `app/features/checkout/` belongs to checkout. The selector can find the scenarios tagged with `@checkout` and run them.\n\nEach scenario also has a stable ID. This one checks the result a customer cares about:\n\n```\n@checkout\nFeature: Simulated checkout\n  @id:checkout-success\n  Scenario: Successful checkout clears the cart\n    Given my cart contains 1 backpacks\n    When I open checkout\n    And I enter valid customer details\n    And I choose an approved payment\n    And I place my order\n    Then my order is confirmed\n    And my receipt total is \"40.00\"\n    When I open my cart\n    Then my cart is empty\n```\n\nI use Playwright-BDD to connect these sentences to Playwright fixtures and page objects. You can use the same selection idea with plain Playwright tests and tags.\n\n## A cart change can break checkout\n\nFolder names alone aren’t enough. Checkout uses the cart. Product details let you add an item to it. If I change cart behavior, I need to test those consumers too.\n\nIn [`tools/impact.ts`](https://github.com/alexanderop/feature-shop/blob/2bb25da27c6481e52b8e9f19823ae4659b392453/tools/impact.ts), I describe the file ownership and dependencies. The selector follows consumers, including indirect ones, until it has the affected set.\n\nThe purchase journey crosses feature boundaries, so I tag it with all the features it covers. A checkout change still runs that complete journey.\n\nShared styles, dependencies, test infrastructure, and unknown files trigger the full suite. So does an unavailable Git comparison. Documentation-only changes select no browser scenarios, but CI still runs the static checks and unit tests.\n\nThis depends on keeping the ownership map and scenario tags accurate. A feature folder doesn’t prove isolation. Review dependencies when you add imports, shared state, or API interactions.\n\n## What happened in GitHub Actions\n\nI opened four small pull requests against the same base commit. Each changed one application file.\n\n| Change | Browser tests executed | Result | \n|---|---|---|\n| Checkout view | 4 / 14 | Passed | \n| Search view | 5 / 14 | Passed | \n| Cart view | 10 / 14 | Passed | \n| Shared CSS | 14 / 14 | Passed | \n\nThe [verification record](https://github.com/alexanderop/feature-shop/blob/2bb25da27c6481e52b8e9f19823ae4659b392453/docs/github-verification.md) links to each PR and Actions run. It records comparisons between selected scenario IDs and the tests Playwright executed.\n\nThese are test counts, not a speed benchmark. Installing dependencies, building the application, and starting the browser still cost time.\n\n## Try the same setup\n\nUse Node 24 and pnpm 10. These commands check out the published version behind this post, including its tests and workflow:\n\n```\ngit clone https://github.com/alexanderop/feature-shop.git\ncd feature-shop\ngit checkout -b try-affected-tests 2bb25da27c6481e52b8e9f19823ae4659b392453\npnpm install --frozen-lockfile\npnpm exec playwright install chromium\npnpm check\npnpm verify run --all\n```\n\nLeave port `3401` free. The runner builds and starts the shop for you. On Linux, use `pnpm exec playwright install --with-deps chromium` to install browser system dependencies too.\n\nEdit `app/features/checkout/CheckoutView.vue`, then inspect the selection before running it:\n\n```\npnpm verify plan --affected\npnpm verify run --affected\n```\n\nExpect the three checkout scenarios and the purchase journey. The default comparison includes uncommitted changes against `HEAD`. After committing your edits, use `--base main` to include your branch changes.\n\nFor GitHub Actions, fork the repository, enable Actions if GitHub prompts you, and open a PR **against your fork’s main branch**. The existing [complete workflow](https://github.com/alexanderop/feature-shop/blob/2bb25da27c6481e52b8e9f19823ae4659b392453/.github/workflows/verify.yml) contains dependency installation, checks, the production build, and report uploads. Its selection step is:\n\n```\n# Excerpt from .github/workflows/verify.yml\n- name: Run affected scenarios\n  if: github.event_name == 'pull_request'\n  env:\n    VERIFY_SKIP_BUILD: '1'\n    VERIFY_BASE: ${{ github.event.pull_request.base.sha }}\n    VERIFY_HEAD: ${{ github.event.pull_request.head.sha }}\n  run: pnpm --silent verify run --affected --base \"$VERIFY_BASE\" --head \"$VERIFY_HEAD\" --json\n```\n\n`pnpm verify` is this project’s CLI, not a built-in Playwright command. It compares changes from the Git merge base, selects scenario IDs, and passes them to [Playwright’s `--grep` filter](https://playwright.dev/docs/test-cli#reference).\n\nThe workflow fetches Git history with `fetch-depth: 0` and tests the PR head commit. It runs all scenarios on main, on a weekly schedule, and on manual runs.\n\nTo adapt this to your own app, copy the selector and runner with their supporting files in `tools/`, then map your paths, dependencies, and scenarios. Adapt the Playwright configuration and workflow to your application’s start command. Copying the YAML excerpt alone won’t create that setup.\n\n## Keep checking the selection\n\nSet the repository Actions variable `SHADOW_FULL_SUITE=true` while evaluating this approach. Successful selective runs will then continue into a full run, so you can look for failures outside the selected tests. In this published workflow, a failed selective step stops that later step.\n\nA full run on main can catch missed dependencies after merging. It cannot protect the PR before merging. Keep the full pre-merge run if you need that assurance.\n\nThis fits how I think about [a modern quality pipeline](https://alexop.dev/posts/modern-frontend-quality-pipeline/)A Modern Quality Pipeline and Testing Strategy for Frontend ProjectsA short, framework-agnostic concept of what a modern quality pipeline and testing strategy look like for any JavaScript or TypeScript frontend project.: give yourself and your agent useful feedback at a cost you can afford. I’ve covered [what a passing browser test should prove](https://alexop.dev/posts/what-should-a-green-test-prove-vitest-browser-mode/)What Should a Green Test Prove? Vue Testing with Vitest Browser ModeA CSS bug passes in jsdom but blocks a real purchase. Build Vue tests around behavior, accessibility, and visual regression with Vitest Browser Mode. and [where to put code so you can test business rules separately](https://alexop.dev/posts/hexagonal-architecture-vue/)Hexagonal Architecture in Vue: Where to Put Your Code and WhyLearn what belongs in Vue components, composables, the application core, and adapters. Use ports and adapters to make rules easier to test and changes easier to contain. in earlier posts.\n\nI still want those unit tests. I also want browser tests that tell me whether someone can complete a purchase. With clear feature boundaries, I can run the relevant journeys while working and keep broader regression checks in the pipeline.", "url": "https://wpnews.pro/news/run-only-the-playwright-tests-your-change-can-affect", "canonical_source": "https://alexop.dev/posts/run-only-affected-playwright-tests/", "published_at": "2026-10-05 05:44:00+00:00", "updated_at": "2026-10-05 06:12:12.899084+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Alexander Op", "feature-shop", "Nuxt", "Playwright", "Playwright-BDD", "GitHub Actions", "Node 24", "pnpm 10"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/run-only-the-playwright-tests-your-change-can-affect", "markdown": "https://wpnews.pro/news/run-only-the-playwright-tests-your-change-can-affect.md", "text": "https://wpnews.pro/news/run-only-the-playwright-tests-your-change-can-affect.txt", "jsonld": "https://wpnews.pro/news/run-only-the-playwright-tests-your-change-can-affect.jsonld"}}