Skip to content

Commit 2e6a3c5

Browse files
authored
Merge pull request #64 from trurl-master/feat/css-typed-om
2 parents a3edce5 + c1d1bd7 commit 2e6a3c5

File tree

58 files changed

+13834
-20206
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+13834
-20206
lines changed

.eslintignore

Lines changed: 0 additions & 1 deletion
This file was deleted.

.eslintrc.cjs

Lines changed: 0 additions & 23 deletions
This file was deleted.

.github/workflows/bump.yml

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,38 @@ on:
66
version:
77
description: 'Semver type of new version (major / minor / patch)'
88
required: true
9+
type: choice
10+
options:
11+
- patch
12+
- minor
13+
- major
914

1015
jobs:
1116
bump-version:
1217
name: Bump version
1318
runs-on: ubuntu-latest
1419
steps:
15-
- name: Check out source
16-
uses: actions/checkout@v2
20+
- name: Checkout repo
21+
uses: actions/checkout@v4
22+
with:
23+
token: ${{ secrets.GITHUB_TOKEN }}
1724

18-
- name: Setup Node.js
19-
uses: actions/setup-node@v2
25+
- name: Setup Node.js LTS
26+
uses: actions/setup-node@v4
2027
with:
21-
node-version: '16'
28+
node-version: 'lts/*'
2229
cache: 'npm'
2330

2431
- name: Install dependencies
25-
uses: bahmutov/npm-install@v1
32+
run: npm ci
2633

2734
- name: Setup Git
2835
run: |
29-
git config user.name 'Ivan Galiatin'
30-
git config user.email 'arxcaeli@gmail.com'
36+
git config user.name 'github-actions[bot]'
37+
git config user.email 'github-actions[bot]@users.noreply.github.com'
3138
32-
- name: bump version
39+
- name: Bump version
3340
run: npm version ${{ github.event.inputs.version }}
3441

35-
- name: Push latest version
42+
- name: Push changes
3643
run: git push origin master --follow-tags

.github/workflows/main.yml

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,60 @@
11
name: Validate
22

3-
on: [push]
3+
on: [push, pull_request]
44

55
jobs:
66
build:
7-
name: Build, lint, and test on Node ${{ matrix.node }} and ${{ matrix.os }}
8-
9-
runs-on: ${{ matrix.os }}
10-
strategy:
11-
matrix:
12-
node: ['16.x', '18.x', '20.x']
13-
os: [ubuntu-latest, windows-latest, macOS-latest]
7+
name: Build, lint, and test on Node LTS
8+
runs-on: ubuntu-latest
149

1510
steps:
1611
- name: Checkout repo
17-
uses: actions/checkout@v2
12+
uses: actions/checkout@v4
1813

19-
- name: Use Node ${{ matrix.node }}
20-
uses: actions/setup-node@v1
14+
- name: Setup Node.js LTS
15+
uses: actions/setup-node@v4
2116
with:
22-
node-version: ${{ matrix.node }}
17+
node-version: 'lts/*'
18+
cache: 'npm'
2319

24-
- name: Install deps and build (with cache)
25-
uses: bahmutov/npm-install@v1
20+
- name: Cache build outputs
21+
uses: actions/cache@v4
22+
with:
23+
path: |
24+
dist
25+
.eslintcache
26+
key: ${{ runner.os }}-build-${{ hashFiles('src/**/*', 'tsconfig.json', 'eslint.config.js') }}
27+
restore-keys: |
28+
${{ runner.os }}-build-
29+
30+
- name: Cache test results
31+
uses: actions/cache@v4
2632
with:
27-
working-directory: |
28-
.
29-
examples
33+
path: |
34+
.jest
35+
node_modules/.cache
36+
key: ${{ runner.os }}-tests-${{ hashFiles('src/**/*.test.*', 'src/**/*.spec.*', 'jest.config.ts', 'vitest.config.ts') }}
37+
restore-keys: |
38+
${{ runner.os }}-tests-
39+
40+
- name: Install dependencies
41+
run: npm ci
42+
43+
- name: Install example dependencies
44+
run: npm ci
45+
working-directory: ./examples
46+
47+
- name: Install Playwright browsers
48+
run: npx playwright install --with-deps
3049

3150
- name: Lint
32-
run: npm run lint
51+
run: npm run lint -- --cache
52+
53+
- name: Type check
54+
run: npm run typecheck
3355

34-
- name: Test
35-
run: npm run test:all --ci --coverage --maxWorkers=2
56+
- name: Test all suites in parallel
57+
run: npx npm-run-all -p test:jest test:swc test:vi test:browser test:examples
3658

3759
- name: Build
3860
run: npm run build

.github/workflows/publish.yml

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,57 @@ name: Publish
22

33
on:
44
release:
5-
# This specifies that the build will be triggered when we publish a release
65
types: [published]
76

