Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .eslintignore

This file was deleted.

23 changes: 0 additions & 23 deletions .eslintrc.cjs

This file was deleted.

27 changes: 17 additions & 10 deletions .github/workflows/bump.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,38 @@ on:
version:
description: 'Semver type of new version (major / minor / patch)'
required: true
type: choice
options:
- patch
- minor
- major

jobs:
bump-version:
name: Bump version
runs-on: ubuntu-latest
steps:
- name: Check out source
uses: actions/checkout@v2
- name: Checkout repo
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}

- name: Setup Node.js
uses: actions/setup-node@v2
- name: Setup Node.js LTS
uses: actions/setup-node@v4
with:
node-version: '16'
node-version: 'lts/*'
cache: 'npm'

- name: Install dependencies
uses: bahmutov/npm-install@v1
run: npm ci

- name: Setup Git
run: |
git config user.name 'Ivan Galiatin'
git config user.email 'arxcaeli@gmail.com'
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'

- name: bump version
- name: Bump version
run: npm version ${{ github.event.inputs.version }}

- name: Push latest version
- name: Push changes
run: git push origin master --follow-tags
62 changes: 42 additions & 20 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,38 +1,60 @@
name: Validate

on: [push]
on: [push, pull_request]

jobs:
build:
name: Build, lint, and test on Node ${{ matrix.node }} and ${{ matrix.os }}

runs-on: ${{ matrix.os }}
strategy:
matrix:
node: ['16.x', '18.x', '20.x']
os: [ubuntu-latest, windows-latest, macOS-latest]
name: Build, lint, and test on Node LTS
runs-on: ubuntu-latest

steps:
- name: Checkout repo
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Use Node ${{ matrix.node }}
uses: actions/setup-node@v1
- name: Setup Node.js LTS
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
node-version: 'lts/*'
cache: 'npm'

- name: Install deps and build (with cache)
uses: bahmutov/npm-install@v1
- name: Cache build outputs
uses: actions/cache@v4
with:
path: |
dist
.eslintcache
key: ${{ runner.os }}-build-${{ hashFiles('src/**/*', 'tsconfig.json', 'eslint.config.js') }}
restore-keys: |
${{ runner.os }}-build-

- name: Cache test results
uses: actions/cache@v4
with:
working-directory: |
.
examples
path: |
.jest
node_modules/.cache
key: ${{ runner.os }}-tests-${{ hashFiles('src/**/*.test.*', 'src/**/*.spec.*', 'jest.config.ts', 'vitest.config.ts') }}
restore-keys: |
${{ runner.os }}-tests-

- name: Install dependencies
run: npm ci

- name: Install example dependencies
run: npm ci
working-directory: ./examples

- name: Install Playwright browsers
run: npx playwright install --with-deps

- name: Lint
run: npm run lint
run: npm run lint -- --cache

- name: Type check
run: npm run typecheck

- name: Test
run: npm run test:all --ci --coverage --maxWorkers=2
- name: Test all suites in parallel
run: npx npm-run-all -p test:jest test:swc test:vi test:browser test:examples

- name: Build
run: npm run build
47 changes: 28 additions & 19 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,57 @@ name: Publish

on:
release:
# This specifies that the build will be triggered when we publish a release
types: [published]

jobs:
publish:
name: 'Publish'
name: Publish to NPM
runs-on: ubuntu-latest
if: "!contains(github.ref_name, 'beta')"
if: ${{ !contains(github.ref_name, 'beta') }}
steps:
- uses: actions/checkout@v2
- name: Checkout repo
uses: actions/checkout@v4

- uses: actions/setup-node@v2
- name: Setup Node.js LTS
uses: actions/setup-node@v4
with:
node-version: 'lts/*'
registry-url: https://registry.npmjs.org/
cache: 'npm'

- name: Install deps and build (with cache)
uses: bahmutov/npm-install@v1
- name: Install dependencies
run: npm ci

- run: npm run build
- name: Build package
run: npm run build

- run: npm publish --access public
- name: Publish to NPM
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

publish_beta:
name: 'Publish beta'
name: Publish beta to NPM
runs-on: ubuntu-latest
if: contains(github.ref_name, 'beta')
if: ${{ contains(github.ref_name, 'beta') }}
steps:
- uses: actions/checkout@v2
- name: Checkout repo
uses: actions/checkout@v4

- uses: actions/setup-node@v2
- name: Setup Node.js LTS
uses: actions/setup-node@v4
with:
node-version: 'lts/*'
registry-url: https://registry.npmjs.org/
cache: 'npm'

- name: Install deps and build (with cache)
uses: bahmutov/npm-install@v1
- name: Install dependencies
run: npm ci

