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
57 changes: 54 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,66 @@ jobs:
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
# For the `browser` test project (Vitest browser mode).
- name: Install browsers
if: matrix.os == 'ubuntu-latest'
run: pnpm exec playwright install --with-deps --only-shell chromium firefox webkit
- name: Check
if: matrix.os == 'ubuntu-latest'
run: pnpm check
# Node project only (v8 coverage doesn't work in Firefox or WebKit).
# Reported in the job summary, not gated: Check gates on the tests.
- name: Coverage
if: matrix.os == 'ubuntu-latest'
continue-on-error: true
run: pnpm test --project node --coverage
- name: Coverage summary
if: always() && matrix.os == 'ubuntu-latest'
run: |
{
echo '### Coverage'
if [ -f coverage/summary.txt ]; then
echo '```'
cat coverage/summary.txt
echo '```'
else
echo 'No coverage summary (the Coverage step failed or was skipped).'
fi
} >> "$GITHUB_STEP_SUMMARY"
# Report only: adds the size table to the job summary, never fails.
- name: Size
if: always() && matrix.os == 'ubuntu-latest'
run: pnpm size --base HEAD^1
# Format, lint and the packed tarball don't depend on the OS, so Windows
# only runs the tests.
# Format, lint, the packed tarball and the browsers don't depend on the
# OS, so Windows only runs the Node tests.
- name: Test
if: matrix.os == 'windows-latest'
run: pnpm test
run: pnpm test --project node

# The lockfile has React 19 and Preact 11, which the test job covers. This
# job runs the Node tests on the oldest versions we check: exactly React
# 18.0.0, and the newest Preact 10 (`preact/compat`). The library doesn't
# depend on either; this guards its `$$typeof` / `_owner` handling.
older-renderers:
name: Test (React 18.0.0, Preact 10)
runs-on: ubuntu-latest
permissions:
contents: read # to check out repo (actions/checkout)
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
- uses: actions/setup-node@v7
with:
node-version-file: '.nvmrc'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
# Changes the working tree only; nothing is committed.
- name: Install React 18.0.0 and Preact 10
run: |
pnpm add --save-dev react@18.0.0 react-dom@18.0.0 preact@^10
node -e 'for (const [p, v] of [["react", "18.0.0"], ["react-dom", "18.0.0"], ["preact", "10."]]) { const got = require(`${p}/package.json`).version; console.log(`${p} ${got}`); if (!got.startsWith(v)) throw new Error(`${p} is ${got}, expected ${v}`); }'
- name: Test
run: pnpm test --project node
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ yarn.lock

