Skip to content

Commit 6294892

Browse files
committed
Basic css typed om support
1 parent a3edce5 commit 6294892

29 files changed

+16070
-9128
lines changed

CLAUDE.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
jsdom-testing-mocks is a TypeScript library that provides browser API mocks for testing in jsdom environments. It supports Jest, Vitest, and @swc/jest testing frameworks.
8+
9+
## Core Mocks
10+
11+
The library provides mocks for these browser APIs:
12+
- **Intersection Observer API** (`src/mocks/intersection-observer.ts`)
13+
- **Resize Observer API** (`src/mocks/resize-observer.ts`)
14+
- **Web Animations API** (`src/mocks/web-animations-api/`)
15+
- **matchMedia/viewport** (`src/mocks/viewport.ts`)
16+
- **CSS Typed OM** (`src/mocks/css-typed-om/`)
17+
- **Size utilities** (`src/mocks/size/`)
18+
19+
## Development Commands
20+
21+
```bash
22+
# Build the library
23+
npm run build
24+
25+
# Watch mode for development
26+
npm run watch
27+
28+
# Run all tests
29+
npm test
30+
31+
# Run specific test suites
32+
npm run test:jest # Jest tests
33+
npm run test:vi # Vitest tests (excludes .browser.test.ts)
34+
npm run test:swc # SWC Jest tests
35+
npm run test:browser # Browser tests with Playwright
36+
npm run test:main # Jest + Vitest + SWC in sequence
37+
38+
# Test examples
39+
npm run test:examples
40+
41+
# Linting and type checking
42+
npm run lint
43+
npm run typecheck
44+
```
45+
46+
## Testing Architecture
47+
48+
The project uses multiple testing strategies:
49+
50+
1. **Unit Tests** (`.test.ts`) - Run in jsdom with Jest/Vitest
51+
2. **Environment Tests** (`.env.test.ts`) - Test framework-specific behavior
52+
3. **Browser Tests** (`.browser.test.ts`) - Run in real browsers via Playwright
53+
54+
### Test Configurations
55+
56+
- `jest.config.ts` - Main Jest config with ts-jest preset
57+
- `swcjest.config.js` - SWC-based Jest config for faster compilation
58+
- `vitest.config.ts` - Vitest config excluding browser tests
59+
- `vitest.browser.config.ts` - Browser tests with Playwright provider
60+
61+
### Running Single Tests
62+
63+
```bash
64+
# Jest single test
65+
npx jest path/to/test.test.ts
66+
67+
# Vitest single test
68+
npx vitest path/to/test.test.ts
69+
70+
# Browser test
71+
npx vitest --config vitest.browser.config.ts path/to/test.browser.test.ts
72+
```
73+
74+
## Code Architecture
75+
76+
### Main Entry Point
77+
`src/index.ts` - Exports all public APIs from individual mock modules
78+
79+
### Mock Structure
80+
Each mock follows this pattern:
81+
- Main implementation file (`{name}.ts`)
82+
- Unit tests (`{name}.test.ts`)
83+
- Environment-specific tests (`{name}.env.test.ts`)
84+
- Browser tests (`{name}.browser.test.ts` where applicable)
85+
86+
### Web Animations API
87+
Most complex mock with multiple files:
88+
- `Animation.ts`, `KeyframeEffect.ts`, `DocumentTimeline.ts` - Core classes
89+
- `cssNumberishHelpers.ts` - Type conversion utilities
90+
- `easingFunctions.ts` - Animation easing support
91+
- `elementAnimations.ts` - Element-specific animation tracking
92+
93+
## Build Configuration
94+
95+
- **tsup** for dual CJS/ESM builds
96+
- **TypeScript** with strict mode enabled
97+
- **ESLint** with TypeScript rules
98+
- **Prettier** for code formatting
99+
100+
## Key Dependencies
101+
102+
- `bezier-easing` - Animation easing functions
103+
- `css-mediaquery` - Media query parsing
104+
- `puppeteer` - Browser automation for tests

