Skip to content

Commit 5309eb8

Browse files
authored
chore: refactor test suites (#36)
* test: Switch to uvu for Node/non-browser tests * test: Switch to wtr for browser tests * test: Remove leftover test file * chore: sort deps
1 parent fa83cd8 commit 5309eb8

10 files changed

+2814
-2439
lines changed

jsconfig.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
"moduleResolution": "NodeNext",
66
"noEmit": true,
77
"allowJs": true,
8-
"checkJs": true
8+
"checkJs": true,
9+
"jsx": "react",
10+
"jsxFactory": "h",
11+
"jsxFragmentFactory": "Fragment",
912
}
1013
}

package.json

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,27 +27,25 @@
2727
"README.md"
2828
],
2929
"scripts": {
30-
"test": "node --experimental-vm-modules node_modules/.bin/jest"
31-
},
32-
"jest": {
33-
"testEnvironment": "jsdom",
34-
"testEnvironmentOptions": {
35-
"customExportConditions": [
36-
"node",
37-
"node-addons"
38-
]
39-
}
30+
"test": "yarn test:node && yarn test:browser",
31+
"test:browser": "wtr test/*.test.js",
32+
"test:node": "uvu test/node"
4033
},
4134
"peerDependencies": {
4235
"preact": ">=10",
4336
"preact-render-to-string": ">=6.4.0"
4437
},
4538
"devDependencies": {
39+
"@types/mocha": "^10.0.7",
40+
"@types/sinon-chai": "^3.2.12",
41+
"@web/dev-server-esbuild": "^1.0.2",
42+
"@web/test-runner": "^0.18.3",
43+
"chai": "^5.1.1",
4644
"htm": "^3.1.1",
47-
"jest": "^29.7.0",
48-
"jest-environment-jsdom": "^29.7.0",
49-
"jsdom": "^22.1.0",
5045
"preact": "10.15.1",
51-
"preact-render-to-string": "^6.4.0"
46+
"preact-render-to-string": "^6.4.0",
47+
"sinon": "^18.0.0",
48+
"sinon-chai": "^4.0.0",
49+
"uvu": "^0.5.6"
5250
}
5351
}

test/location-stub.test.js

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

test/match.test.js

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

test/node/location-stub.test.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { test } from 'uvu';
2+
import * as assert from 'uvu/assert';
3+
4+
import { locationStub } from '../../src/prerender.js';
5+
6+
test.before.each(() => {
7+
if (globalThis.location) {
8+
delete globalThis.location;
9+
}
10+
});
11+
12+
test('Contains all Location instance properties', () => {
13+
locationStub('/foo/bar?baz=qux#quux');
14+
15+
[
16+
// 'ancestorOrigins', // Not supported by FireFox and sees little use, but we could add an empty val if it's needed
17+
'hash',
18+
'host',
19+
'hostname',
20+
'href',
21+
'origin',
22+
'pathname',
23+
'port',
24+
'protocol',
25+
'search',
26+
].forEach(key => {
27+
assert.ok(Object.hasOwn(globalThis.location, key), `missing: ${key}`);
28+
});
29+
});
30+
31+
// Do we need to support `assign`, `reload`, and/or `replace`?
32+
test('Support bound methods', () => {
33+
locationStub('/foo/bar?baz=qux#quux');
34+
35+
assert.equal(globalThis.location.toString(), 'http://localhost/foo/bar?baz=qux#quux')
36+
});
37+
38+
test.run();

test/node/prerender.test.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { test } from 'uvu';
2+
import * as assert from 'uvu/assert';
3+
import { html } from 'htm/preact';
4+
5+
import { default as prerender } from '../../src/prerender.js';
6+
7+
test('extracts links', async () => {
8+
const App = () => html`
9+
<div>
10+
<a href="/foo">foo</a>
11+
<a href="/bar" target="_blank">bar</a>
12+
<a href="/baz" target="_self">baz</a>
13+
</div>
14+
`;
15+
16+
17+
const { links } = await prerender(html`<${App} />`);
18+
assert.equal(links.size, 2, `incorrect number of links found: ${links.size}`);
19+
assert.ok(links.has('/foo'), `missing: /foo`);
20+
assert.ok(links.has('/baz'), `missing: /baz`);
21+
});
22+
23+
test('appends iso data script', async () => {
24+
const { html: h } = await prerender(html`<div />`);
25+
// Empty for now, but used for hydration vs render detection
26+
assert.match(h, /<script type="isodata"><\/script>/, 'missing iso data script tag');
27+
});
28+
29+
test.run();