# Test output
coverage/
.nyc_output/
test/typescript/*.js

# Output of `npm pack` / `pnpm pack`
*.tgz
Expand Down
3 changes: 0 additions & 3 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@
"overrides": [
{
"files": ["test/**"],
"env": {
"mocha": true
},
"globals": {
"document": "readonly",
"Element": "readonly"
Expand Down
57 changes: 28 additions & 29 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,53 +53,52 @@ included. For an urgent security fix that's newer than that, add the package to
**TL; DR:** - Everything you normally need to run is aggregated into:

```sh
# Format, lint, then all tests
# Format, lint, types, all tests, then the packed package
$ pnpm run check
$ pnpm run benchmark
```

(We use `builder` to parallelize things, so tasks may output in different
orders)

### Testing

We write one set of tests located in:

- `test/node/**.spec.js`
We test with [Vitest](https://vitest.dev/). One set of specs, `test/*.spec.mjs`,
runs in two projects (`vitest.config.mts`):

that run in two very different scenarios (below). Most generic test cases come
from `fast-deep-equal`, vendored unchanged in `test/fixtures/fast-deep-equal/`
(see its README).
- `node`: Node, with [jsdom](https://github.com/jsdom/jsdom) for the specs
that need a DOM.
- `browser`: [Vitest browser mode](https://vitest.dev/guide/browser/) in
headless Chromium, Firefox and WebKit, through Playwright.

#### Node
Most generic test cases come from `fast-deep-equal`, vendored unchanged in
`test/fixtures/fast-deep-equal/` (see its README). Our own cases (React
elements, custom behavior) are in `test/fixtures/index.mjs`, and
`test/react.spec.mjs` renders real React and Preact (`preact/compat`)
components.

The tests are natively run in `node` (hence why they are located in `tests/node`
to begin with) without any transpilation or "build". You can run them with:
Install the browsers once (and again when Playwright is updated):

```sh
# Single run
$ pnpm run test-node

# Persistent watch
$ pnpm run test-node --watch
$ pnpm exec playwright install --only-shell chromium firefox webkit
```

#### Browsers
```sh
# All projects
$ pnpm test

The same tests are then imported and built with `webpack` to a test bundle that
can be run in arbitrary browsers. CI runs them in headless Chrome on Linux and
Windows (GitHub Actions).
# Node only, or one browser
$ pnpm test --project node
$ pnpm test --project "browser (firefox)"

To run the browser tests on your machine (note: you must already have the
browser you're running installed):
# Watch mode
$ pnpm vitest --project node

```sh
# Default: headless chrome
$ pnpm run test-browser
# Example: real Chrome + Firefox + Safari
$ pnpm run test-browser --browsers Chrome,Firefox,Safari
# Coverage (Node only; v8 coverage doesn't work in Firefox or WebKit)
$ pnpm test --project node --coverage
```

CI runs every project on Linux and adds the coverage summary to the job
summary. It runs the Node project on Windows, and on React 18.0.0 with Preact
10 (the lockfile has React 19 and Preact 11).

### Types

`pnpm types:check` type-checks `index.js` from its JSDoc and checks that the declarations it emits match `index.d.ts`. `pnpm pack:check` then compiles the type probe in `test/types/` against the packed package, as a CommonJS (`.cts`) and an ES module (`.mts`) consumer. Add a case there for any usage the types must keep supporting.
Expand Down
2 changes: 1 addition & 1 deletion benchmark/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

const tests = require('../test/node/tests');
const tests = require('../test/fixtures/index.mjs');
const Benchmark = require('benchmark');

const correctnessTests = [];
Expand Down
50 changes: 9 additions & 41 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,14 @@
"main": "index.js",
"typings": "index.d.ts",
"scripts": {
"preversion": "pnpm check",
"check": "pnpm format && pnpm lint && pnpm types:check && pnpm test && pnpm pack:check",
"benchmark": "node benchmark",
"format": "oxfmt --check",
"format:fix": "oxfmt",
"lint": "oxlint --report-unused-disable-directives-severity=error",
"lint:fix": "oxlint --report-unused-disable-directives-severity=error --fix",
"types:check": "node scripts/types-check.mjs",
"test-browser": "karma start test/browser/karma.conf.js",
"test-node": "mocha \"test/node/*.spec.js\"",
"test-node-cov": "nyc mocha \"test/node/*.spec.js\"",
"test": "builder concurrent --buffer test-node-cov test-browser",
"test": "vitest run",
"changeset": "changeset",
"pack:check": "node scripts/pack-check.mjs",
"size": "node scripts/size.mjs"
Expand All @@ -42,55 +38,27 @@
"packageManager": "pnpm@12.16.0",
"devDependencies": {
"@arethetypeswrong/cli": "0.18.5",
"@babel/core": "^7.21.0",
"@babel/preset-env": "^7.20.2",
"@changesets/changelog-github": "^1.0.1",
"@changesets/cli": "^3.0.3",
"@testing-library/dom": "^9.0.1",
"@testing-library/preact": "^3.2.3",
"@types/node": "^18.15.0",
"@types/react": "^19.3.0",
"assert": "^2.0.0",
"babel-loader": "^9.1.2",
"@vitest/browser-playwright": "^5.0.5",
"@vitest/coverage-v8": "^5.0.5",
"benchmark": "^2.1.4",
"builder": "^5.0.0",
"core-js": "^3.29.0",
"fast-deep-equal": "3.1.3",
"jsdom": "^21.1.0",
"jsdom-global": "^3.0.2",
"karma": "^6.4.1",
"karma-chrome-launcher": "^3.1.1",
"karma-firefox-launcher": "^2.1.2",
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.5",
"karma-safari-launcher": "^1.0.0",
"karma-webpack": "^5.0.0",
"jsdom": "^30.1.3",
"lodash": "^4.17.10",
"mocha": "^11.8.0",
"nano-equal": "^2.0.2",
"nyc": "^15.1.0",
"oxfmt": "0.75.0",
"oxlint": "1.90.0",
"preact": "^10.13.1",
"process": "^0.11.10",
"playwright": "^1.64.1",
"preact": "^11.1.1",
"publint": "0.3.25",
"react": "^18.2.0",
"react-test-renderer": "^18.2.0",
"react": "^19.3.1",
"react-dom": "^19.3.1",
"shallow-equal-fuzzy": "0.0.2",
"sinon": "^15.0.1",
"terser": "5.51.2",
"typescript": "7.0.2",
"webpack": "^5.76.0"
},
"nyc": {
"exclude": [
"**/test/**",
"node_modules"
],
"reporter": [
"lcov",
"text-summary"
]
"vitest": "^5.0.5"
},
"files": [
"index.js",
Expand Down
Loading
Loading