Skip to content

Commit 481706d

Browse files
authored
tests: inital framework (#27)
* tests: inital framework * Update index.spec.js * Update package.json * Update test.yml * Update index.spec.js * chore: add basic cases * test: update for CI * chore: pkg update * chore: increase timeout * chore: change to the actual directory * chore: force add 30s * ci: fix timeout * ci: test one * ci: debug * switch to node:test * test: add another example with tailwind and tests * chore: switch to `@matteo.collina/snap` for now * fix: null check viteEnv for builds
1 parent cada9db commit 481706d

File tree

33 files changed

+553
-38
lines changed

33 files changed

+553
-38
lines changed

.github/workflows/test.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@ jobs:
1414

1515
- uses: actions/setup-node@v3
1616
with:
17-
node-version: '18.x'
17+
node-version: '20'
1818
corepack-enable: true
1919
registry-url: 'https://registry.npmjs.org'
2020

2121
- name: Deps
2222
run: |
23+
npm i -g corepack@latest
2324
corepack enable
2425
pnpm i --frozen-lockfile
2526
2627
- name: Test
27-
run: pnpm -r test
28+
run: pnpm test:ci
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"\n <!doctype html>\n <html lang=\"\">\n <head>\n <script type=\"module\" src=\"/@vite/client\"></script>\n\n <meta charset=\"UTF-8\" />\n \n <title></title>\n\n \n \n \n </head>\n <body>\n <div id=\"app\"><h1 class=\"text-red-500\">Hello World</h1></div>\n <script type='module' src=\"/virtual:adex:client\"></script></body>\n </html>\n "
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"\n <!doctype html>\n <html lang=\"\">\n <head>\n <script type=\"module\" src=\"/@vite/client\"></script>\n\n <meta charset=\"UTF-8\" />\n \n <title></title>\n\n \n \n \n </head>\n <body>\n <div id=\"app\"><h2>About</h2></div>\n <script type='module' src=\"/virtual:adex:client\"></script></body>\n </html>\n "
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"\n <!doctype html>\n <html lang=\"\">\n <head>\n <script type=\"module\" src=\"/@vite/client\"></script>\n\n <meta charset=\"UTF-8\" />\n \n <title></title>\n\n \n \n \n </head>\n <body>\n <div id=\"app\"><h1>Hello World</h1></div>\n <script type='module' src=\"/virtual:adex:client\"></script></body>\n </html>\n "
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"\n <!doctype html>\n <html lang=\"\">\n <head>\n <script type=\"module\" src=\"/@vite/client\"></script>\n\n <meta charset=\"UTF-8\" />\n \n <title></title>\n\n \n \n \n </head>\n <body>\n <div id=\"app\"><h2>About</h2></div>\n <script type='module' src=\"/virtual:adex:client\"></script></body>\n </html>\n "
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"import { createHotContext as __vite__createHotContext } from \"/@vite/client\";import.meta.hot = __vite__createHotContext(\"/@id/__x00__virtual:adex:global.css\");import { updateStyle as __vite__updateStyle, removeStyle as __vite__removeStyle } from \"/@vite/client\"\nconst __vite__id = \"\\u0000virtual:adex:global.css\"\nconst __vite__css = \"\"\n__vite__updateStyle(__vite__id, __vite__css)\nimport.meta.hot.accept()\nimport.meta.hot.prune(() => __vite__removeStyle(__vite__id))"

adex/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@
5959
"runtime"
6060
],
6161
"scripts": {
62-
"next": "bumpp"
62+
"next": "bumpp",
63+
"test": "glob -c 'node --test' tests/**/*.spec.js"
6364
},
6465
"dependencies": {
6566
"@barelyhuman/tiny-use": "^0.0.2",
@@ -77,10 +78,13 @@
7778
"unifont": "^0.0.2"
7879
},
7980
"devDependencies": {
81+
"@matteo.collina/snap": "^0.3.0",
8082
"@preact/preset-vite": "^2.8.2",
8183
"@types/node": "^20.14.10",
8284
"adex-adapter-node": "^0.0.17",
8385
"autoprefixer": "^10.4.19",
86+
"glob": "^11.0.1",
87+
"kolorist": "^1.8.0",
8488
"tailwindcss": "^3.4.4",
8589
"vite": "^5.3.1"
8690
},

adex/runtime/client.js

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,6 @@ import 'virtual:adex:global.css'
1313
// @ts-expect-error injected by vite
1414
import { routes } from '~routes'
1515

