Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Windows CI via node+jest (as alternative to bun) #155

Merged
merged 1 commit into from
Jan 16, 2024
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
26 changes: 25 additions & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,35 @@ on:

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 jest-extended esbuild@^0.19.11
# https://jestjs.io/docs/ecmascript-modules
node --experimental-vm-modules node_modules/jest/bin/jest --runInBand --coverage
if: ${{ matrix.env.tool == 'node+jest' }}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@
"engines": {
"bun": ">=1",
"node": ">=18"
},
"jest": {
"setupFilesAfterEnv": ["jest-extended/all"]
}
}
15 changes: 12 additions & 3 deletions packages/nuejs/test/render.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
"import-meta-resolve": "^4.0.0",
"js-yaml": "^4.1.0",
"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
Expand Up @@ -2,6 +2,8 @@
// Router for single-page applications
import { onclick, loadPage, setSelected } from './page-router.js'

const is_browser = typeof window == 'object'

const fns = []

async function fire(path) {
Expand All @@ -13,7 +15,7 @@ async function fire(path) {
}

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

Expand Down
13 changes: 6 additions & 7 deletions packages/nuekit/src/browser/page-router.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,6 @@ export async function loadPage(path) {
}


// back button
addEventListener('popstate', e => {
const { path, is_spa } = e.state || {}
if (path) loadPage(path)
})


// setup linking
export function onclick(root, fn) {

Expand Down Expand Up @@ -103,6 +96,12 @@ if (is_browser) {

// initial selected
setSelected(location.pathname)

// back button
addEventListener('popstate', e => {
const { path } = e.state || {}
if (path) loadPage(path)
})
}


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 @@ -104,6 +105,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 @@ -127,11 +131,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,6 +1,6 @@

import { join, extname, basename, sep, parse as parsePath } from 'node:path'
import { log, getParts, getAppDir, getDirs, colors } from './util.js'
import { log, getParts, getAppDir, getDirs, colors, getPosixPath } from './util.js'
import { parse as parseNue } from 'nuejs-core/index.js'
import { nuemark } from 'nuemark/index.js'
import { promises as fs } from 'node:fs'
Expand Down Expand Up @@ -125,7 +125,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'


export function log(msg, extra='') {
Expand Down Expand Up @@ -29,6 +29,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 @@ -37,21 +38,27 @@ export function getParts(path) {


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

// getDirs('a/b/c') --> ['a', 'a/b', 'a/b/c']
export function getDirs(dir) {
if (!dir) return []
dir = normalize(dir)
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('\\', '/')
}
19 changes: 19 additions & 0 deletions packages/nuekit/test/kit-init.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
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.rm(root, { recursive: true, force: true })
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)
})
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)}`
}
}
8 changes: 6 additions & 2 deletions packages/nuekit/test/misc.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ 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 })

const lcss = await findModule('lightningcss')
const stylus = await findModule('stylus')

Expand Down Expand Up @@ -85,8 +89,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')
})

24 changes: 11 additions & 13 deletions packages/nuekit/test/nuekit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,19 @@ 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'

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

// helper function for creating files to the root directory
Expand Down Expand Up @@ -124,7 +130,7 @@ test('content collection', async () => {
expect(coll[0].url).toBe('/blog/first.html')
expect(coll[0].title).toBe('First')
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 @@ -174,20 +180,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 Down
7 changes: 7 additions & 0 deletions pnpm-lock.yaml

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