Skip to content

Commit

Permalink
test: loaders (#416)
Browse files Browse the repository at this point in the history
  • Loading branch information
privatenumber authored Nov 27, 2023
1 parent 5e26179 commit 30392f2
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 21 deletions.
1 change: 1 addition & 0 deletions tests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { nodeVersions } from './utils/node-versions';
await describe(`Node ${node.version}`, async ({ runTestSuite }) => {
await runTestSuite(import('./specs/cli'), node);
await runTestSuite(import('./specs/watch'), node);
await runTestSuite(import('./specs/loaders'), node);
await runTestSuite(
import('./specs/smoke'),
node,
Expand Down
22 changes: 5 additions & 17 deletions tests/specs/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,11 @@ import { tsxPath } from '../utils/tsx.js';
import { ptyShell, isWindows } from '../utils/pty-shell/index';
import { expectMatchInOrder } from '../utils/expect-match-in-order.js';
import type { NodeApis } from '../utils/tsx.js';
import { compareNodeVersion, type Version } from '../../src/utils/node-features.js';

const isProcessAlive = (pid: number) => {
try {
process.kill(pid, 0);
return true;
} catch {}
return false;
};
import { isProcessAlive } from '../utils/is-process-alive.js';

export default testSuite(({ describe }, node: NodeApis) => {
const { tsx } = node;

describe('CLI', ({ describe, test }) => {
describe('argv', async ({ describe, onFinish }) => {
const fixture = await createFixture({
Expand Down Expand Up @@ -109,12 +102,7 @@ export default testSuite(({ describe }, node: NodeApis) => {
});
});

const nodeVersion = node.version.split('.').map(Number) as Version;

// https://nodejs.org/docs/latest-v18.x/api/cli.html#--test
const cliTestFlag = compareNodeVersion([18, 1, 0], nodeVersion) >= 0;
const testRunnerGlob = compareNodeVersion([21, 0, 0], nodeVersion) >= 0;
if (cliTestFlag) {
if (node.supports.cliTestFlag) {
test('Node.js test runner', async ({ onTestFinish }) => {
const fixture = await createFixture({
'test.ts': `
Expand All @@ -132,15 +120,15 @@ export default testSuite(({ describe }, node: NodeApis) => {
[
'--test',
...(
testRunnerGlob
node.supports.testRunnerGlob
? []
: ['test.ts']
),
],
fixture.path,
);

if (testRunnerGlob) {
if (node.supports.testRunnerGlob) {
expect(tsxProcess.stdout).toMatch('some passing test\n');
} else {
expect(tsxProcess.stdout).toMatch('# pass 1\n');
Expand Down
90 changes: 90 additions & 0 deletions tests/specs/loaders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { testSuite, expect } from 'manten';
import { createFixture } from 'fs-fixture';
import type { NodeApis } from '../utils/tsx.js';

export default testSuite(({ describe }, node: NodeApis) => {
describe('Loaders', ({ describe }) => {
describe('Hooks', async ({ test }) => {
const fixture = await createFixture({
'package.json': JSON.stringify({ type: 'module' }),

'ts.ts': `
import fs from 'fs';
console.log(Boolean(fs) as unknown as string);
`,
'mts.mts': `
import fs from 'fs';
console.log(JSON.stringify([Boolean(fs) as unknown as string, import.meta.url]));
`,
});

test('.ts', async () => {
const tsxResult = await node.hook(['./ts.ts'], fixture.path);

expect(tsxResult.stdout).toBe('true');
if (node.supports.moduleRegister) {
expect(tsxResult.stderr).toBe('');
} else {
expect(tsxResult.stderr).toMatch('ExperimentalWarning: Custom ESM Loaders is an experimental feature');
}
expect(tsxResult.exitCode).toBe(0);
});

test('.mts', async () => {
const tsxResult = await node.hook(['./mts.mts'], fixture.path);

const [imported, importMetaUrl] = JSON.parse(tsxResult.stdout);
expect(imported).toBe(true);
expect(importMetaUrl.endsWith('/mts.mts')).toBeTruthy();

if (node.supports.moduleRegister) {
expect(tsxResult.stderr).toBe('');
} else {
expect(tsxResult.stderr).toMatch('ExperimentalWarning: Custom ESM Loaders is an experimental feature');
}
expect(tsxResult.exitCode).toBe(0);
});
});

describe('CJS patching', async ({ test }) => {
const fixture = await createFixture({
'package.json': JSON.stringify({ type: 'commonjs' }),

'ts.ts': `
import fs from 'fs';
console.log(Boolean(fs) as unknown as string);
`,
'cts.cts': `
import fs from 'fs';
console.log(Boolean(fs) as unknown as string);
`,
'mts.mts': `
import fs from 'fs';
console.log(Boolean(fs) as unknown as string, import.meta.url);
`,
});

test('.ts', async () => {
const tsxResult = await node.cjsPatched(['./ts.ts'], fixture.path);

expect(tsxResult.stdout).toBe('true');
expect(tsxResult.stderr).toBe('');
expect(tsxResult.exitCode).toBe(0);
});

// TODO: Investigate why this works -- it shouldnt
// test('should not be able to load .mjs', async () => {
// const tsxResult = await node.cjsPatched(['./mts.mts'], fixture.path);

// expect(tsxResult.stdout).toBe('true');
// expect(tsxResult.stderr).toBe('');
// expect(tsxResult.exitCode).toBe(0);
// });
});
});
});
7 changes: 7 additions & 0 deletions tests/utils/is-process-alive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const isProcessAlive = (pid: number) => {
try {
process.kill(pid, 0);
return true;
} catch {}
return false;
};
10 changes: 10 additions & 0 deletions tests/utils/node-features.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export type Version = [number, number, number];

export const compareNodeVersion = (
version: Version,
nodeVersion: Version,
) => (
nodeVersion[0] - version[0]
|| nodeVersion[1] - version[1]
|| nodeVersion[2] - version[2]
);
43 changes: 39 additions & 4 deletions tests/utils/tsx.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import path from 'path';
import { fileURLToPath } from 'url';
import { execaNode } from 'execa';
import getNode from 'get-node';
import { compareNodeVersion, type Version } from './node-features.js';

type Options = {
args: string[];
nodePath?: string;
cwd?: string;
};

const __dirname = fileURLToPath(import.meta.url);
export const tsxPath = path.join(__dirname, '../../../dist/cli.mjs');
export const tsxPath = fileURLToPath(new URL('../../dist/cli.mjs', import.meta.url).toString());

const cjsPatchPath = fileURLToPath(new URL('../../dist/cjs/index.cjs', import.meta.url).toString());
const hookPath = new URL('../../dist/esm/index.cjs', import.meta.url).toString();

export const tsx = (
options: Options,
Expand Down Expand Up @@ -38,11 +40,26 @@ export const createNode = async (
const node = await getNode(nodeVersion, {
progress: true,
});
console.log('Got node', Date.now() - startTime, node);
console.log(`Got node in ${Date.now() - startTime}ms`, node);

const versionParsed = node.version.split('.').map(Number) as Version;
const supports = {
moduleRegister: compareNodeVersion([20, 6, 0], versionParsed) >= 0,

// https://nodejs.org/docs/latest-v18.x/api/cli.html#--test
cliTestFlag: compareNodeVersion([18, 1, 0], versionParsed) >= 0,

testRunnerGlob: compareNodeVersion([21, 0, 0], versionParsed) >= 0,
};
const hookFlag = supports.moduleRegister ? '--import' : '--loader';

return {
version: node.version,

path: node.path,

supports,

tsx: (
args: string[],
cwd?: string,
Expand All @@ -61,6 +78,24 @@ export const createNode = async (
all: true,
},
),

cjsPatched: (
args: string[],
cwd?: string,
) => execaNode(args[0], args.slice(1), {
cwd,
nodePath: node.path,
nodeOptions: ['--require', cjsPatchPath],
}),

hook: (
args: string[],
cwd?: string,
) => execaNode(args[0], args.slice(1), {
cwd,
nodePath: node.path,
nodeOptions: [hookFlag, hookPath],
}),
};
};

Expand Down

0 comments on commit 30392f2

Please sign in to comment.