|
| 1 | +import {spawnSync} from 'child_process'; |
1 | 2 | import {resolve} from 'path'; |
2 | 3 | import type {MongoMemoryReplSet, MongoMemoryServer} from 'mongodb-memory-server'; |
3 | 4 | import type {Config} from './types'; |
4 | 5 |
|
5 | | -const configFile = process.env.MONGO_MEMORY_SERVER_FILE || 'jest-mongodb-config.js'; |
6 | | - |
7 | 6 | type MongoMemoryReplSetOpts = NonNullable<ConstructorParameters<typeof MongoMemoryReplSet>[0]>; |
8 | 7 | type MongoMemoryServerOpts = NonNullable<ConstructorParameters<typeof MongoMemoryServer>[0]>; |
9 | 8 |
|
10 | 9 | export function isMongoMemoryReplSetOptions( |
11 | 10 | options?: MongoMemoryReplSetOpts | MongoMemoryServerOpts |
12 | 11 | ): options is MongoMemoryReplSetOpts { |
13 | | - return Boolean((options as MongoMemoryReplSetOpts).replSet); |
| 12 | + return Boolean((options as MongoMemoryReplSetOpts | undefined)?.replSet); |
14 | 13 | } |
15 | 14 |
|
16 | | -export function getMongodbMemoryOptions( |
17 | | - cwd: string |
18 | | -): MongoMemoryReplSetOpts | MongoMemoryServerOpts | undefined { |
| 15 | +function getConfigFile() { |
| 16 | + return process.env.MONGO_MEMORY_SERVER_FILE || 'jest-mongodb-config.js'; |
| 17 | +} |
| 18 | + |
| 19 | +const configCache = new Map<string, Config | null>(); |
| 20 | + |
| 21 | +function importConfig(configPath: string): Config | undefined { |
19 | 22 | try { |
20 | | - // eslint-disable-next-line @typescript-eslint/no-require-imports |
21 | | - const {mongodbMemoryServerOptions}: Config = require(resolve(cwd, configFile)); |
| 23 | + // Node 22.12+ can let `require` load ESM by default. When Jest runs in CJS mode |
| 24 | + // and the config is `.mjs`, spawn a one-off Node process to import it as ESM |
| 25 | + // and return the plain JSON payload. |
| 26 | + const {status, stdout} = spawnSync( |
| 27 | + process.execPath, |
| 28 | + [ |
| 29 | + '--input-type=module', |
| 30 | + '--eval', |
| 31 | + [ |
| 32 | + 'import {pathToFileURL} from "node:url";', |
| 33 | + `const mod = await import(pathToFileURL(${JSON.stringify(configPath)}).href);`, |
| 34 | + 'const payload = mod.default ?? mod;', |
| 35 | + 'console.log(JSON.stringify(payload));', |
| 36 | + ].join('\n'), |
| 37 | + ], |
| 38 | + {encoding: 'utf8'} |
| 39 | + ); |
22 | 40 |
|
23 | | - return mongodbMemoryServerOptions; |
| 41 | + if (status === 0 && stdout.trim()) { |
| 42 | + return JSON.parse(stdout) as Config; |
| 43 | + } |
24 | 44 | } catch { |
25 | | - return { |
26 | | - binary: { |
27 | | - checkMD5: false, |
28 | | - }, |
29 | | - instance: {}, |
30 | | - }; |
| 45 | + // ignore and fall through to undefined |
31 | 46 | } |
| 47 | + |
| 48 | + return undefined; |
32 | 49 | } |
33 | 50 |
|
34 | | -export function getMongoURLEnvName(cwd: string) { |
35 | | - try { |
36 | | - // eslint-disable-next-line @typescript-eslint/no-require-imports |
37 | | - const {mongoURLEnvName}: Config = require(resolve(cwd, configFile)); |
| 51 | +function loadConfig(cwd?: string): Config | undefined { |
| 52 | + const baseDir = cwd || process.cwd(); |
38 | 53 |
|
39 | | - return mongoURLEnvName || 'MONGO_URL'; |
40 | | - } catch { |
41 | | - return 'MONGO_URL'; |
| 54 | + if (configCache.has(baseDir)) { |
| 55 | + return configCache.get(baseDir) ?? undefined; |
42 | 56 | } |
43 | | -} |
44 | 57 |
|
45 | | -export function shouldUseSharedDBForAllJestWorkers(cwd: string) { |
| 58 | + const configPath = resolve(baseDir, getConfigFile()); |
| 59 | + |
46 | 60 | try { |
47 | 61 | // eslint-disable-next-line @typescript-eslint/no-require-imports |
48 | | - const {useSharedDBForAllJestWorkers}: Config = require(resolve(cwd, configFile)); |
| 62 | + const loadedConfig = require(configPath) as Config | {default?: Config}; |
49 | 63 |
|
50 | | - if (typeof useSharedDBForAllJestWorkers === 'undefined') { |
51 | | - return true; |
| 64 | + if (loadedConfig && typeof (loadedConfig as {default?: Config}).default !== 'undefined') { |
| 65 | + const config = (loadedConfig as {default?: Config}).default; |
| 66 | + configCache.set(baseDir, config ?? null); |
| 67 | + |
| 68 | + return config; |
52 | 69 | } |
53 | 70 |
|
54 | | - return useSharedDBForAllJestWorkers; |
| 71 | + const config = loadedConfig as Config; |
| 72 | + configCache.set(baseDir, config ?? null); |
| 73 | + |
| 74 | + return config; |
55 | 75 | } catch { |
| 76 | + const importedConfig = importConfig(configPath); |
| 77 | + configCache.set(baseDir, importedConfig ?? null); |
| 78 | + |
| 79 | + return importedConfig; |
| 80 | + } |
| 81 | +} |
| 82 | + |
| 83 | +export function getMongodbMemoryOptions( |
| 84 | + cwd?: string |
| 85 | +): MongoMemoryReplSetOpts | MongoMemoryServerOpts | undefined { |
| 86 | + const config = loadConfig(cwd); |
| 87 | + |
| 88 | + if (config?.mongodbMemoryServerOptions) { |
| 89 | + return config.mongodbMemoryServerOptions; |
| 90 | + } |
| 91 | + |
| 92 | + return { |
| 93 | + binary: { |
| 94 | + checkMD5: false, |
| 95 | + }, |
| 96 | + instance: {}, |
| 97 | + }; |
| 98 | +} |
| 99 | + |
| 100 | +export function getMongoURLEnvName(cwd?: string) { |
| 101 | + const config = loadConfig(cwd); |
| 102 | + |
| 103 | + return config?.mongoURLEnvName || 'MONGO_URL'; |
| 104 | +} |
| 105 | + |
| 106 | +export function shouldUseSharedDBForAllJestWorkers(cwd?: string) { |
| 107 | + const config = loadConfig(cwd); |
| 108 | + |
| 109 | + if (typeof config?.useSharedDBForAllJestWorkers === 'undefined') { |
56 | 110 | return true; |
57 | 111 | } |
| 112 | + |
| 113 | + return config.useSharedDBForAllJestWorkers; |
58 | 114 | } |
0 commit comments