Skip to content

Commit

Permalink
Fix Windows CI via node+jest (as alternative to bun)
Browse files Browse the repository at this point in the history
  • Loading branch information
fritx committed Jan 11, 2024
1 parent e8a1f9b commit 0413ead
Show file tree
Hide file tree
Showing 15 changed files with 134 additions and 55 deletions.
26 changes: 25 additions & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,35 @@ name: Test
on: [push, pull_request, workflow_dispatch]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
env:
- { os: 'ubuntu-22.04', tool: 'bun' }
- { os: 'macos-12', tool: 'bun' }
# Windows support for bun install is not implemented yet
# - { os: 'windows-2022', tool: 'bun' }
# - { os: 'ubuntu-22.04', tool: 'node+jest' }
# - { os: 'macos-12', tool: 'node+jest' }
- { os: 'windows-2022', tool: 'node+jest' }
runs-on: ${{ matrix.env.os }}
steps:
- uses: actions/checkout@v3

# Testing `bun`
- uses: oven-sh/setup-bun@v1
if: ${{ matrix.env.tool == 'bun' }}
- run: |
bun -v
bun install
bun install --no-save esbuild@^0.19.11
bun test --coverage
if: ${{ matrix.env.tool == 'bun' }}
# Testing `node+jest`
- run: |
node -v && npm -v
npm install
npm install --no-save jest esbuild@^0.19.11
# https://jestjs.io/docs/ecmascript-modules
node --experimental-vm-modules node_modules/jest/bin/jest --coverage
if: ${{ matrix.env.tool == 'node+jest' }}
Binary file modified bun.lockb
Binary file not shown.
19 changes: 14 additions & 5 deletions packages/nuejs/test/render.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ const IF_SIBLING = `
test('If sibling', () => {
const els = [{ label: 'First'}]
const html = render(IF_SIBLING, { els })
expect(html).toInclude('First')
expect(html).toContain('First')
})


Expand All @@ -207,7 +207,7 @@ test(':for error', () => {
render('<div>\n<h1>Hey</h1>\n<b :for="foo bar"></b></div>')

} catch (e) {
expect(e.lineText).toInclude(':for="foo bar"')
expect(e.lineText).toContain(':for="foo bar"')
expect(e.column).toBeGreaterThan(1)
expect(e.line).toBe(3)
}
Expand All @@ -218,9 +218,18 @@ test('{ expr } error', () => {
render('<div>\n<b>Hey { foo[0] } { title }</b></div>')

} catch (e) {
expect(e.subexpr).toBe('foo[0]')
expect(e.line).toBe(2)
expect(e.column).toBe(9)
// Getting different results from different environments
// bun: TypeError: undefined is not an object (evaluating '_.foo[0]')
if (process.isBun) {
expect(e.subexpr).toBe('foo[0]')
expect(e.line).toBe(2)
expect(e.column).toBe(9)
} else {
// node: TypeError: Cannot read properties of undefined (reading '0')
expect(e.subexpr).toBe('0')
expect(e.line).toBe(2)
expect(e.column).toBe(13)
}
}
})

1 change: 1 addition & 0 deletions packages/nuekit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
},
"dependencies": {
"diff-dom": "^5.0.6",
"es-main": "^1.3.0",
"js-yaml": "^4.1.0",
"marked": "^9.1.6",
"nuejs-core": "^0.3.0"
Expand Down
4 changes: 3 additions & 1 deletion packages/nuekit/src/browser/app-router.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@

import { onclick, loadPage, setSelected } from './page-router.js'

const is_browser = typeof window == 'object'

const fns = []

async function fire(path) {
Expand All @@ -12,7 +14,7 @@ async function fire(path) {
}

// clear existing routes
addEventListener('before:route', () => {
is_browser && addEventListener('before:route', () => {
fns.splice(0, fns.length)
})

Expand Down
2 changes: 1 addition & 1 deletion packages/nuekit/src/browser/page-router.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export async function loadPage(path) {


// back button
addEventListener('popstate', e => {
is_browser && addEventListener('popstate', e => {
const { path, is_spa } = e.state || {}
if (path) loadPage(path)
})
Expand Down
2 changes: 1 addition & 1 deletion packages/nuekit/src/builder.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

import { join, extname } from 'node:path'
import { join, normalize } from 'node:path'

export async function getBuilder(is_esbuild) {
try {
Expand Down
13 changes: 5 additions & 8 deletions packages/nuekit/src/cli.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env bun

import { log, colors } from './util.js'
import esMain from 'es-main'

// [-npe] --> [-n, -p, -e]
export function expandArgs(args) {
Expand Down Expand Up @@ -103,6 +104,9 @@ async function runCommand(args) {
else if (cmd == 'stats') await nue.stats()
}

// Only run main when called as real CLI
if (esMain(import.meta)) {

const args = getArgs(process.argv)

// help
Expand All @@ -126,11 +130,4 @@ if (args.help) {
}
}









}
5 changes: 3 additions & 2 deletions packages/nuekit/src/site.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

import { log, parseMarkdown, getParts, getAppDir, getDirs, colors } from './util.js'
import { log, parseMarkdown, getParts, getAppDir, getDirs, colors, getPosixPath } from './util.js'
import { join, extname, basename, sep, parse as parsePath } from 'node:path'
import { parse as parseNue } from 'nuejs-core/index.js'
import { promises as fs } from 'node:fs'
Expand Down Expand Up @@ -124,7 +124,8 @@ export async function createSite(args) {

}).forEach(path => {
const ext = extname(path)
arr.push('/' + join(dir, to_ext ? path.replace(ext, '.' + to_ext) : path))
const subpath = to_ext ? path.replace(ext, '.' + to_ext) : path
arr.push('/' + getPosixPath(join(dir, subpath)))
})

} catch (e) {
Expand Down
11 changes: 9 additions & 2 deletions packages/nuekit/src/util.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

/* misc stuff. think shame.css */
import { sep, parse } from 'node:path'
import { sep, parse, normalize } from 'node:path'
import { marked } from 'marked'
import yaml from 'js-yaml'

Expand Down Expand Up @@ -46,6 +46,7 @@ export const colors = getColorFunctions()
/* path parts */

export function getParts(path) {
path = normalize(path)
const { dir, name, base } = parse(path)
const appdir = getAppDir(path)
const url = getUrl(dir, name)
Expand All @@ -54,20 +55,26 @@ export function getParts(path) {


export function getAppDir(path) {
path = normalize(path)
const [ appdir ] = path.split(sep)
return appdir == path ? '.' : appdir
}

export function getDirs(dir) {
dir = normalize(dir)
if (!dir) return []
const els = dir.split(sep)
return els.map((el, i) => els.slice(0, i + 1).join(sep))
}

export function getUrl(dir, name) {
let url = dir.replace('\\', '/') + '/'
let url = getPosixPath(dir) + '/'
if (url[0] != '/') url = '/' + url
// if (name != 'index')
url += name + '.html'
return url
}

export function getPosixPath(path) {
return path.replaceAll('\\', '/')
}
16 changes: 16 additions & 0 deletions packages/nuekit/test/kit-init.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { promises as fs } from 'node:fs'
import { join } from 'node:path'
import { init } from '../src/init.js'

// temporary directory
const root = '_test'

// setup and teardown
beforeAll(async () => await fs.mkdir(root, { recursive: true }))
afterAll(async () => await fs.rm(root, { recursive: true, force: true }))

test('init dist/@nue dir', async () => {
await init({ dist: root, is_dev: true, esbuild: false })
const names = await fs.readdir(join(root, '@nue'))
expect(names.length).toBeGreaterThan(7)
})
35 changes: 15 additions & 20 deletions packages/nuekit/test/kit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import { createSite } from '../src/site.js'
import { createKit } from '../src/nuekit.js'
import { promises as fs } from 'node:fs'
import { join, parse } from 'node:path'
import { init } from '../src/init.js'

import { toMatchPath } from './match-path.js'

expect.extend({ toMatchPath })

// temporary directory
const root = '_test'
Expand Down Expand Up @@ -120,7 +123,7 @@ test('content collection', async () => {
expect(coll.length).toBe(2)
expect(coll[0].url).toBe('/blog/first.html')
expect(coll[1].title).toBe('Second')
expect(coll[1].dir).toBe('blog/nested')
expect(coll[1].dir).toMatchPath('blog/nested')
expect(coll[1].slug).toBe('hey.html')
})

Expand Down Expand Up @@ -159,20 +162,12 @@ test('getRequestPaths', async () => {
// SPA root
const path = 'admin/index.html'
await write(path)
expect(await site.getRequestPaths('/admin/')).toMatchObject({ path })
expect(await site.getRequestPaths('/admin/customers')).toMatchObject({ path })
expect((await site.getRequestPaths('/admin/')).path).toMatchPath(path)
expect((await site.getRequestPaths('/admin/customers')).path).toMatchPath(path)
expect(await site.getRequestPaths('/admin/readme.html')).toMatchObject({ path: '404.html' })
})



test('init dist/@nue dir', async () => {
await init({ dist: root, is_dev: true, esbuild: false })
const names = await fs.readdir(join(root, '@nue'))
expect(names.length).toBeGreaterThan(7)
})


test('inline CSS', async () => {
const kit = await getKit()
await write('inline/style.css', 'body { margin: 0 }')
Expand All @@ -183,7 +178,7 @@ test('inline CSS', async () => {

expect(data.inline_css[0]).toEqual({ path: "/inline/style.css", content: "body { margin: 0 }"})
const html = await kit.renderPage('inline/index.md', data)
expect(html).toInclude('<style href="/inline/style.css">body { margin: 0 }</style>')
expect(html).toContain('<style href="/inline/style.css">body { margin: 0 }</style>')
})


Expand All @@ -207,8 +202,8 @@ test('index.html', async() => {
await kit.gen('index.html')
const html = await readDist(kit.dist, 'index.html')

expect(html).toInclude('hotreload.js')
expect(html).toInclude('island="test"')
expect(html).toContain('hotreload.js')
expect(html).toContain('island="test"')
})

test('index.md', async() => {
Expand All @@ -217,9 +212,9 @@ test('index.md', async() => {
await kit.gen('index.md')
const html = await readDist(kit.dist, 'index.html')

expect(html).toInclude('hotreload.js')
expect(html).toInclude('<title>Hey</title>')
expect(html).toInclude('<h1>Hey</h1>')
expect(html).toContain('hotreload.js')
expect(html).toContain('<title>Hey</title>')
expect(html).toContain('<h1>Hey</h1>')
})


Expand All @@ -230,11 +225,11 @@ test('bundle', async() => {
// bun bundle
const opts = { path: `./${root}/b.ts`, outdir: root, bundle: true }
await buildJS(opts)
expect(await read('b.js')).toInclude('var foo = 30')
expect(await read('b.js')).toContain('var foo = 30')

// esbuild bundl3
await buildJS({ ...opts, esbuild: true })
expect(await read('b.js')).toInclude('var foo = 30')
expect(await read('b.js')).toContain('var foo = 30')
})

test('syntax errors', async() => {
Expand Down
26 changes: 26 additions & 0 deletions packages/nuekit/test/match-path.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { getPosixPath } from '../src/util.js'

// https://stackoverflow.com/questions/67325342/how-to-run-os-agnostic-jest-test-files-that-check-paths
// https://jestjs.io/docs/expect#expectextendmatchers
export function toMatchPath(actual, expected) {
const { printReceived, printExpected, matcherHint } = this.utils

const pass = getPosixPath(actual) == expected

return {
pass,
message: () => pass
? matcherHint('.not.toMatchPath') +
'\n\n' +
'Expected path not to match:\n' +
` ${printExpected(expected)}\n` +
'Received:\n' +
` ${printReceived(actual)}`
: matcherHint('.toMatchPath') +
'\n\n' +
'Expected path to match:\n' +
` ${printExpected(expected)}\n` +
'Received:\n' +
` ${printReceived(actual)}`
}
}
13 changes: 8 additions & 5 deletions packages/nuekit/test/misc.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { match } from '../src/browser/app-router.js'
import { renderHead } from '../src/layout.js'
import { getArgs } from '../src/cli.js'

import { toMatchPath } from './match-path.js'

expect.extend({ toMatchPath })


test('CLI args', () => {
Expand All @@ -16,9 +19,9 @@ test('CLI args', () => {

test('head', () => {
const head = renderHead({ charset: 'foo', title: 'Hey', preload_image: 'hey.png' })
expect(head).toInclude('meta charset="foo"')
expect(head).toInclude('<title>Hey</title>')
expect(head).toInclude('<link rel="preload" as="image" href="hey.png">')
expect(head).toContain('meta charset="foo"')
expect(head).toContain('<title>Hey</title>')
expect(head).toContain('<link rel="preload" as="image" href="hey.png">')
})


Expand All @@ -38,8 +41,8 @@ test('app router', async () => {
test('path parts', () => {
const parts = getParts('docs/glossary/semantic-css.md')
expect(parts.url).toBe('/docs/glossary/semantic-css.html')
expect(parts.dir).toBe('docs/glossary')
expect(parts.appdir).toBe('docs')
expect(parts.dir).toMatchPath('docs/glossary')
expect(parts.appdir).toMatchPath('docs')
expect(parts.slug).toBe('semantic-css.html')
})

Loading

0 comments on commit 0413ead

Please sign in to comment.