> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/gsinghjay/astro-shadcn-sanity/llms.txt
> Use this file to discover all available pages before exploring further.

# End-to-end tests

> Playwright E2E tests across 5 browser projects and fast integration tests that validate schema and module conventions without a browser.

End-to-end tests use [Playwright](https://playwright.dev/). There are two modes: full browser E2E across 5 device configurations, and fast integration tests that run schema/content validation without launching a browser.

## Running E2E tests

```bash theme={null}
# Full suite — all 5 browser projects (builds Astro first)
npm run test:e2e

# Chromium only — fastest feedback
npm run test:chromium

# Headed mode — watch the browser
npm run test:headed

# Interactive Playwright UI explorer
npm run test:ui

# Specific test file
npx playwright test tests/e2e/smoke.spec.ts

# Specific browser project
npx playwright test --project=mobile-safari
```

## Integration tests (no browser)

Integration tests use the same Playwright/Vitest runner but skip browser launch entirely. They validate schema structure, module imports, Storybook configuration, and story file conventions:

```bash theme={null}
npx playwright test tests/integration
```

Integration test directories in `tests/integration/`:

* `blocks-2-1/` — Block registry and component conventions
* `schema-1-3/` — Sanity schema validation
* `storybook-1-4.test.ts` — Storybook config, story files, and build verification
* `site-settings-2-3/` — Site settings schema
* `sponsor-3-1/` — Sponsor document schema
* `template-2-0/`, `variant-2-4/` — Template block wiring

## Browser matrix

Five browser projects cover the primary desktop and mobile combinations:

| Project         | Device          | Use case                |
| --------------- | --------------- | ----------------------- |
| `chromium`      | Desktop Chrome  | Primary desktop browser |
| `firefox`       | Desktop Firefox | Cross-browser coverage  |
| `webkit`        | Desktop Safari  | macOS/iOS engine        |
| `mobile-chrome` | Pixel 7         | Android responsive      |
| `mobile-safari` | iPhone 14       | iOS responsive          |

## playwright.config.ts

```typescript theme={null}
import { defineConfig, devices } from '@playwright/test'

const BASE_URL = process.env.BASE_URL || 'http://localhost:4321'

export default defineConfig({
  testDir: './tests',
  outputDir: './test-results',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,

  reporter: [
    ['html', { outputFolder: 'playwright-report', open: 'never' }],
    ['junit', { outputFile: 'test-results/results.xml' }],
    ['list'],
  ],

  timeout: 60_000,
  expect: { timeout: 10_000 },

  use: {
    baseURL: BASE_URL,
    actionTimeout: 15_000,
    navigationTimeout: 30_000,
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },

  webServer: {
    command: 'sh -c "npm run build --workspace=astro-app && npm run preview --workspace=astro-app"',
    url: BASE_URL,
    reuseExistingServer: !process.env.CI,
    timeout: 120_000,
  },

  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } },
    { name: 'mobile-chrome', use: { ...devices['Pixel 7'] } },
    { name: 'mobile-safari', use: { ...devices['iPhone 14'] } },
  ],
})
```

### CI behavior

* `forbidOnly: true` — `.only()` in test files blocks the pipeline.
* `retries: 2` — Each test gets two retries before failing.
* `workers: 1` — Serial execution for stability (prevents port conflicts).
* Traces captured on first retry, screenshots and videos on failure.

## Test file locations

```text theme={null}
tests/
├── e2e/
│   ├── smoke.spec.ts              # Homepage smoke + a11y + perf baseline
│   ├── navigation.spec.ts         # Header/footer links and routing
│   ├── homepage-2-2.spec.ts       # Homepage block rendering
│   ├── pages-1-2.spec.ts          # Dynamic page routes
│   ├── dynamic-pages.spec.ts      # Sanity-driven page rendering
│   ├── sponsors.spec.ts           # Sponsor directory pages
│   ├── projects.spec.ts           # Project cards and listings
│   ├── events-calendar.spec.ts    # Event calendar block
│   ├── seo-structured-data.spec.ts # JSON-LD and meta tags
│   ├── site-settings-2-3.spec.ts  # Global site settings
│   ├── gtm-datalayer.spec.ts      # GA4 / GTM data layer
│   ├── portal-auth.spec.ts        # Sponsor portal auth flows
│   ├── portal-events.spec.ts      # Portal event management
│   ├── portal-progress.spec.ts    # Portal progress tracking
│   └── error-pages.spec.ts        # 404 and error handling
├── integration/                   # Schema/config validation (no browser)
└── support/
    ├── fixtures/
    │   └── index.ts               # Merged test fixtures
    └── helpers/
        └── a11y.ts                # axe-core WCAG 2.1 AA helper
```

## Fixtures

All test files import from the shared fixtures index instead of importing directly from `@playwright/test`:

```typescript theme={null}
import { test, expect } from '../support/fixtures'
```

The fixture layer provides two automatic behaviors:

* **network-error-monitor** — Fails the test if any HTTP 4xx/5xx responses are detected during page navigation. Opt out per-test with `{ annotation: [{ type: 'skipNetworkMonitoring' }] }`.
* **log** — Structured logging attached to Playwright HTML reports.

## Writing a new E2E test

<Steps>
  <Step title="Create the spec file">
    Add a `.spec.ts` file in `tests/e2e/`. Name it after the feature (e.g., `contact-form.spec.ts`).
  </Step>

  <Step title="Import from fixtures">
    ```typescript theme={null}
    import { test, expect } from '../support/fixtures'
    import { expectAccessible } from '../support/helpers/a11y'
    ```
  </Step>

  <Step title="Write tests with semantic locators">
    Prefer `getByRole`, `getByText`, and `locator` with semantic selectors. Use `data-testid` for elements with no semantic role:

    ```typescript theme={null}
    test('page loads', async ({ page }) => {
      await page.goto('/sponsors')
      await expect(page.getByRole('heading', { name: /sponsors/i })).toBeVisible()
    })
    ```
  </Step>

  <Step title="Include an accessibility assertion">
    Every new page or block test must call `expectAccessible`:

    ```typescript theme={null}
    test('no a11y violations', async ({ page }) => {
      await page.goto('/sponsors')
      await expectAccessible(page)
    })
    ```
  </Step>
</Steps>

## Setting BASE\_URL

By default, tests run against `http://localhost:4321`. Override with the `BASE_URL` environment variable to test a deployed preview URL:

```bash theme={null}
BASE_URL=https://preview.ywcccapstone1.com npm run test:e2e
```

<Note>
  Install browser binaries once after cloning: `npx playwright install --with-deps`
</Note>

## Dependencies

| Package                              | Purpose                              |
| ------------------------------------ | ------------------------------------ |
| `@playwright/test`                   | Test runner and browser automation   |
| `@axe-core/playwright`               | WCAG accessibility auditing          |
| `@seontechnologies/playwright-utils` | Network monitor and logging fixtures |