16-
const withComponents = routes.map(d => {
17-
return {
18-
...d,
19-
component: lazy(d.module),
20-
}
21-
})
22-
2316
function ComponentWrapper({ url = '' }) {
2417
return h(
2518
LocationProvider,
@@ -31,8 +24,8 @@ function ComponentWrapper({ url = '' }) {
3124
h(
3225
Router,
3326
{},
34-
withComponents.map(d =>
35-
h(Route, { path: d.routePath, component: d.component })
27+
routes.map(d =>
28+
h(Route, { path: d.routePath, component: lazy(d.module) })
3629
)
3730
)
3831
)
@@ -46,6 +39,7 @@ export const App = ({ url = '' }) => {
4639
async function hydrate() {
4740
preactHydrate(h(ComponentWrapper, {}), document.getElementById('app'))
4841
}
42+
4943
if (typeof window !== 'undefined') {
5044
hydrate()
5145
}

adex/runtime/handler.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { CONSTANTS, emitToHooked } from 'adex/hook'
22
import { prepareRequest, prepareResponse } from 'adex/http'
33
import { toStatic } from 'adex/ssr'
4-
import { renderToString } from 'adex/utils/isomorphic'
4+
import { renderToStringAsync } from 'adex/utils/isomorphic'
55
import { h } from 'preact'
66

77
// @ts-expect-error injected by vite
@@ -60,9 +60,7 @@ export async function handler(req, res) {
6060
// @ts-expect-error
6161
global.location = new URL(req.url, 'http://localhost')
6262

63-
const rendered = await renderToString(
64-
h(App, { url: [baseURL, search].filter(Boolean).join('?') })
65-
)
63+
const rendered = await renderToStringAsync(h(App, { url: req.url }), {})
6664

6765
const htmlString = HTMLTemplate({
6866
metas,
@@ -73,7 +71,7 @@ export async function handler(req, res) {
7371
routeParams: Buffer.from(JSON.stringify(routeParams), 'utf8').toString(
7472
'base64'
7573
),
76-
body: rendered.html,
74+
body: rendered,
7775
})
7876
const modifiableContext = {
7977
req: req,

adex/src/head.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export type {
1+
export {
22
useHead,
33
useLang,
44
useLink,

adex/src/utils/isomorphic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export { parse as pathToRegex } from 'regexparam'
2-
export { prerender as renderToString } from 'preact-iso'
2+
export { renderToStringAsync } from 'preact-render-to-string'

adex/src/vite.js

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,71 @@ export function adex({
6161
'virtual:adex:handler',
6262
readFileSync(join(__dirname, '../runtime/handler.js'), 'utf8')
6363
),
64+
createVirtualModule(
65+
'virtual:adex:server',
66+
`import { createServer } from '${adapterMap[adapter]}'
67+
import { dirname, join } from 'node:path'
68+
import { fileURLToPath } from 'node:url'
69+
import { existsSync, readFileSync } from 'node:fs'
70+
import { env } from 'adex/env'
71+
72+
import 'virtual:adex:font.css'
73+
import 'virtual:adex:global.css'
74+
75+
const __dirname = dirname(fileURLToPath(import.meta.url))
76+
77+
const PORT = parseInt(env.get('PORT', '3000'), 10)
78+
const HOST = env.get('HOST', 'localhost')
79+
80+
const paths = {
81+
assets: join(__dirname, './assets'),
82+
islands: join(__dirname, './islands'),
83+
client: join(__dirname, '../client'),
84+
}
85+
86+
function getServerManifest() {
87+
const manifestPath = join(__dirname, 'manifest.json')
88+
if (existsSync(manifestPath)) {
89+
const manifestFile = readFileSync(manifestPath, 'utf8')
90+
return parseManifest(manifestFile)
91+
}
92+
return {}
93+
}
94+
95+
function getClientManifest() {
96+
const manifestPath = join(__dirname, '../client/manifest.json')
97+
if (existsSync(manifestPath)) {
98+
const manifestFile = readFileSync(manifestPath, 'utf8')
99+
return parseManifest(manifestFile)
100+
}
101+
return {}
102+
}
103+
104+
function parseManifest(manifestString) {
105+
try {
106+
const manifestJSON = JSON.parse(manifestString)
107+
return manifestJSON
108+
} catch (err) {
109+
return {}
110+
}
111+
}
112+
113+
const server = createServer({
114+
port: PORT,
115+
host: HOST,
116+
adex:{
117+
manifests:{server:getServerManifest(),client:getClientManifest()},
118+
paths,
119+
}
120+
})
121+
122+
if ('run' in server) {
123+
server.run()
124+
}
125+
126+
export default server.fetch
127+
`
128+
),
64129
addFontsPlugin(fonts),
65130
adexDevServer({ islands }),
66131
adexBuildPrep({ islands }),
@@ -176,7 +241,7 @@ function adexIslandsBuilder() {
176241
// if being imported by the client, don't send
177242
// back the transformed server code, send the
178243
// original component
179-
if (!viteEnv.ssr) return
244+
if (!viteEnv?.ssr) return
180245

181246
const islands = findIslands(readSourceFile(id), {
182247
isFunctionIsland: node =>
@@ -655,7 +720,7 @@ function adexGuards() {
655720

656721
// ignore usage of `process.env` in `adex/env`
657722
const envLoadId = await this.resolve('adex/env')
658-
if (id === envLoadId.id) return
723+
if (id === envLoadId?.id) return
659724

660725
if (code.includes('process.env')) {
661726
this.error(
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"compilerOptions":{
3+
"jsx":"react-jsx",
4+
"jsxImportSource": "preact"
5+
}
6+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "minimal-tailwind",
3+
"type": "module",
4+
"dependencies": {
5+
"@preact/preset-vite": "catalog:",
6+
"adex": "workspace:*",
7+
"preact": "catalog:"
8+
},
9+
"devDependencies": {
10+
"autoprefixer": "^10.4.20",
11+
"tailwindcss": "^3",
12+
"vite": "^5.4.8"
13+
}
14+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
plugins: {
3+
tailwindcss: {},
4+
autoprefixer: {},
5+
},
6+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function AboutPage() {
2+
return <h2>About</h2>
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function Page() {
2+
return <h1 class="text-red-500">Hello World</h1>
3+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/** @type {import('tailwindcss').Config} */
2+
export default {
3+
content: ['./src/pages/**/*.{tsx,jsx}'],
4+
theme: {
5+
extend: {},
6+
},
7+
plugins: [],
8+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { defineConfig } from 'vite'
2+
import { adex } from "adex"
3+
import preact from "@preact/preset-vite"
4+
5+
export default defineConfig({
6+
plugins: [
7+
adex({
8+
islands: false,
9+
ssr: true,
10+
}),
11+
preact(),
12+
],
13+
})
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"compilerOptions":{
3+
"jsx":"react-jsx",
4+
"jsxImportSource": "preact"
5+
}
6+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "minimal",
3+
"type": "module",
4+
"dependencies": {
5+
"adex": "workspace:*",
6+
"preact": "catalog:",
7+
"@preact/preset-vite": "catalog:"
8+
},
9+
10+
"devDependencies": {
11+
"vite": "^5.4.8"
12+
}
13+
14+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function AboutPage() {
2+
return <h2>About</h2>
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function Page() {
2+
return <h1>Hello World</h1>
3+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { defineConfig } from 'vite'
2+
import { adex } from "adex"
3+
import preact from "@preact/preset-vite"
4+
5+
export default defineConfig({
6+
plugins: [
7+
adex({
8+
islands: false,
9+
ssr: true,
10+
}),
11+
preact(),
12+
],
13+
})

adex/tests/minimal-tailwind.spec.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import Snap from '@matteo.collina/snap'
2+
import { after, before, describe, it } from 'node:test'
3+
import assert, { deepEqual } from 'node:assert'
4+
5+
import { devServerURL, launchDemoDevServer } from './utils.js'
6+
const snap = Snap(import.meta.url)
7+
8+
describe('devMode ssr minimal with styles', async () => {
9+
let devServerProc
10+
before(async () => {
11+
devServerProc = await launchDemoDevServer('tests/fixtures/minimal-tailwind')
12+
})
13+
after(async () => {
14+
devServerProc.kill()
15+
})
16+
17+
await it('gives a non-static ssr response', async ctx => {
18+
const response = await fetch(devServerURL).then(d => d.text())
19+
const snapshot = await snap(response)
20+
deepEqual(response, snapshot)
21+
})
22+
23+
await it('gives a static SSR response', async ctx => {
24+
const response2 = await fetch(new URL('/about', devServerURL)).then(d =>
25+
d.text()
26+
)
27+
const snapshot = await snap(response2)
28+
deepEqual(response2, snapshot)
29+
})
30+
31+
await it('has styles', async ctx => {
32+
const response = await fetch(
33+
new URL('/virtual:adex:global.css', devServerURL)
34+
).then(d => d.text())
35+
assert.ok(response.includes('.text-red-500'))
36+
})
37+
})

0 commit comments

Comments
 (0)