fix(core): load Mocha test files as ES Modules (fixes internal-API imports from tests, #5636)#5640
fix(core): load Mocha test files as ES Modules (fixes internal-API imports from tests, #5636)#5640DavertMik wants to merge 1 commit into
Conversation
…s resolve to the live instance
Test files were loaded with synchronous require(), which under tsx/cjs
created a second CommonJS copy of lib/* modules. A test's
`import { config } from "codeceptjs"` then resolved to a disconnected copy
whose module-level singletons were never populated (#5636).
Load test files through `await import()` instead — the same way the
container already loads helpers — so the whole run shares one ES module
graph and plain imports are honest. New lib/mocha/loadTests.js mirrors
Mocha's loadFiles (lazyLoadFiles + per-file pre-require/require/post-require)
to preserve teardown hooks, the gherkin .feature path, and the
dup/missing-Feature validation.
All synchronous mocha.loadFiles() sites converted: codecept.run(), rerun,
workers (parent grouping + worker threads), dry-run, and check.
TypeScript: tsx/cjs is a require hook and can no longer transpile test
files loaded via import(). requireModules() auto-maps tsx/cjs -> tsx/esm
with a deprecation notice; tsx/esm needs "type": "module" in package.json
(init now writes it, and an ERR_REQUIRE_CYCLE_MODULE guard points users to it).
BREAKING CHANGE: the programmatic Workers grouping API
(createGroupsOfTests, createGroupsOfSuites, addTestFiles, splitTestsByGroups)
is now async. TypeScript projects must set "type": "module" in package.json.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@mirao can you check this implementation? this solves the root cause of the issue (with some breaking changes) |
|
I see. You replaced In my production CodeceptJS 4.x project now I have setup both I can test it with a beta version if you release it. With the beta I could remove the patch I did because of the internal API issues locally and test the beta without them. |
|
@mirao I would prefer the most simple and consistent fix here. Seems like migrating everything to ESM is the right path here. Instead of maintaining 2 loader types better to stick to one. Sure. I will release beta with this one! I think such a big change should load as 4.1.0 not less Here is beta version to test: https://github.com/codeceptjs/CodeceptJS/releases/tag/4.1.0-beta.1-esm-mocha |
OK. In my production projects where I tested it, I needed to add The beta works for me and solves the issues #5632 and #5635 . The original issue #5641 is solved as well. Note that still I run all my productions tests (web + mobile, all in TypeScript). They all pass and no more issue found (when comparing with 4.0.x). So from my point of view, the version 4.1 works well (or at least it's not worse than 4.0 😄 ) |
Problem
A test that imports the internal API —
import { config } from "codeceptjs"— gets a value that looks empty/disconnected from the running session (#5636).Root cause: Mocha loads test files with synchronous
require(). Undertsx/cjsthat creates a second CommonJS copy of everylib/*module, each with its own module-level singletons (config,container,recorder,event,store). The test imports the second copy, whose singletons were never populated by the runner. Helpers don't have this problem because the container loads them withawait import()(ESM).Fix
Load test files the same way helpers are loaded — through
await import()— so the whole run shares one ES module graph and the plainimportresolves to the live instance. No bridge, noglobalThisindirection.New
lib/mocha/loadTests.jsmirrors Mocha's ownloadFiles(lazyLoadFiles(true)somocha.run()won't sync-require, then per file emitpre-require→await import()→require/post-require). That preserves:mocha/ui.jsonpost-require),.featurepath,Featurevalidation.All synchronous
mocha.loadFiles()sites converted:codecept.run(),rerun, workers (parent grouping + worker threads),dry-run,check. The factory'sloadFilesoverride is removed.TypeScript loader migration
tsx/cjsis arequirehook and can't transpile files loaded viaimport(). So:requireModules()auto-mapstsx/cjs→tsx/esmwith a deprecation notice (existing configs keep working),tsx/esmrequires"type": "module"inpackage.json—initnow writes it, and anERR_REQUIRE_CYCLE_MODULEguard tells users to add it,typescript,configuration,installation,parallel) updated.createGroupsOfTests,createGroupsOfSuites,addTestFiles,splitTestsByGroupsreturn Promises (you cannot load ES modules synchronously). Callers mustawait. Docs + unit tests updated."type": "module"inpackage.json. Projects ontsx/cjswithout it will hitERR_REQUIRE_CYCLE_MODULEuntil they add it (the error message says so). Therequirevalue itself is auto-migrated.Verification
import { config } from "codeceptjs"and assertsconfig.get('name')equals the running config — proves the second-copy bug is gone.tsx/esm+"type":"module"fixture loads end-to-end with all four hooks firing.Alternative to #5636 that keeps the abstraction (no
realm.js/globalThissingletons).🤖 Generated with Claude Code