Skip to content

Commit

Permalink
test: api (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
privatenumber authored May 1, 2024
1 parent 16e87a5 commit 99ba136
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 8 deletions.
21 changes: 13 additions & 8 deletions src/cjs/api/require.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,30 @@ import { register } from './global-require-patch.js';
import { resolveFilename } from './module-resolve-filename.js';

const getRequestContext = (
filepath: string | URL,
id: string,
fromFile: string | URL,
) => {
if (!fromFile) {
throw new Error('The current file path (__filename or import.meta.url) must be provided in the second argument of tsx.require()');
}

if (
(typeof filepath === 'string' && filepath.startsWith('file://'))
|| filepath instanceof URL
(typeof fromFile === 'string' && fromFile.startsWith('file://'))
|| fromFile instanceof URL
) {
filepath = fileURLToPath(filepath);
fromFile = fileURLToPath(fromFile);
}
return path.dirname(filepath);

return path.resolve(path.dirname(fromFile), id);
};

const tsxRequire = (
id: string,
fromFile: string | URL,
) => {
const contextId = getRequestContext(id, fromFile);
const unregister = register();
try {
const contextId = path.resolve(getRequestContext(fromFile), id);

// eslint-disable-next-line import-x/no-dynamic-require, n/global-require
return require(contextId);
} finally {
Expand All @@ -35,7 +40,7 @@ const resolve = (
fromFile: string | URL,
options?: { paths?: string[] | undefined },
) => {
const contextId = path.resolve(getRequestContext(fromFile), id);
const contextId = getRequestContext(id, fromFile);
return resolveFilename(contextId, module, false, options);
};
resolve.paths = require.resolve.paths;
Expand Down
1 change: 1 addition & 0 deletions tests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { nodeVersions } from './utils/node-versions';
const node = await createNode(nodeVersion);
await describe(`Node ${node.version}`, async ({ runTestSuite }) => {
await runTestSuite(import('./specs/cli'), node);
await runTestSuite(import('./specs/api'), node);
await runTestSuite(import('./specs/watch'), node);
await runTestSuite(import('./specs/loaders'), node);
await runTestSuite(
Expand Down
131 changes: 131 additions & 0 deletions tests/specs/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import path from 'path';
import { execaNode } from 'execa';
import { testSuite, expect } from 'manten';
import { createFixture } from 'fs-fixture';
import { tsxEsmPath, cjsApiPath, type NodeApis } from '../utils/tsx.js';

const tsFiles = {
'file.ts': `
import { foo } from './foo'
export const message = foo as string
`,
'foo.ts': `
import { bar } from './bar.js'
export const foo = \`foo \${bar}\` as string
`,
'bar.ts': 'export const bar = "bar" as string',
};

export default testSuite(({ describe }, node: NodeApis) => {
describe('API', ({ describe }) => {
describe('CommonJS', ({ test }) => {
test('register / unregister', async ({ onTestFinish }) => {
const fixture = await createFixture({
'register.cjs': `
const { register } = require(${JSON.stringify(cjsApiPath)});
try {
require('./file');
} catch {
console.log('Fails as expected');
}
const unregister = register();
const loaded = require('./file');
console.log(loaded.message);
// Remove from cache
const loadedPath = require.resolve('./file');
delete require.cache[loadedPath];
unregister();
try {
require('./file');
} catch {
console.log('Unregistered');
}
`,
...tsFiles,
});
onTestFinish(async () => await fixture.rm());

const { stdout } = await execaNode(path.join(fixture.path, 'register.cjs'), [], {
nodePath: node.path,
nodeOptions: [],
});

expect(stdout).toBe('Fails as expected\nfoo bar\nUnregistered');
});

test('tsx.require()', async ({ onTestFinish }) => {
const fixture = await createFixture({
'require.cjs': `
const tsx = require(${JSON.stringify(cjsApiPath)});
try {
require('./file');
} catch {
console.log('Fails as expected');
}
const loaded = tsx.require('./file', __filename);
console.log(loaded.message);
// Remove from cache
const loadedPath = tsx.require.resolve('./file', __filename);
delete require.cache[loadedPath];
try {
require('./file');
} catch {
console.log('Unpolluted global require');
}
`,
...tsFiles,
});
onTestFinish(async () => await fixture.rm());

const { stdout } = await execaNode(path.join(fixture.path, 'require.cjs'), [], {
nodePath: node.path,
nodeOptions: [],
});

expect(stdout).toBe('Fails as expected\nfoo bar\nUnpolluted global require');
});
});

describe('Module', ({ test }) => {
if (node.supports.moduleRegister) {
test('module.register', async ({ onTestFinish }) => {
const fixture = await createFixture({
'package.json': JSON.stringify({ type: 'module' }),
'module-register.mjs': `
import { register } from 'node:module';
await import('./file.ts').catch((error) => {
console.log('Fails as expected');
});
register(${JSON.stringify(tsxEsmPath)}, {
parentURL: import.meta.url,
data: true,
})
const { message } = await import('./file.ts?nocache')
console.log(message)
`,
...tsFiles,
});
onTestFinish(async () => await fixture.rm());

const { stdout } = await execaNode(path.join(fixture.path, 'module-register.mjs'), [], {
nodePath: node.path,
nodeOptions: [],
});

expect(stdout).toBe('Fails as expected\nfoo bar');
});
}
});
});
});
2 changes: 2 additions & 0 deletions tests/utils/tsx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ type Options = {
};

export const tsxPath = fileURLToPath(new URL('../../dist/cli.mjs', import.meta.url).toString());
export const cjsApiPath = fileURLToPath(new URL('../../dist/cjs/api/index.cjs', import.meta.url).toString());
export const tsxEsmPath = new URL('../../dist/esm/index.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();
Expand Down

0 comments on commit 99ba136

Please sign in to comment.