extension-testlisted
Install: claude install-skill andrewr303/claude-codex-plugin-lab
# Extension Testing
## Testing Layer Architecture
```
Unit Tests (Jest) → Test isolated logic, chrome.* API mocks
Integration Tests (Jest) → Test service interactions, message passing
E2E Tests (Puppeteer) → Test in real Chrome with extension loaded
```
**Critical constraint**: Extensions CANNOT run in headless mode. E2E requires `headless: false` or Chrome's `--headless=new` (Chrome 112+).
---
## Layer 1: Unit + Integration (Jest)
### Install
```bash
npm install -D jest @types/jest ts-jest jest-chrome
# For React popup:
npm install -D @testing-library/react @testing-library/jest-dom jsdom
```
### jest.config.ts
```ts
export default {
preset: 'ts-jest',
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['./jest.setup.ts'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
};
```
### jest.setup.ts (minimal)
```ts
import chrome from 'jest-chrome';
Object.assign(global, { chrome });
```
Full mock setup → [chrome-api-mocks.md](references/chrome-api-mocks.md)
Unit/integration patterns → [unit-integration-testing.md](references/unit-integration-testing.md)
---
## Layer 2: E2E (Puppeteer)
### Install
```bash
npm install -D puppeteer
```
### Launch extension in Chrome
```ts
import puppeteer from 'puppeteer';
import path from 'path';
const browser = await puppeteer.launch({
headless: false, // extensions require non-headless
args: [
`--disable-extensions-except=${path.resolve('dist')}`,
`--load-extension=${path.re