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
6 changes: 2 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@

## [1.1.0](https://github.com/Lojhan/poku-react-testing/compare/v1.0.1...v1.1.0) (2026-03-31)


### Features

* optimize react testing runtime and add prettier ([#6](https://github.com/Lojhan/poku-react-testing/issues/6)) ([424194b](https://github.com/Lojhan/poku-react-testing/commit/424194b2c5bdc5f8c3d3c7a41bc91b50d51dd38c))
- optimize react testing runtime and add prettier ([#6](https://github.com/Lojhan/poku-react-testing/issues/6)) ([424194b](https://github.com/Lojhan/poku-react-testing/commit/424194b2c5bdc5f8c3d3c7a41bc91b50d51dd38c))

## [1.0.1](https://github.com/Lojhan/poku-react-testing/compare/v1.0.0...v1.0.1) (2026-03-31)


### Bug Fixes

* add repository metadata required for npm provenance ([#4](https://github.com/Lojhan/poku-react-testing/issues/4)) ([f20b16a](https://github.com/Lojhan/poku-react-testing/commit/f20b16a9ab72bb957743c7739a926d0bfb851f68))
- add repository metadata required for npm provenance ([#4](https://github.com/Lojhan/poku-react-testing/issues/4)) ([f20b16a](https://github.com/Lojhan/poku-react-testing/commit/f20b16a9ab72bb957743c7739a926d0bfb851f68))

## 1.0.0 (2026-03-31)

Expand Down
103 changes: 52 additions & 51 deletions benchmark/REPORT.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,49 @@
# React Testing Framework Benchmark Report

> Generated: Tue, 31 Mar 2026 21:00:50 GMT
> Generated: Wed, 01 Apr 2026 12:41:50 GMT

## Environment

| Property | Value |
|---|---|
| Node.js | v22.5.1 |
| Platform | darwin 25.4.0 |
| CPU | Apple M3 Pro |
| CPU Cores | 12 |
| Total RAM | 18.0 GB |
| Runs/scenario | 7 (trim ±1) |
| Property | Value |
| ------------- | ------------- |
| Node.js | v22.5.1 |
| Platform | darwin 25.4.0 |
| CPU | Apple M3 Pro |
| CPU Cores | 12 |
| Total RAM | 18.0 GB |
| Runs/scenario | 7 (trim ±1) |

## Scenarios

Each scenario runs the **same 9 React tests** across 5 test files:

| Test File | Tests |
|---|---|
| 'counter.test.jsx' | 1 — stateful counter, event interaction |
| 'hooks.test.jsx' | 2 — custom hook harness + `renderHook` |
| 'lifecycle.test.jsx' | 2 — `rerender`, `unmount` + effect cleanup |
| 'context.test.jsx' | 1 — `createContext` + wrapper injection |
| 'concurrency.test.jsx' | 2 — React 19 `use()` + `useTransition` |
| Test File | Tests |
| ---------------------- | ------------------------------------------ |
| 'counter.test.jsx' | 1 — stateful counter, event interaction |
| 'hooks.test.jsx' | 2 — custom hook harness + `renderHook` |
| 'lifecycle.test.jsx' | 2 — `rerender`, `unmount` + effect cleanup |
| 'context.test.jsx' | 1 — `createContext` + wrapper injection |
| 'concurrency.test.jsx' | 2 — React 19 `use()` + `useTransition` |

### Frameworks under test

| Combination | DOM layer | Assertion style |
|---|---|---|
| poku + poku-react-testing | happy-dom | `assert.strictEqual` |
| poku + poku-react-testing | jsdom | `assert.strictEqual` |
| jest 29 + @testing-library/react | jsdom (jest-environment-jsdom) | `expect().toBe()` |
| vitest 3 + @testing-library/react | jsdom | `expect().toBe()` |
| vitest 3 + @testing-library/react | happy-dom | `expect().toBe()` |
| Combination | DOM layer | Assertion style |
| --------------------------------- | ------------------------------ | -------------------- |
| poku + poku-react-testing | happy-dom | `assert.strictEqual` |
| poku + poku-react-testing | jsdom | `assert.strictEqual` |
| jest 29 + @testing-library/react | jsdom (jest-environment-jsdom) | `expect().toBe()` |
| vitest 3 + @testing-library/react | jsdom | `expect().toBe()` |
| vitest 3 + @testing-library/react | happy-dom | `expect().toBe()` |

## Results

| Scenario | Mean | Min | Max | Stdev | Peak RSS | vs poku+happy-dom |
|--------------------|--------|--------|--------|--------|----------|-------------------|
| poku + happy-dom | 1.073s | 0.996s | 1.230s | 0.085s | 163.3 MB | *(baseline)* |
| poku + jsdom | 1.060s | 1.007s | 1.177s | 0.060s | 163.4 MB | -1% |
| jest + jsdom | 0.859s | 0.779s | 0.929s | 0.050s | 206.2 MB | -20% |
| vitest + jsdom | 0.964s | 0.950s | 0.987s | 0.017s | 148.0 MB | -10% |
| vitest + happy-dom | 0.838s | 0.812s | 0.864s | 0.021s | 116.3 MB | -22% |
| ------------------ | ------ | ------ | ------ | ------ | -------- | ----------------- |
| poku + happy-dom | 0.560s | 0.515s | 0.600s | 0.033s | 154.3 MB | _(baseline)_ |
| poku + jsdom | 0.444s | 0.429s | 0.451s | 0.008s | 157.1 MB | -21% |
| jest + jsdom | 1.040s | 0.975s | 1.135s | 0.056s | 203.4 MB | +86% |
| vitest + jsdom | 1.193s | 1.129s | 1.269s | 0.057s | 152.3 MB | +113% |
| vitest + happy-dom | 1.041s | 0.990s | 1.126s | 0.047s | 117.1 MB | +86% |

> **Wall-clock time** is measured with `performance.now()` around the child-process spawn.
> **Peak RSS** is captured via `/usr/bin/time -l` on macOS (bytes → MB).
Expand All @@ -53,44 +53,44 @@ Each scenario runs the **same 9 React tests** across 5 test files:

### Overall ranking (mean wall-clock time)

1. **vitest + happy-dom** — 0.838s
2. **jest + jsdom** — 0.859s
3. **vitest + jsdom** — 0.964s
4. **poku + jsdom** — 1.060s
5. **poku + happy-dom** — 1.073s
1. **poku + jsdom** — 0.444s
2. **poku + happy-dom** — 0.560s
3. **jest + jsdom** — 1.040s
4. **vitest + happy-dom** — 1.041s
5. **vitest + jsdom** — 1.193s

### Speed comparison

- poku+happy-dom vs jest+jsdom: jest is **-20% faster**
- poku+happy-dom vs vitest+jsdom: vitest is **-10% faster**
- jest+jsdom vs vitest+jsdom: vitest is **12% slower** than jest
- poku+happy-dom vs jest+jsdom: jest is **86% slower**
- poku+happy-dom vs vitest+jsdom: vitest is **113% slower**
- jest+jsdom vs vitest+jsdom: vitest is **15% slower** than jest

### DOM adapter impact

- **poku**: happy-dom vs jsdom — jsdom is **-1% faster**
- **poku**: happy-dom vs jsdom — jsdom is **-21% faster**
- **vitest**: happy-dom vs jsdom — jsdom is **15% slower**

### Memory footprint

- **vitest + happy-dom**: 116.3 MB peak RSS
- **vitest + jsdom**: 148.0 MB peak RSS
- **poku + happy-dom**: 163.3 MB peak RSS
- **poku + jsdom**: 163.4 MB peak RSS
- **jest + jsdom**: 206.2 MB peak RSS
- **vitest + happy-dom**: 117.1 MB peak RSS
- **vitest + jsdom**: 152.3 MB peak RSS
- **poku + happy-dom**: 154.3 MB peak RSS
- **poku + jsdom**: 157.1 MB peak RSS
- **jest + jsdom**: 203.4 MB peak RSS

### Consistency (lower stdev = more predictable)

- **vitest + jsdom**: σ = 0.017s
- **vitest + happy-dom**: σ = 0.021s
- **jest + jsdom**: σ = 0.050s
- **poku + jsdom**: σ = 0.060s
- **poku + happy-dom**: σ = 0.085s
- **poku + jsdom**: σ = 0.008s
- **poku + happy-dom**: σ = 0.033s
- **vitest + happy-dom**: σ = 0.047s
- **jest + jsdom**: σ = 0.056s
- **vitest + jsdom**: σ = 0.057s

## Key findings

- **Fastest**: vitest + happy-dom — 0.838s mean
- **Slowest**: poku + happy-dom — 1.073s mean
- **Speed spread**: 28% difference between fastest and slowest
- **Fastest**: poku + jsdom — 0.444s mean
- **Slowest**: vitest + jsdom — 1.193s mean
- **Speed spread**: 169% difference between fastest and slowest

### Interpretation

Expand All @@ -100,6 +100,7 @@ processes with minimal bootstrap — means cold-start overhead is proportional t
files, not to the framework's own initialization.

**jest** carries the heaviest startup cost due to:

1. Babel transformation of every TSX file on first run (no persistent cache in this benchmark)
2. 'jest-worker' process pool initialisation
3. JSDOM environment setup per test file
Expand Down
6 changes: 4 additions & 2 deletions benchmark/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions benchmark/poku.config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { defineConfig } from 'poku';
import { reactTestingPlugin } from 'poku-react-testing/plugin';

const configuredDom = process.env.POKU_REACT_TEST_DOM;
const dom = configuredDom === 'jsdom' ? 'jsdom' : 'happy-dom';
const dom = process.env.POKU_REACT_TEST_DOM;
if (!dom) {
throw new Error('POKU_REACT_TEST_DOM environment variable is not set');
}

export default defineConfig({
plugins: [reactTestingPlugin({ dom })],
isolation: 'none',
});
74 changes: 37 additions & 37 deletions benchmark/results.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"timestamp": "2026-03-31T21:00:50.386Z",
"timestamp": "2026-04-01T12:41:50.774Z",
"system": {
"nodeVersion": "v22.5.1",
"platform": "darwin 25.4.0",
Expand All @@ -14,68 +14,68 @@
"results": [
{
"label": "poku + happy-dom",
"mean": 1073.1924668,
"min": 995.5031250000002,
"max": 1229.6369170000003,
"stddev": 84.66710558647982,
"meanRss": 171232460.8,
"meanUserCpu": 4396,
"meanSysCpu": 1584,
"mean": 559.9537916000002,
"min": 515.060708,
"max": 599.9880840000001,
"stddev": 33.06234198220535,
"meanRss": 161808384,
"meanUserCpu": 672,
"meanSysCpu": 202,
"runs": 7,
"validRuns": 7,
"failures": 0
},
{
"label": "poku + jsdom",
"mean": 1060.1384749999997,
"min": 1007.1474579999995,
"max": 1176.5342500000006,
"stddev": 60.012456221527664,
"meanRss": 171294720,
"meanUserCpu": 3228,
"meanSysCpu": 1440,
"mean": 443.6319584000001,
"min": 428.5047089999998,
"max": 450.59829100000024,
"stddev": 7.9857833050707905,
"meanRss": 164767334.4,
"meanUserCpu": 432,
"meanSysCpu": 92,
"runs": 7,
"validRuns": 7,
"failures": 0
},
{
"label": "jest + jsdom",
"mean": 858.7310334000001,
"min": 778.734042,
"max": 929.1150420000013,
"stddev": 50.38267849622563,
"meanRss": 216186880,
"meanUserCpu": 778,
"meanSysCpu": 176,
"mean": 1040.1169332000002,
"min": 975.1540420000001,
"max": 1134.9154159999998,
"stddev": 56.06532298235639,
"meanRss": 213300019.2,
"meanUserCpu": 936,
"meanSysCpu": 228,
"runs": 7,
"validRuns": 7,
"failures": 0
},
{
"label": "vitest + jsdom",
"mean": 964.3196584000004,
"min": 949.5501660000009,
"max": 986.9945420000004,
"stddev": 16.60550682561403,
"meanRss": 155179417.6,
"meanUserCpu": 3336,
"meanSysCpu": 1102,
"mean": 1192.7835997999996,
"min": 1129.2755830000006,
"max": 1268.7202919999982,
"stddev": 56.83080807294834,
"meanRss": 159652249.6,
"meanUserCpu": 3798,
"meanSysCpu": 1380,
"runs": 7,
"validRuns": 7,
"failures": 0
},
{
"label": "vitest + happy-dom",
"mean": 837.8697498000001,
"min": 812.1916249999995,
"max": 864.1250409999993,
"stddev": 20.924101623413893,
"meanRss": 121916620.8,
"meanUserCpu": 2942,
"meanSysCpu": 1006,
"mean": 1041.3667920000007,
"min": 990.0950420000008,
"max": 1126.3293750000012,
"stddev": 47.26983715919258,
"meanRss": 122814464,
"meanUserCpu": 3346,
"meanSysCpu": 1156,
"runs": 7,
"validRuns": 7,
"failures": 0
}
]
}
}
4 changes: 2 additions & 2 deletions benchmark/tests/poku/concurrency.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const ResourceView = ({ resource }) => {
return <h2>{value}</h2>;
};

test('renders a resolved use() resource under Suspense', () => {
test('renders a resolved use() resource under Suspense', async () => {
const value = 'Loaded from use() resource';
const resolvedResource = {
status: 'fulfilled',
Expand All @@ -30,7 +30,7 @@ test('renders a resolved use() resource under Suspense', () => {
);
});

await test('runs urgent and transition update pipeline', async () => {
test('runs urgent and transition update pipeline', async () => {
const TransitionPipeline = () => {
const [urgentState, setUrgentState] = useState('idle');
const [deferredState, setDeferredState] = useState('idle');
Expand Down
2 changes: 1 addition & 1 deletion benchmark/tests/poku/context.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const ThemeLabel = () => {
return <p>Theme: {theme}</p>;
};

test('injects context values via wrapper', () => {
test('injects context values via wrapper', async () => {
const ThemeWrapper = ({ children }) => (
<ThemeContext.Provider value='dark'>{children}</ThemeContext.Provider>
);
Expand Down
2 changes: 1 addition & 1 deletion benchmark/tests/poku/counter.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const Counter = ({ initialCount = 0 }) => {
);
};

test('renders and updates a React component', () => {
test('renders and updates a React component', async () => {
render(<Counter initialCount={1} />);

assert.strictEqual(
Expand Down
4 changes: 2 additions & 2 deletions benchmark/tests/poku/hooks.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const HookHarness = () => {
);
};

test('tests custom hooks through a component harness', () => {
test('tests custom hooks through a component harness', async () => {
render(<HookHarness />);

assert.strictEqual(
Expand All @@ -46,7 +46,7 @@ test('tests custom hooks through a component harness', () => {
);
});

test('tests hook logic directly with renderHook', () => {
test('tests hook logic directly with renderHook', async () => {
const { result } = renderHook(({ initial }) => useToggle(initial), {
initialProps: { initial: true },
});
Expand Down
Loading
Loading