capture-browser-results.js

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import puppeteer from 'puppeteer';
2+
import fs from 'fs';
3+
import path from 'path';
4+
import { fileURLToPath } from 'url';
5+
6+
const __filename = fileURLToPath(import.meta.url);
7+
const __dirname = path.dirname(__filename);
8+
9+
async function captureBrowserResults(testFile = 'comprehensive-browser-verification.html') {
10+
console.log('Starting browser test capture...');
11+
12+
const browser = await puppeteer.launch({
13+
headless: false,
14+
defaultViewport: { width: 1920, height: 1080 }
15+
});
16+
17+
try {
18+
const page = await browser.newPage();
19+
20+
// Navigate to our test file
21+
const testFilePath = path.resolve(__dirname, testFile);
22+
await page.goto(`file://${testFilePath}`);
23+
24+
console.log('Waiting for tests to complete...');
25+
26+
// Wait for tests to finish (look for results element)
27+
await page.waitForSelector('#results', { timeout: 30000 });
28+
29+
// Wait a bit more for all tests to complete
30+
await new Promise(resolve => setTimeout(resolve, 3000));
31+
32+
// Capture browser info
33+
const browserInfo = await page.evaluate(() => {
34+
// eslint-disable-next-line no-undef
35+
const infoElement = document.getElementById('browser-info');
36+
return infoElement ? infoElement.innerText : 'Browser info not found';
37+
});
38+
39+
// Capture expressions results
40+
const expressions = await page.evaluate(() => {
41+
// eslint-disable-next-line no-undef
42+
const expressionResults = document.querySelectorAll('.expression-result');
43+
const results = [];
44+
45+
expressionResults.forEach((result, index) => {
46+
const expression = result.querySelector('.expression')?.innerText || `Expression ${index}`;
47+
const resultValue = result.querySelector('.result')?.innerText || '';
48+
const type = result.querySelector('.type')?.innerText || '';
49+
const error = result.querySelector('.error')?.innerText || '';
50+
51+
results.push({
52+
expression,
53+
result: resultValue,
54+
type: type.replace('Type: ', ''),
55+
error: error.replace('Error: ', '')
56+
});
57+
});
58+
59+
return results;
60+
});
61+
62+
// Create test results format for compatibility
63+
const testResults = expressions.map(expr => ({
64+
testName: expr.expression,
65+
status: expr.error ? '✗ FAIL' : '✓ PASS',
66+
expectedType: '',
67+
actualType: expr.type,
68+
expectedValue: '',
69+
actualValue: expr.result,
70+
error: expr.error,
71+
comparison: expr.error ? `Browser throws: ${expr.error}` : `Browser returns: ${expr.result}`,
72+
behaviorNote: ''
73+
}));
74+
75+
const summary = `Total: ${testResults.length} | Passed: ${testResults.filter(r => r.status === '✓ PASS').length} | Failed: ${testResults.filter(r => r.status === '✗ FAIL').length}`;
76+
77+
// Generate report
78+
const report = {
79+
timestamp: new Date().toISOString(),
80+
browserInfo,
81+
summary,
82+
testResults
83+
};
84+
85+
// Save detailed report
86+
const reportPath = path.join(__dirname, 'browser-test-results.json');
87+
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));
88+
89+
// Generate human-readable report
90+
const humanReadableReport = generateHumanReadableReport(report);
91+
const humanReportPath = path.join(__dirname, 'browser-test-results.txt');
92+
fs.writeFileSync(humanReportPath, humanReadableReport);
93+
94+
console.log('\n=== BROWSER TEST RESULTS ===');
95+
console.log(browserInfo);
96+
console.log('\n' + summary);
97+
console.log('\nDetailed results saved to:');
98+
console.log('- browser-test-results.json (structured data)');
99+
console.log('- browser-test-results.txt (human readable)');
100+
101+
// Show some key findings
102+
const passed = testResults.filter(r => r.status.includes('PASS')).length;
103+
const failed = testResults.filter(r => r.status.includes('FAIL')).length;
104+
const warnings = testResults.filter(r => r.status.includes('WARNING')).length;
105+
const skipped = testResults.filter(r => r.status.includes('SKIP')).length;
106+
107+
console.log(`\n=== KEY FINDINGS ===`);
108+
console.log(`Passed: ${passed}`);
109+
console.log(`Failed: ${failed}`);
110+
console.log(`Warnings: ${warnings}`);
111+
console.log(`Skipped: ${skipped}`);
112+
113+
// Show some interesting discrepancies
114+
const discrepancies = testResults.filter(r =>
115+
r.status.includes('WARNING') ||
116+
(r.status.includes('PASS') && r.comparison && !r.comparison.includes('Expected'))
117+
);
118+
119+
if (discrepancies.length > 0) {
120+
console.log(`\n=== INTERESTING DISCREPANCIES ===`);
121+
discrepancies.slice(0, 10).forEach(d => {
122+
console.log(`\n${d.testName}:`);
123+
console.log(` Expected: ${d.expectedType} - ${d.expectedValue}`);
124+
console.log(` Actual: ${d.actualType} - ${d.actualValue}`);
125+
if (d.comparison) console.log(` Browser: ${d.comparison}`);
126+
});
127+
}
128+
129+
} catch (error) {
130+
console.error('Error capturing browser results:', error);
131+
} finally {
132+
await browser.close();
133+
}
134+
}
135+
136+
function generateHumanReadableReport(report) {
137+
let output = '';
138+
139+
output += 'CSS TYPED OM BROWSER VERIFICATION RESULTS\n';
140+
output += '==========================================\n\n';
141+
output += `Timestamp: ${report.timestamp}\n\n`;
142+
143+
output += 'BROWSER INFORMATION\n';
144+
output += '-------------------\n';
145+
output += report.browserInfo + '\n\n';
146+
147+
output += 'SUMMARY\n';
148+
output += '-------\n';
149+
output += report.summary + '\n\n';
150+
151+
output += 'DETAILED TEST RESULTS\n';
152+
output += '---------------------\n';
153+
154+
const categories = {};
155+
report.testResults.forEach(result => {
156+
const category = result.testName.split(':')[0];
157+
if (!categories[category]) categories[category] = [];
158+
categories[category].push(result);
159+
});
160+
161+
Object.entries(categories).forEach(([category, tests]) => {
162+
output += `\n${category.toUpperCase()}\n`;
163+
output += '-'.repeat(category.length) + '\n';
164+
165+
tests.forEach(test => {
166+
output += `\n${test.testName}\n`;
167+
output += ` Status: ${test.status}\n`;
168+
output += ` Expected Type: ${test.expectedType}\n`;
169+
output += ` Actual Type: ${test.actualType}\n`;
170+
output += ` Expected Value: ${test.expectedValue}\n`;
171+
output += ` Actual Value: ${test.actualValue}\n`;
172+
173+
if (test.error) output += ` Error: ${test.error}\n`;
174+
if (test.comparison) output += ` Browser Behavior: ${test.comparison}\n`;
175+
if (test.behaviorNote) output += ` Note: ${test.behaviorNote}\n`;
176+
});
177+
});
178+
179+
return output;
180+
}
181+
182+
// Run the capture
183+
const testFile = process.argv[2] || 'comprehensive-browser-verification.html';
184+
captureBrowserResults(testFile).catch(console.error);

0 commit comments

Comments
 (0)