From 801de3161158ebb3bd98060cc6fe8de44e9b8dcf Mon Sep 17 00:00:00 2001 From: "Anthony Fu (via agent)" Date: Thu, 20 Aug 2026 08:21:22 +0000 Subject: [PATCH 1/3] ci: run a11y tests in their own CI job, separate from e2e `pnpm test:e2e` used to run every Playwright project, including the axe-core color-contrast scans (`a11y` project) inside the single `e2e` CI job. Split them: - `test:e2e` now targets the five e2e-only projects explicitly (dev, build, webcontainer, instant, build-subbase). - New `test:a11y` script runs just the `a11y` project. - CI gets a new `a11y` job mirroring `e2e`'s Playwright setup, so a11y regressions surface as their own check and run in parallel with e2e instead of extending its runtime. Created with the help of an agent. --- .github/workflows/ci.yml | 55 ++++++++++++++++++++++++++++++++++++++++ AGENTS.md | 2 +- package.json | 3 ++- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8824d3f5..5eea682b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -127,3 +127,58 @@ jobs: name: playwright-results path: test/e2e/.results retention-days: 7 + + a11y: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v7 + + - name: Install pnpm + uses: pnpm/action-setup@v6 + + - name: Set node + uses: actions/setup-node@v7 + with: + node-version: lts/* + + - name: Setup + run: npm i -g @antfu/ni + + - name: Install + run: nci + + # The orchestrator runs `pnpm build` + `pnpm web:build` itself; no + # separate build step needed here. + + - name: Get Playwright version + id: pw-version + run: | + version=$(node -p "require('@playwright/test/package.json').version") + echo "version=$version" >> "$GITHUB_OUTPUT" + + - name: Cache Playwright browsers + uses: actions/cache@v6 + id: pw-cache + with: + path: ~/.cache/ms-playwright + key: playwright-${{ runner.os }}-${{ steps.pw-version.outputs.version }} + + - name: Install Playwright browser + if: steps.pw-cache.outputs.cache-hit != 'true' + run: pnpm exec playwright install --with-deps chromium + + - name: Install Playwright system deps + if: steps.pw-cache.outputs.cache-hit == 'true' + run: pnpm exec playwright install-deps chromium + + - name: A11y + run: nr test:a11y + + - name: Upload Playwright artifacts + if: failure() + uses: actions/upload-artifact@v7 + with: + name: playwright-results-a11y + path: test/e2e/.results + retention-days: 7 diff --git a/AGENTS.md b/AGENTS.md index 10752523..2a12129e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,7 +14,7 @@ RPC functions live in `packages/node-modules-inspector/src/node/rpc/.ts` - `pnpm dev` — dev server - `pnpm build` — full build -- `pnpm test` / `pnpm test:e2e` — vitest / playwright +- `pnpm test` / `pnpm test:e2e` / `pnpm test:a11y` — vitest / playwright e2e / playwright accessibility (axe-core) - `pnpm lint` / `pnpm typecheck` ## Conventions diff --git a/package.json b/package.json index 590e1e70..710113a3 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "prepare": "npx simple-git-hooks && pnpm -C packages/node-modules-inspector run dev:prepare && skills-npm", "lint": "pnpm -C packages/node-modules-inspector run dev:prepare && eslint .", "test": "vitest", - "test:e2e": "playwright test", + "test:e2e": "playwright test --project=dev --project=build --project=webcontainer --project=instant --project=build-subbase", + "test:a11y": "playwright test --project=a11y", "test:e2e:install": "playwright install chromium", "release": "bumpp -r", "typecheck": "vue-tsc --noEmit" From ad0f178939537aebbc391041806184fbe18a9c2b Mon Sep 17 00:00:00 2001 From: "Anthony Fu (via agent)" Date: Thu, 20 Aug 2026 08:24:04 +0000 Subject: [PATCH 2/3] fix(tools): use consistent (unquoted) property quoting in resolve.test.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pre-existing lint failure from #195 — some object-literal keys were quoted (`'h3'`) while sibling keys of the same object weren't (`nuxt`), which `style/quote-props` flags as inconsistent. Only surfaces once a PR's branch is rebased/merged onto the current `main`, which is why CI here needs it fixed too. Created with the help of an agent. --- .../node-modules-tools/src/registry/resolve.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/node-modules-tools/src/registry/resolve.test.ts b/packages/node-modules-tools/src/registry/resolve.test.ts index 7fae818a..3c02f60a 100644 --- a/packages/node-modules-tools/src/registry/resolve.test.ts +++ b/packages/node-modules-tools/src/registry/resolve.test.ts @@ -319,10 +319,10 @@ describe('resolveRegistryDependencies', () => { it('excludes a package and its exclusively-reachable dependencies', async () => { const { fetch, requests } = createMockRegistry({ - nuxt: { versions: { '3.0.0': { dependencies: { '@nuxt/kit': '^3.0.0', 'h3': '^1.0.0' } } } }, - '@nuxt/kit': { versions: { '3.0.0': { dependencies: { 'unctx': '^2.0.0' } } } }, - unctx: { versions: { '2.0.0': {} } }, - h3: { versions: { '1.0.0': {} } }, + 'nuxt': { versions: { '3.0.0': { dependencies: { '@nuxt/kit': '^3.0.0', 'h3': '^1.0.0' } } } }, + '@nuxt/kit': { versions: { '3.0.0': { dependencies: { unctx: '^2.0.0' } } } }, + 'unctx': { versions: { '2.0.0': {} } }, + 'h3': { versions: { '1.0.0': {} } }, }) const result = await resolveRegistryDependencies({ @@ -341,9 +341,9 @@ describe('resolveRegistryDependencies', () => { it('keeps a shared dep still reachable from a non-excluded path', async () => { const { fetch } = createMockRegistry({ - nuxt: { versions: { '3.0.0': { dependencies: { '@nuxt/kit': '^3.0.0', 'vite': '^5.0.0' } } } }, + 'nuxt': { versions: { '3.0.0': { dependencies: { '@nuxt/kit': '^3.0.0', 'vite': '^5.0.0' } } } }, '@nuxt/kit': { versions: { '3.0.0': { dependencies: { vite: '^5.0.0' } } } }, - vite: { versions: { '5.0.0': {} } }, + 'vite': { versions: { '5.0.0': {} } }, }) const result = await resolveRegistryDependencies({ From 0da11021ee3326b7e8e4fc189bc64e6c28cddf07 Mon Sep 17 00:00:00 2001 From: "Anthony Fu (via agent)" Date: Thu, 20 Aug 2026 08:40:21 +0000 Subject: [PATCH 3/3] fix: pre-existing e2e/a11y failures unrelated to this PR's CI split MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both were already broken on `main` (predate this branch and #195) and would fail the new `e2e`/`a11y` jobs regardless of the split itself: - `instant.spec.ts` expected a button named 'Instant' and a plain-text 'npm registry' link role; the landing page's toggle has read 'Registry Query' since #193 introduced the test, and the Overview panel's 'npm registry' was a plain ``. Fixed the span to be a real link (matching its 'WebContainer' sibling) and updated the stale assertion. - `badge-color-gray` (used by `NodeVersionRange` with `!bg-active`) only cleared a 4.13:1 dark-mode contrast ratio — bumped the dark text shade following the same pattern as the other hue overrides above it. Created with the help of an agent. --- .../src/app/components/panel/Overview.vue | 2 +- packages/node-modules-inspector/src/uno.config.ts | 6 ++++++ test/e2e/instant.spec.ts | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/node-modules-inspector/src/app/components/panel/Overview.vue b/packages/node-modules-inspector/src/app/components/panel/Overview.vue index 969d54a2..e77a4111 100644 --- a/packages/node-modules-inspector/src/app/components/panel/Overview.vue +++ b/packages/node-modules-inspector/src/app/components/panel/Overview.vue @@ -71,7 +71,7 @@ const timepassed = computed(() => rawPayload.value?.timestamp ? Date.now() - raw flex="~ gap-2 items-center" >
- npm registry + npm registry { test.describe('hosted instant mode', () => { test('landing defaults to Instant mode with a Sandbox toggle', async ({ page }) => { await page.goto('/') - await expect(page.getByRole('button', { name: 'Instant', exact: true })).toBeVisible({ timeout: 30_000 }) + await expect(page.getByRole('button', { name: 'Registry Query', exact: true })).toBeVisible({ timeout: 30_000 }) await expect(page.getByRole('button', { name: 'Sandbox Install' })).toBeVisible() await expect(page.getByPlaceholder('Enter package names')).toBeVisible()