Skip to content

Commit

Permalink
Use node:test and node:assert/strict (#9649)
Browse files Browse the repository at this point in the history
  • Loading branch information
bluwy authored and ematipico committed Jan 12, 2024
1 parent 9bb779d commit 9b1f251
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 55 deletions.
14 changes: 13 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 1 addition & 3 deletions packages/upgrade/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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": {
Expand Down
13 changes: 7 additions & 6 deletions packages/upgrade/test/context.test.js
Original file line number Diff line number Diff line change
@@ -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);
});
});
57 changes: 29 additions & 28 deletions packages/upgrade/test/install.test.js
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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 () => {
Expand All @@ -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 () => {
Expand All @@ -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 () => {
Expand All @@ -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 () => {
Expand All @@ -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 () => {
Expand Down Expand Up @@ -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 () => {
Expand Down Expand Up @@ -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/)
});
});
1 change: 1 addition & 0 deletions packages/upgrade/test/utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { before, beforeEach } from 'node:test';
import { setStdout } from '../dist/index.js';
import stripAnsi from 'strip-ansi';

Expand Down
23 changes: 12 additions & 11 deletions packages/upgrade/test/verify.test.js
Original file line number Diff line number Diff line change
@@ -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', () => {
Expand All @@ -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, []);
});
});
6 changes: 0 additions & 6 deletions pnpm-lock.yaml

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

51 changes: 51 additions & 0 deletions scripts/cmd/test.js
Original file line number Diff line number Diff line change
@@ -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);
}
5 changes: 5 additions & 0 deletions scripts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}

Expand Down

0 comments on commit 9b1f251

Please sign in to comment.