Skip to content

Commit e0f5bb8

Browse files
miraoclaude
andcommitted
test(effects): port effects-under-tsx/cjs coverage from #5634 (#5635)
#5635 fixes the dual-realm split at the source (shared recorder/container), which makes within/tryTo/hopeThat/retryTo work from a CJS-loaded test without the effects.js indirection PR #5634 added — i.e. #5635 supersedes #5634's mechanism. To avoid losing #5634's regression coverage, fold its effects assertions into this PR's fixture: extend the helper with the effects-exercising methods and add effects_test.ts, then assert the markers from the same single fixture run. retryTo is kept last and the child exec has a timeout guard so a future regression that re-hangs it fails cleanly instead of hanging. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 730e701 commit e0f5bb8

3 files changed

Lines changed: 119 additions & 20 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Effects regression under tsx/cjs (originally https://github.com/codeceptjs/CodeceptJS/issues/5632,
2+
// first addressed in PR #5634). within/tryTo/hopeThat/retryTo are part of the internal API and
3+
// delegate to the recorder/container singletons. Imported through a CommonJS loader (tsx/cjs) they
4+
// used to load a second, disconnected copy: tryTo/hopeThat returned without running their callback,
5+
// within skipped its inner steps, and retryTo hung forever.
6+
//
7+
// With the singletons shared at the source (lib/realm.js, #5635) the CJS copy of effects.js resolves
8+
// the live recorder/container, so all four run. Kept as dedicated coverage so a future regression that
9+
// re-splits the recorder/container fails here too.
10+
import { within, tryTo, hopeThat, retryTo } from "../../../lib/effects.js";
11+
12+
Feature("effects under tsx/cjs");
13+
14+
Scenario("tryTo executes the failing step and returns false", async ({ I }) => {
15+
const ok = await tryTo(() => {
16+
I.seeMissing();
17+
});
18+
console.log(`EFFECTS_TRYTO result=${ok}`);
19+
});
20+
21+
Scenario("within applies the context to inner steps", ({ I }) => {
22+
within("body", () => {
23+
I.clickInside();
24+
});
25+
});
26+
27+
Scenario("hopeThat executes the soft assertion and returns true", async ({ I }) => {
28+
const ok = await hopeThat(() => {
29+
I.pass();
30+
});
31+
console.log(`EFFECTS_HOPETHAT result=${ok}`);
32+
});
33+
34+
// Kept last on purpose: when the recorder is disconnected, retryTo never resolves and hangs,
35+
// so the earlier markers are already flushed before the runner-test timeout fires.
36+
Scenario("retryTo runs the callback until it succeeds", async ({ I }) => {
37+
await retryTo(() => {
38+
I.flaky();
39+
}, 3);
40+
console.log("EFFECTS_RETRY done");
41+
});

test/data/internal-api-tsx-cjs/internal_api_helper.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,43 @@ const Helper = HelperModule.default || HelperModule
55
const Config = ConfigModule.default || ConfigModule
66

77
class ConfigHelper extends Helper {
8+
constructor(config) {
9+
super(config)
10+
this._withinActive = false
11+
this._tries = 0
12+
}
13+
814
reportConfig() {
915
// Helper is loaded via import() (the ESM realm), so it has always shared the live config.
1016
console.log(`API_HELPER marker=${Config.get().helpers.ConfigHelper.marker}`)
1117
}
18+
19+
// --- used by the effects scenarios ---
20+
_withinBegin() {
21+
this._withinActive = true
22+
}
23+
24+
_withinEnd() {
25+
this._withinActive = false
26+
}
27+
28+
seeMissing() {
29+
throw new Error('element not found')
30+
}
31+
32+
clickInside() {
33+
console.log(`EFFECTS_CLICK withinActive=${this._withinActive}`)
34+
}
35+
36+
pass() {
37+
console.log('EFFECTS_PASS ran')
38+
}
39+
40+
flaky() {
41+
this._tries++
42+
console.log(`EFFECTS_FLAKY try=${this._tries}`)
43+
if (this._tries < 2) throw new Error('not ready yet')
44+
}
1245
}
1346

1447
export default ConfigHelper

test/runner/internal_api_tsx_test.js

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,55 @@ const codecept_dir = path.join(__dirname, '/../data/internal-api-tsx-cjs')
1212
const codecept_run = `${runner} run --config ${codecept_dir}/codecept.conf.ts`
1313

1414
// Regression test for https://github.com/codeceptjs/CodeceptJS/issues/5635
15-
// The internal API (config/container/recorder/event/store) must resolve to the live
16-
// singletons when imported from a test through a CommonJS loader (tsx/cjs), not a second,
17-
// disconnected copy. Drives a real tsx/cjs project and asserts each one is the live instance.
15+
// The internal API (config/container/recorder/event/store, and the effects that delegate to them)
16+
// must resolve to the live singletons when imported from a test through a CommonJS loader (tsx/cjs),
17+
// not a second, disconnected copy. Drives a real tsx/cjs project once and asserts on its output.
1818
describe('CodeceptJS internal API under tsx/cjs', function () {
1919
this.timeout(40000)
2020

21-
it('resolves config/container/recorder/event/store to the live singletons from a test', done => {
22-
exec(`${codecept_run}`, { timeout: 30000 }, (err, stdout) => {
23-
stdout.should.include('1 passed')
24-
// config (#5635): the real config the runner loaded, not an empty {}
25-
stdout.should.include('API_CONFIG name=internal-api-tsx-cjs-test')
26-
stdout.should.include('API_CONFIG marker=config-marker-123')
27-
// container: the live helpers map populated by the runner
28-
stdout.should.include('API_CONTAINER helper=object')
29-
// store: initialized by the runner
30-
stdout.should.include('API_STORE hasDir=true')
31-
// recorder: started by the runner for this test
32-
stdout.should.include('API_RECORDER running=true')
33-
// event: the live dispatcher the framework subscribes to
34-
stdout.should.include('API_EVENT live=true')
35-
// helper (ESM realm) reads the same live config
36-
stdout.should.include('API_HELPER marker=config-marker-123')
37-
chai.expect(err).to.be.null
21+
let stdout = ''
22+
let runErr = null
23+
24+
// Run the fixture once; the `timeout` kills the child if a regression makes retryTo() hang forever
25+
// (its manual promise never resolves on a disconnected recorder), so a broken fix fails on the
26+
// missing markers instead of hanging the whole suite.
27+
before(done => {
28+
exec(`${codecept_run}`, { timeout: 30000 }, (err, out) => {
29+
runErr = err
30+
stdout = out
3831
done()
3932
})
4033
})
34+
35+
it('resolves config/container/recorder/event/store to the live singletons from a test', () => {
36+
stdout.should.include('5 passed')
37+
// config (#5635): the real config the runner loaded, not an empty {}
38+
stdout.should.include('API_CONFIG name=internal-api-tsx-cjs-test')
39+
stdout.should.include('API_CONFIG marker=config-marker-123')
40+
// container: the live helpers map populated by the runner
41+
stdout.should.include('API_CONTAINER helper=object')
42+
// store: initialized by the runner
43+
stdout.should.include('API_STORE hasDir=true')
44+
// recorder: started by the runner for this test
45+
stdout.should.include('API_RECORDER running=true')
46+
// event: the live dispatcher the framework subscribes to
47+
stdout.should.include('API_EVENT live=true')
48+
// helper (ESM realm) reads the same live config
49+
stdout.should.include('API_HELPER marker=config-marker-123')
50+
chai.expect(runErr).to.be.null
51+
})
52+
53+
it('runs within/tryTo/hopeThat/retryTo imported through the CJS loader', () => {
54+
// tryTo ran its callback and resolved to false (a failed try), instead of returning
55+
// undefined from a disconnected, never-started recorder
56+
stdout.should.include('EFFECTS_TRYTO result=false')
57+
// within() applied its context so the inner step saw _withinBegin
58+
stdout.should.include('EFFECTS_CLICK withinActive=true')
59+
// hopeThat() ran its callback and resolved to true
60+
stdout.should.include('EFFECTS_PASS ran')
61+
stdout.should.include('EFFECTS_HOPETHAT result=true')
62+
// retryTo() retried the flaky callback until it passed (and did not hang)
63+
stdout.should.include('EFFECTS_FLAKY try=2')
64+
stdout.should.include('EFFECTS_RETRY done')
65+
})
4166
})

0 commit comments

Comments
 (0)