0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-16 21:46:22 -05:00

Use node:test and node:assert/strict (#9649)

This commit is contained in:
Bjorn Lu 2024-01-12 15:53:00 +08:00 committed by GitHub
parent d02a3c48a3
commit 71db79e62a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 119 additions and 55 deletions

View file

@ -88,13 +88,25 @@ DEBUG=vite:[name] astro dev # debug specific process, e.g. "vite:deps" or "vit
# run this in the top-level project root to run all tests
pnpm run test
# run only a few tests in the `astro` package, great for working on a single feature
# (example - `pnpm run test:match "cli"` runs `cli.test.js`)
# (example - `pnpm run test:match "cli"` runs tests with "cli" in the name)
pnpm run test:match "$STRING_MATCH"
# run tests on another package
# (example - `pnpm --filter @astrojs/rss run test` runs `packages/astro-rss/test/rss.test.js`)
pnpm --filter $STRING_MATCH run test
```
Most tests use [`mocha`](https://mochajs.org) as the test runner. We're slowly migrating to use [`node:test`](https://nodejs.org/api/test.html) instead through the custom [`astro-scripts test`](./scripts/cmd/test.js) command. For packages that use `node:test`, you can run these commands in their directories:
```shell
# run all of the package's tests
pnpm run test
# run only a few tests in the package
# (example - `pnpm run test -m "cli"` runs tests with "cli" in the name)
pnpm run test -m "$STRING_MATCH"
# run a single test file, you can use `node --test` directly
node --test ./test/foo.test.js
```
#### E2E tests
Certain features, like HMR and client hydration, need end-to-end tests to verify functionality in the dev server. [Playwright](https://playwright.dev/) is used to test against the dev server.

View file

@ -20,7 +20,7 @@
"build": "astro-scripts build \"src/index.ts\" --bundle && tsc",
"build:ci": "astro-scripts build \"src/index.ts\" --bundle",
"dev": "astro-scripts dev \"src/**/*.ts\"",
"test": "mocha --exit --timeout 20000 --parallel"
"test": "astro-scripts test \"test/**/*.test.js\""
},
"files": [
"dist",
@ -39,8 +39,6 @@
"@types/which-pm-runs": "^1.0.0",
"arg": "^5.0.2",
"astro-scripts": "workspace:*",
"chai": "^4.3.7",
"mocha": "^10.2.0",
"strip-ansi": "^7.1.0"
},
"engines": {

View file

@ -1,19 +1,20 @@
import { expect } from 'chai';
import { describe, it } from 'node:test';
import * as assert from 'node:assert/strict';
import { getContext } from '../dist/index.js';
describe('context', () => {
it('no arguments', async () => {
const ctx = await getContext([]);
expect(ctx.version).to.eq('latest');
expect(ctx.dryRun).to.be.undefined;
assert.equal(ctx.version, 'latest');
assert.equal(ctx.dryRun, undefined);
});
it('tag', async () => {
const ctx = await getContext(['beta']);
expect(ctx.version).to.eq('beta');
expect(ctx.dryRun).to.be.undefined;
assert.equal(ctx.version, 'beta');
assert.equal(ctx.dryRun, undefined);
});
it('dry run', async () => {
const ctx = await getContext(['--dry-run']);
expect(ctx.dryRun).to.eq(true);
assert.equal(ctx.dryRun, true);
});
});

View file

@ -1,4 +1,5 @@
import { expect } from 'chai';
import { describe, it } from 'node:test';
import * as assert from 'node:assert/strict';
import { setup } from './utils.js';
import { install } from '../dist/index.js';
@ -23,7 +24,7 @@ describe('install', () => {
],
};
await install(context);
expect(fixture.hasMessage('◼ astro is up to date on v1.0.0')).to.be.true;
assert.equal(fixture.hasMessage('◼ astro is up to date on v1.0.0'), true);
});
it('patch', async () => {
@ -38,7 +39,7 @@ describe('install', () => {
],
};
await install(context);
expect(fixture.hasMessage('● astro can be updated to v1.0.1')).to.be.true;
assert.equal(fixture.hasMessage('● astro can be updated to v1.0.1'), true);
});
it('minor', async () => {
@ -53,7 +54,7 @@ describe('install', () => {
],
};
await install(context);
expect(fixture.hasMessage('● astro can be updated to v1.2.0')).to.be.true;
assert.equal(fixture.hasMessage('● astro can be updated to v1.2.0'), true);
});
it('major (reject)', async () => {
@ -80,10 +81,10 @@ describe('install', () => {
],
};
await install(context);
expect(fixture.hasMessage('▲ astro can be updated to v2.0.0')).to.be.true;
expect(prompted).to.be.true;
expect(exitCode).to.eq(0);
expect(fixture.hasMessage('check Be sure to follow the CHANGELOG.')).to.be.false;
assert.equal(fixture.hasMessage('▲ astro can be updated to v2.0.0'), true);
assert.equal(prompted, true);
assert.equal(exitCode, 0);
assert.equal(fixture.hasMessage('check Be sure to follow the CHANGELOG.'), false);
});
it('major (accept)', async () => {
@ -110,10 +111,10 @@ describe('install', () => {
],
};
await install(context);
expect(fixture.hasMessage('▲ astro can be updated to v2.0.0')).to.be.true;
expect(prompted).to.be.true;
expect(exitCode).to.be.undefined;
expect(fixture.hasMessage('check Be sure to follow the CHANGELOG.')).to.be.true;
assert.equal(fixture.hasMessage('▲ astro can be updated to v2.0.0'), true);
assert.equal(prompted, true);
assert.equal(exitCode, undefined);
assert.equal(fixture.hasMessage('check Be sure to follow the CHANGELOG.'), true);
});
it('multiple major', async () => {
@ -148,14 +149,14 @@ describe('install', () => {
],
};
await install(context);
expect(fixture.hasMessage('▲ a can be updated to v2.0.0')).to.be.true;
expect(fixture.hasMessage('▲ b can be updated to v7.0.0')).to.be.true;
expect(prompted).to.be.true;
expect(exitCode).to.be.undefined;
assert.equal(fixture.hasMessage('▲ a can be updated to v2.0.0'), true);
assert.equal(fixture.hasMessage('▲ b can be updated to v7.0.0'), true);
assert.equal(prompted, true);
assert.equal(exitCode, undefined);
const [changelog, a, b] = fixture.messages().slice(-5);
expect(changelog).to.match(/^check/);
expect(a).to.match(/^a/);
expect(b).to.match(/^b/);
assert.match(changelog, /^check/);
assert.match(a, /^a/);
assert.match(b, /^b/);
});
it('current patch minor major', async () => {
@ -197,15 +198,15 @@ describe('install', () => {
],
};
await install(context);
expect(fixture.hasMessage('◼ current is up to date on v1.0.0')).to.be.true;
expect(fixture.hasMessage('● patch can be updated to v1.0.1')).to.be.true;
expect(fixture.hasMessage('● minor can be updated to v1.2.0')).to.be.true;
expect(fixture.hasMessage('▲ major can be updated to v3.0.0')).to.be.true;
expect(prompted).to.be.true;
expect(exitCode).to.be.undefined;
expect(fixture.hasMessage('check Be sure to follow the CHANGELOG.')).to.be.true;
assert.equal(fixture.hasMessage('◼ current is up to date on v1.0.0'), true);
assert.equal(fixture.hasMessage('● patch can be updated to v1.0.1'), true);
assert.equal(fixture.hasMessage('● minor can be updated to v1.2.0'), true);
assert.equal(fixture.hasMessage('▲ major can be updated to v3.0.0'), true);
assert.equal(prompted, true);
assert.equal(exitCode, undefined);
assert.equal(fixture.hasMessage('check Be sure to follow the CHANGELOG.'), true);
const [changelog, major] = fixture.messages().slice(-4);
expect(changelog).to.match(/^check/);
expect(major).to.match(/^major/);
assert.match(changelog, /^check/);
assert.match(major, /^major/)
});
});

View file

@ -1,3 +1,4 @@
import { before, beforeEach } from 'node:test';
import { setStdout } from '../dist/index.js';
import stripAnsi from 'strip-ansi';

View file

@ -1,4 +1,5 @@
import { expect } from 'chai';
import { describe, it, beforeEach } from 'node:test';
import * as assert from 'node:assert/strict';
import { collectPackageInfo } from '../dist/index.js';
describe('collectPackageInfo', () => {
@ -16,61 +17,61 @@ describe('collectPackageInfo', () => {
it('detects astro', async () => {
collectPackageInfo(context, { astro: '1.0.0' }, {});
expect(context.packages).deep.equal([
assert.deepEqual(context.packages, [
{ name: 'astro', currentVersion: '1.0.0', targetVersion: 'latest' },
]);
});
it('detects @astrojs', async () => {
collectPackageInfo(context, { '@astrojs/preact': '1.0.0' }, {});
expect(context.packages).deep.equal([
assert.deepEqual(context.packages, [
{ name: '@astrojs/preact', currentVersion: '1.0.0', targetVersion: 'latest' },
]);
});
it('supports ^ prefixes', async () => {
collectPackageInfo(context, { astro: '^1.0.0' }, {});
expect(context.packages).deep.equal([
assert.deepEqual(context.packages, [
{ name: 'astro', currentVersion: '^1.0.0', targetVersion: 'latest' },
]);
});
it('supports ~ prefixes', async () => {
collectPackageInfo(context, { astro: '~1.0.0' }, {});
expect(context.packages).deep.equal([
assert.deepEqual(context.packages, [
{ name: 'astro', currentVersion: '~1.0.0', targetVersion: 'latest' },
]);
});
it('supports prereleases', async () => {
collectPackageInfo(context, { astro: '1.0.0-beta.0' }, {});
expect(context.packages).deep.equal([
assert.deepEqual(context.packages, [
{ name: 'astro', currentVersion: '1.0.0-beta.0', targetVersion: 'latest' },
]);
});
it('ignores self', async () => {
collectPackageInfo(context, { '@astrojs/upgrade': '0.0.1' }, {});
expect(context.packages).deep.equal([]);
assert.deepEqual(context.packages, []);
});
it('ignores linked packages', async () => {
collectPackageInfo(context, { '@astrojs/preact': 'link:../packages/preact' }, {});
expect(context.packages).deep.equal([]);
assert.deepEqual(context.packages, []);
});
it('ignores workspace packages', async () => {
collectPackageInfo(context, { '@astrojs/preact': 'workspace:*' }, {});
expect(context.packages).deep.equal([]);
assert.deepEqual(context.packages, []);
});
it('ignores github packages', async () => {
collectPackageInfo(context, { '@astrojs/preact': 'github:withastro/astro' }, {});
expect(context.packages).deep.equal([]);
assert.deepEqual(context.packages, []);
});
it('ignores tag', async () => {
collectPackageInfo(context, { '@astrojs/preact': 'beta' }, {});
expect(context.packages).deep.equal([]);
assert.deepEqual(context.packages, []);
});
});

View file

@ -5148,12 +5148,6 @@ importers:
astro-scripts:
specifier: workspace:*
version: link:../../scripts
chai:
specifier: ^4.3.7
version: 4.3.10
mocha:
specifier: ^10.2.0
version: 10.2.0
strip-ansi:
specifier: ^7.1.0
version: 7.1.0

View file

@ -0,0 +1,51 @@
import { run } from 'node:test';
import { spec } from 'node:test/reporters';
import arg from 'arg';
import glob from 'tiny-glob';
const isCI = !!process.env.CI;
const defaultTimeout = isCI ? 30000 : 20000;
export default async function test() {
const args = arg({
'--match': String, // aka --test-name-pattern: https://nodejs.org/api/test.html#filtering-tests-by-name
'--only': Boolean, // aka --test-only: https://nodejs.org/api/test.html#only-tests
'--parallel': Boolean, // aka --test-concurrency: https://nodejs.org/api/test.html#test-runner-execution-model
'--watch': Boolean, // experimental: https://nodejs.org/api/test.html#watch-mode
'--timeout': Number, // Test timeout in milliseconds (default: 30000ms)
'--setup': String, // Test setup file
// Aliases
'-m': '--match',
'-o': '--only',
'-p': '--parallel',
'-w': '--watch',
'-t': '--timeout',
'-s': '--setup',
});
const pattern = args._[1];
if (!pattern) throw new Error('Missing test glob pattern');
const files = await glob(pattern, { filesOnly: true, absolute: true });
// For some reason, the `only` option does not work and we need to explicitly set the CLI flag instead.
// Node.js requires opt-in to run .only tests :(
// https://nodejs.org/api/test.html#only-tests
if (args['--only']) {
process.env.NODE_OPTIONS ??= '';
process.env.NODE_OPTIONS += ' --test-only';
}
// https://nodejs.org/api/test.html#runoptions
run({
files,
testNamePatterns: args['--match'],
concurrency: args['--parallel'],
only: args['--only'],
setup: args['--setup'],
watch: args['--watch'],
timeout: args['--timeout'] ?? defaultTimeout, // Node.js defaults to Infinity, so set better fallback
})
.pipe(new spec())
.pipe(process.stdout);
}

View file

@ -18,6 +18,11 @@ export default async function run() {
await prebuild(...args);
break;
}
case 'test': {
const { default: test } = await import('./cmd/test.js');
await test(...args);
break;
}
}
}