87
jobs:
98
publish:
10-
name: 'Publish'
9+
name: Publish to NPM
1110
runs-on: ubuntu-latest
12-
if: "!contains(github.ref_name, 'beta')"
11+
if: ${{ !contains(github.ref_name, 'beta') }}
1312
steps:
14-
- uses: actions/checkout@v2
13+
- name: Checkout repo
14+
uses: actions/checkout@v4
1515

16-
- uses: actions/setup-node@v2
16+
- name: Setup Node.js LTS
17+
uses: actions/setup-node@v4
1718
with:
1819
node-version: 'lts/*'
1920
registry-url: https://registry.npmjs.org/
21+
cache: 'npm'
2022

21-
- name: Install deps and build (with cache)
22-
uses: bahmutov/npm-install@v1
23+
- name: Install dependencies
24+
run: npm ci
2325

24-
- run: npm run build
26+
- name: Build package
27+
run: npm run build
2528

26-
- run: npm publish --access public
29+
- name: Publish to NPM
30+
run: npm publish --access public
2731
env:
28-
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
32+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
2933

3034
publish_beta:
31-
name: 'Publish beta'
35+
name: Publish beta to NPM
3236
runs-on: ubuntu-latest
33-
if: contains(github.ref_name, 'beta')
37+
if: ${{ contains(github.ref_name, 'beta') }}
3438
steps:
35-
- uses: actions/checkout@v2
39+
- name: Checkout repo
40+
uses: actions/checkout@v4
3641

37-
- uses: actions/setup-node@v2
42+
- name: Setup Node.js LTS
43+
uses: actions/setup-node@v4
3844
with:
3945
node-version: 'lts/*'
4046
registry-url: https://registry.npmjs.org/
47+
cache: 'npm'
4148

42-
- name: Install deps and build (with cache)
43-
uses: bahmutov/npm-install@v1
49+
- name: Install dependencies
50+
run: npm ci
4451

45-
- run: npm run build
52+
- name: Build package
53+
run: npm run build
4654

47-
- run: npm publish --tag beta --access public
55+
- name: Publish beta to NPM
56+
run: npm publish --tag beta --access public
4857
env:
49-
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
58+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@
33
node_modules
44
.cache
55
.parcel-cache
6+
.eslintcache
7+
.jest
68
dist

.husky/pre-commit

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env sh
2+
. "$(dirname -- "$0")/_/husky.sh"
3+
4+
npm run lint && npm run typecheck

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

README.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ A set of tools for emulating browser behavior in jsdom environment
1919
[matchMedia](#mock-viewport)
2020
[Intersection Observer](#mock-intersectionobserver)
2121
[Resize Observer](#mock-resizeobserver)
22-
[Web Animations API](#mock-web-animations-api)
22+
[Web Animations API](#mock-web-animations-api)
23+
[CSS Typed OM](#mock-css-typed-om)
2324

2425
## Installation
2526

@@ -410,6 +411,37 @@ it('adds an element into the dom and fades it in', async () => {
410411

411412
It's perfectly usable with fake timers, except for the [issue with promises](https://github.com/facebook/jest/issues/2157). Also note that you would need to manually advance timers by the duration of the animation taking frame duration (which currently is set to 16ms in `jest`/`sinon.js`) into account. So if you, say, have an animation with a duration of `300ms`, you will need to advance your timers by the value that is at least the closest multiple of the frame duration, which in this case is `304ms` (`19` frames \* `16ms`). Otherwise the last frame may not fire and the animation won't finish.
412413

414+
## Mock CSS Typed OM
415+
416+
Provides a complete implementation of the CSS Typed Object Model Level 1 specification for testing CSS numeric values and calculations. While primarily used internally by the Web Animations API mock, it's available as a standalone feature supporting all major CSS units, mathematical operations, and type checking.
417+
418+
```jsx
419+
import { mockCSSTypedOM } from 'jsdom-testing-mocks';
420+
421+
mockCSSTypedOM();
422+
423+
it('performs CSS calculations correctly', () => {
424+
const width = CSS.px(100);
425+
const height = CSS.px(200);
426+
427+
expect(width.add(CSS.px(50)).toString()).toBe('150px');
428+
expect(width.mul(height).toString()).toBe('calc(100px * 200px)');
429+
expect(CSS.cm(2.54).to('in').toString()).toBe('1in');
430+
expect(CSS.px(100).min(CSS.px(200), CSS.px(50)).toString()).toBe('50px');
431+
});
432+
433+
it('enforces type safety', () => {
434+
// Cannot add incompatible units or use raw numbers
435+
expect(() => CSS.px(10).add(CSS.em(5))).toThrow();
436+
expect(() => CSS.px(10).add(5)).toThrow();
437+
438+
// Use CSS.number() for dimensionless values
439+
expect(CSS.px(10).add(CSS.number(5)).toString()).toBe('calc(10px + 5)');
440+
});
441+
```
442+
443+
Supports all CSS units (length, angle, time, frequency, resolution, flex, percentage), mathematical operations, and enforces type compatibility rules as defined in the [W3C specification](https://www.w3.org/TR/css-typed-om-1/).
444+
413445
## Current issues
414446

415447
- Needs more tests

0 commit comments

Comments
 (0)