test/node/router-match.test.js

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { test } from 'uvu';
2+
import * as assert from 'uvu/assert';
3+
4+
// @ts-expect-error - no types, not meant for public use
5+
import { exec } from '../../src/router.js';
6+
7+
function execPath(path, pattern, opts) {
8+
return exec(path, pattern, { path, query: {}, params: {}, ...(opts || {}) });
9+
}
10+
11+
test('Base route', () => {
12+
const accurateResult = execPath('/', '/');
13+
assert.equal(accurateResult, { path: '/', params: {}, query: {} });
14+
15+
const inaccurateResult = execPath('/user/1', '/');
16+
assert.equal(inaccurateResult, undefined);
17+
});
18+
19+
test('Param route', () => {
20+
const accurateResult = execPath('/user/2', '/user/:id');
21+
assert.equal(accurateResult, { path: '/user/2', params: { id: '2' }, id: '2', query: {} });
22+
23+
const inaccurateResult = execPath('/', '/user/:id');
24+
assert.equal(inaccurateResult, undefined);
25+
});
26+
27+
test('Param rest segment', () => {
28+
const accurateResult = execPath('/user/foo', '/user/*');
29+
assert.equal(accurateResult, { path: '/user/foo', params: {}, query: {}, rest: '/foo' });
30+
31+
const inaccurateResult = execPath('/', '/user/:id/*');
32+
assert.equal(inaccurateResult, undefined);
33+
});
34+
35+
test('Param route with rest segment', () => {
36+
const accurateResult = execPath('/user/2/foo', '/user/:id/*');
37+
assert.equal(accurateResult, { path: '/user/2/foo', params: { id: '2' }, id: '2', query: {}, rest: '/foo' });
38+
39+
const accurateResult2 = execPath('/user/2/foo/bar/bob', '/user/:id/*');
40+
assert.equal(accurateResult2, {
41+
path: '/user/2/foo/bar/bob',
42+
params: { id: '2' },
43+
id: '2',
44+
query: {},
45+
rest: '/foo/bar/bob'
46+
});
47+
48+
const inaccurateResult = execPath('/', '/user/:id/*');
49+
assert.equal(inaccurateResult, undefined);
50+
});
51+
52+
test('Optional param route', () => {
53+
const accurateResult = execPath('/user', '/user/:id?');
54+
assert.equal(accurateResult, { path: '/user', params: { id: undefined }, id: undefined, query: {} });
55+
56+
const inaccurateResult = execPath('/', '/user/:id?');
57+
assert.equal(inaccurateResult, undefined);
58+
});
59+
60+
test('Optional rest param route "/:x*"', () => {
61+
const accurateResult = execPath('/user', '/user/:id?');
62+
assert.equal(accurateResult, { path: '/user', params: { id: undefined }, id: undefined, query: {} });
63+
64+
const inaccurateResult = execPath('/', '/user/:id?');
65+
assert.equal(inaccurateResult, undefined);
66+
});
67+
68+
test('Rest param route "/:x+"', () => {
69+
const matchedResult = execPath('/user/foo', '/user/:id+');
70+
assert.equal(matchedResult, { path: '/user/foo', params: { id: 'foo' }, id: 'foo', query: {} });
71+
72+
const matchedResultWithSlash = execPath('/user/foo/bar', '/user/:id+');
73+
assert.equal(matchedResultWithSlash, {
74+
path: '/user/foo/bar',
75+
params: { id: 'foo/bar' },
76+
id: 'foo/bar',
77+
query: {}
78+
});
79+
80+
const emptyResult = execPath('/user', '/user/:id+');
81+
assert.equal(emptyResult, undefined);
82+
83+
const mismatchedResult = execPath('/', '/user/:id+');
84+
assert.equal(mismatchedResult, undefined);
85+
});
86+
87+
test('Handles leading/trailing slashes', () => {
88+
const result = execPath('/about-late/_SEGMENT1_/_SEGMENT2_/', '/about-late/:seg1/:seg2/');
89+
assert.equal(result, {
90+
path: '/about-late/_SEGMENT1_/_SEGMENT2_/',
91+
params: {
92+
seg1: '_SEGMENT1_',
93+
seg2: '_SEGMENT2_'
94+
},
95+
seg1: '_SEGMENT1_',
96+
seg2: '_SEGMENT2_',
97+
query: {}
98+
});
99+
});
100+
101+
test('should not overwrite existing properties', () => {
102+
const result = execPath('/foo/bar', '/:path/:query', { path: '/custom-path' });
103+
assert.equal(result, {
104+
params: { path: 'foo', query: 'bar' },
105+
path: '/custom-path',
106+
query: {}
107+
});
108+
});
109+
110+
test.run();

0 commit comments

Comments
 (0)