- run: npm run build
- name: Build package
run: npm run build

- run: npm publish --tag beta --access public
- name: Publish beta to NPM
run: npm publish --tag beta --access public
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
node_modules
.cache
.parcel-cache
.eslintcache
.jest
dist
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run lint && npm run typecheck
104 changes: 104 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

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.

## Core Mocks

The library provides mocks for these browser APIs:
- **Intersection Observer API** (`src/mocks/intersection-observer.ts`)
- **Resize Observer API** (`src/mocks/resize-observer.ts`)
- **Web Animations API** (`src/mocks/web-animations-api/`)
- **matchMedia/viewport** (`src/mocks/viewport.ts`)
- **CSS Typed OM** (`src/mocks/css-typed-om/`)
- **Size utilities** (`src/mocks/size/`)

## Development Commands

```bash
# Build the library
npm run build

# Watch mode for development
npm run watch

# Run all tests
npm test

# Run specific test suites
npm run test:jest # Jest tests
npm run test:vi # Vitest tests (excludes .browser.test.ts)
npm run test:swc # SWC Jest tests
npm run test:browser # Browser tests with Playwright
npm run test:main # Jest + Vitest + SWC in sequence

# Test examples
npm run test:examples

# Linting and type checking
npm run lint
npm run typecheck
```

## Testing Architecture

The project uses multiple testing strategies:

1. **Unit Tests** (`.test.ts`) - Run in jsdom with Jest/Vitest
2. **Environment Tests** (`.env.test.ts`) - Test framework-specific behavior
3. **Browser Tests** (`.browser.test.ts`) - Run in real browsers via Playwright

### Test Configurations

- `jest.config.ts` - Main Jest config with ts-jest preset
- `swcjest.config.js` - SWC-based Jest config for faster compilation
- `vitest.config.ts` - Vitest config excluding browser tests
- `vitest.browser.config.ts` - Browser tests with Playwright provider

### Running Single Tests

```bash
# Jest single test
npx jest path/to/test.test.ts

# Vitest single test
npx vitest path/to/test.test.ts

# Browser test
npx vitest --config vitest.browser.config.ts path/to/test.browser.test.ts
```

## Code Architecture

### Main Entry Point
`src/index.ts` - Exports all public APIs from individual mock modules

### Mock Structure
Each mock follows this pattern:
- Main implementation file (`{name}.ts`)
- Unit tests (`{name}.test.ts`)
- Environment-specific tests (`{name}.env.test.ts`)
- Browser tests (`{name}.browser.test.ts` where applicable)

### Web Animations API
Most complex mock with multiple files:
- `Animation.ts`, `KeyframeEffect.ts`, `DocumentTimeline.ts` - Core classes
- `cssNumberishHelpers.ts` - Type conversion utilities
- `easingFunctions.ts` - Animation easing support
- `elementAnimations.ts` - Element-specific animation tracking

## Build Configuration

- **tsup** for dual CJS/ESM builds
- **TypeScript** with strict mode enabled
- **ESLint** with TypeScript rules
- **Prettier** for code formatting

## Key Dependencies

- `bezier-easing` - Animation easing functions
- `css-mediaquery` - Media query parsing
- `puppeteer` - Browser automation for tests
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ A set of tools for emulating browser behavior in jsdom environment
[matchMedia](#mock-viewport)
[Intersection Observer](#mock-intersectionobserver)
[Resize Observer](#mock-resizeobserver)
[Web Animations API](#mock-web-animations-api)
[Web Animations API](#mock-web-animations-api)
[CSS Typed OM](#mock-css-typed-om)

## Installation

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

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.

## Mock CSS Typed OM

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.

```jsx
import { mockCSSTypedOM } from 'jsdom-testing-mocks';

mockCSSTypedOM();

it('performs CSS calculations correctly', () => {
const width = CSS.px(100);
const height = CSS.px(200);

expect(width.add(CSS.px(50)).toString()).toBe('150px');
expect(width.mul(height).toString()).toBe('calc(100px * 200px)');
expect(CSS.cm(2.54).to('in').toString()).toBe('1in');
expect(CSS.px(100).min(CSS.px(200), CSS.px(50)).toString()).toBe('50px');
});

it('enforces type safety', () => {
// Cannot add incompatible units or use raw numbers
expect(() => CSS.px(10).add(CSS.em(5))).toThrow();
expect(() => CSS.px(10).add(5)).toThrow();

// Use CSS.number() for dimensionless values
expect(CSS.px(10).add(CSS.number(5)).toString()).toBe('calc(10px + 5)');
});
```

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/).

## Current issues

- Needs more tests
Expand Down
Loading