Skip to content
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
2 changes: 2 additions & 0 deletions tegg/core/vitest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"exports": {
".": "./src/index.ts",
"./runner": "./src/runner.ts",
"./setup": "./src/setup.ts",
"./shared": "./src/shared.ts",
"./package.json": "./package.json"
},
Expand All @@ -38,6 +39,7 @@
"exports": {
".": "./dist/index.js",
"./runner": "./dist/runner.js",
"./setup": "./dist/setup.js",
"./shared": "./dist/shared.js",
"./package.json": "./package.json"
}
Expand Down
44 changes: 44 additions & 0 deletions tegg/core/vitest/src/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import fs from 'node:fs';
import { createRequire } from 'node:module';
import path from 'node:path';
import { pathToFileURL } from 'node:url';

const nodeRequire = createRequire(import.meta.url);
const esmDirectoryCache = new Map<string, boolean>();

function isEsmFile(filePath: string): boolean {
if (filePath.endsWith('.mjs')) return true;
if (filePath.endsWith('.cjs')) return false;

let directory = path.dirname(filePath);
const visited: string[] = [];
while (directory !== path.dirname(directory)) {
const cached = esmDirectoryCache.get(directory);
if (cached !== undefined) {
for (const item of visited) esmDirectoryCache.set(item, cached);
return cached;
}

visited.push(directory);
const packageFile = path.join(directory, 'package.json');
if (fs.existsSync(packageFile)) {
let isEsm = false;
try {
isEsm = JSON.parse(fs.readFileSync(packageFile, 'utf8')).type === 'module';
} catch {
// Invalid package metadata follows Node's CommonJS-compatible fallback.
}
for (const item of visited) esmDirectoryCache.set(item, isEsm);
return isEsm;
}
directory = path.dirname(directory);
}
return false;
}

// This setup file runs inside the test ViteVM. CJS files must use Node's
// require cache, while ESM files stay in Vitest's transformed import graph.
globalThis.__EGG_MODULE_IMPORTER__ = async (filePath: string) => {
if (isEsmFile(filePath)) return import(pathToFileURL(filePath).href);
return nodeRequire(filePath);
};
5 changes: 5 additions & 0 deletions tegg/core/vitest/test/fixture_app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ describe('fixture demo app', () => {
});

it('injects ctx and getEggObject', async () => {
const loadedModule = (await globalThis.__EGG_MODULE_IMPORTER__?.(
path.join(__dirname, 'fixtures/apps/demo-app/modules/demo-module/HelloService.ts'),
)) as { HelloService: typeof HelloService };
assert.strictEqual(loadedModule.HelloService, HelloService);
Comment thread
elrrrrrrr marked this conversation as resolved.

const ctx = app.ctxStorage.getStore();
assert(ctx);
const helloService = (await ctx.getEggObject(HelloService)) as any;
Expand Down
2 changes: 1 addition & 1 deletion tegg/core/vitest/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default defineConfig({
environment: 'node',
include: ['test/**/*.test.ts'],
// Register TS loader (ts-node) before tests so Egg can load .ts via Module._extensions.
setupFiles: ['test/setup.ts'],
setupFiles: ['./src/setup.ts', 'test/setup.ts'],
// Custom runner for tegg context injection via enterWith + held beginModuleScope.
runner: './src/runner.ts',
},
Expand Down
6 changes: 6 additions & 0 deletions tools/egg-bin/src/commands/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,12 @@ export default class Test<T extends typeof Test> extends BaseCommand<T> {
}
if (!runner) {
debug('skip @eggjs/tegg-vitest/runner: self-test fixture or not resolvable');
} else {
const teggSetup = importResolve('@eggjs/tegg-vitest/setup', {
paths: [flags.base, import.meta.dirname],
});
setupFiles.unshift(teggSetup);
debug('auto add @eggjs/tegg-vitest/setup: %o', teggSetup);
}
Comment thread
elrrrrrrr marked this conversation as resolved.

return {
Expand Down
Loading