Skip to content

Commit fe84e96

Browse files
Copilotkobenguyent
andcommitted
Changes before error encountered
Co-authored-by: kobenguyent <7845001+kobenguyent@users.noreply.github.com>
1 parent 333b215 commit fe84e96

File tree

4 files changed

+86
-30
lines changed

4 files changed

+86
-30
lines changed

lib/container.js

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,21 @@ class Container {
6363
// create support objects
6464
container.support = {}
6565
container.helpers = await createHelpers(config.helpers || {})
66-
container.translation = loadTranslation(config.translation || null, config.vocabularies || [])
66+
container.translation = await loadTranslation(config.translation || null, config.vocabularies || [])
6767
container.proxySupport = await createSupportObjects(config.include || {})
6868
container.plugins = await createPlugins(config.plugins || {}, opts)
6969
container.result = new Result()
7070

71-
await createActor(config.include?.I)
71+
// Create actor - pass custom I object only if no I is provided in includes
72+
// If I is provided in includes, it should remain as a pure support object
73+
const customIProvided = config.include && config.include.I
74+
const actorConfig = customIProvided ? {} : config.include?.I
75+
container.actor = await createActor(actorConfig)
76+
77+
// Only set I to actor if no custom I was loaded as a support object
78+
if (!customIProvided) {
79+
container.support.I = container.actor
80+
}
7281

7382
if (opts && opts.ai) ai.enable(config.ai) // enable AI Assistant
7483
if (config.gherkin) await loadGherkinSteps(config.gherkin.steps || [])
@@ -173,8 +182,9 @@ class Container {
173182
*/
174183
static clear(newHelpers = {}, newSupport = {}, newPlugins = {}) {
175184
container.helpers = newHelpers
176-
container.translation = loadTranslation()
177-
container.proxySupport = createSupportObjects(newSupport)
185+
container.translation = Translation.createEmpty() // Use empty translation to avoid async issues
186+
// Handle simple objects synchronously for backward compatibility
187+
container.proxySupport = createSupportObjectsSync(newSupport)
178188
container.plugins = newPlugins
179189
container.sharedKeys = new Set() // Clear shared keys
180190
asyncHelperPromise = Promise.resolve()
@@ -306,9 +316,20 @@ async function requireHelperFromModule(helperName, config, HelperClass) {
306316
HelperClass = mod.default || mod
307317
} catch (err) {
308318
if (err.code === 'ERR_MODULE_NOT_FOUND') {
309-
throw new Error(`Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`)
319+
// Try adding .js extension for custom helpers (ESM compatibility)
320+
if (!moduleName.endsWith('.js') && !moduleName.endsWith('.mjs') && !moduleName.endsWith('.ts')) {
321+
try {
322+
const mod = await import(moduleName + '.js');
323+
HelperClass = mod.default || mod
324+
} catch (retryErr) {
325+
throw new Error(`Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`)
326+
}
327+
} else {
328+
throw new Error(`Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`)
329+
}
330+
} else {
331+
throw err
310332
}
311-
throw err
312333
}
313334
}
314335
return HelperClass
@@ -328,8 +349,8 @@ async function createSupportObjects(config) {
328349
const supportObjects = {};
329350
for (const name in config) {
330351
if (name === 'I') {
331-
// Handle I (actor) separately
332-
supportObjects[name] = await createActor(config.I);
352+
// Load I as a support object, not as an actor
353+
supportObjects[name] = await loadSupportObject(config.I);
333354
continue;
334355
}
335356

@@ -482,7 +503,7 @@ async function loadSupportObject(modulePath, supportObjectName) {
482503
* Method collect own property and prototype
483504
*/
484505

485-
function loadTranslation(locale, vocabularies) {
506+
async function loadTranslation(locale, vocabularies) {
486507
if (!locale) {
487508
return Translation.createEmpty()
488509
}
@@ -495,12 +516,15 @@ function loadTranslation(locale, vocabularies) {
495516
} else if (fileExists(path.join(global.codecept_dir, locale))) {
496517
// get from a provided file instead
497518
translation = Translation.createDefault()
498-
translation.loadVocabulary(locale)
519+
await translation.loadVocabulary(locale)
499520
} else {
500521
translation = Translation.createDefault()
501522
}
502523

503-
vocabularies.forEach(v => translation.loadVocabulary(v))
524+
// Load vocabularies asynchronously
525+
for (const v of vocabularies) {
526+
await translation.loadVocabulary(v)
527+
}
504528

505529
return translation
506530
}
@@ -535,3 +559,18 @@ function normalizeAndJoin(basePath, subPath) {
535559
// Join the paths using POSIX-style
536560
return path.posix.join(normalizedBase, normalizedSub)
537561
}
562+
563+
function createSupportObjectsSync(config) {
564+
// Synchronous version for simple objects (used by clear method)
565+
const supportObjects = {};
566+
for (const name in config) {
567+
if (typeof config[name] === 'object') {
568+
supportObjects[name] = config[name];
569+
}
570+
}
571+
// Store objects in container for access
572+
for (const name in supportObjects) {
573+
container.support[name] = supportObjects[name];
574+
}
575+
return supportObjects;
576+
}

lib/translation.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,17 @@ class Translation {
1818
const filePath = path.join(global.codecept_dir, vocabularyFile);
1919

2020
try {
21-
const vocabulary = await import(filePath).then(m => m.default || m);
21+
let vocabulary;
22+
if (filePath.endsWith('.json')) {
23+
// Handle JSON files with fs
24+
const fs = await import('fs');
25+
const content = fs.readFileSync(filePath, 'utf8');
26+
vocabulary = JSON.parse(content);
27+
} else {
28+
// Handle JS modules
29+
const module = await import(filePath);
30+
vocabulary = module.default || module;
31+
}
2232
this.vocabulary = merge(this.vocabulary, vocabulary);
2333
} catch (err) {
2434
throw new Error(`Can't load vocabulary from ${filePath}; ${err}`);

test/unit/bdd_test.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import chai from 'chai'
66
import recorder from '../../lib/recorder.js'
77
import container from '../../lib/container.js'
88
import Config from '../../lib/config.js'
9-
import { clearSteps, Given, When, Then, And, matchStep } from '../../lib/mocha/bdd.js'
9+
import { clearSteps, Given, When, Then, And, matchStep, defineParameterType } from '../../lib/mocha/bdd.js'
10+
import run from '../../lib/mocha/gherkin.js'
11+
import actor from '../../lib/actor.js'
12+
import event from '../../lib/event.js'
1013

1114
const { expect } = chai
1215
const uuidFn = Messages.IdGenerator.uuid()
@@ -17,6 +20,9 @@ const matcher = new Gherkin.GherkinClassicTokenMatcher()
1720
const __dirname = path.dirname(fileURLToPath(import.meta.url))
1821
global.codecept_dir = path.join(__dirname, '/..')
1922

23+
let printed = []
24+
let I
25+
2026
class Color {
2127
constructor(name) {
2228
this.name = name

test/unit/container_test.js

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url))
1212

1313
describe('Container', () => {
1414
before(() => {
15+
global.codecept_dir = path.join(__dirname, '/..')
1516
global.inject = container.support
1617
global.actor = actor
1718
})
@@ -150,7 +151,7 @@ describe('Container', () => {
150151
})
151152

152153
describe('#create', () => {
153-
it('should create container with helpers', () => {
154+
it('should create container with helpers', async () => {
154155
const config = {
155156
helpers: {
156157
MyHelper: {
@@ -159,7 +160,7 @@ describe('Container', () => {
159160
FileSystem: {},
160161
},
161162
}
162-
container.create(config)
163+
await container.create(config)
163164
// custom helpers
164165
expect(container.helpers('MyHelper')).is.ok
165166
expect(container.helpers('MyHelper').method()).to.eql('hello world')
@@ -196,8 +197,8 @@ describe('Container', () => {
196197
expect(Object.keys(container.support('I'))).to.include('doSomething')
197198
})
198199

199-
it('should load DI includes provided as require paths', () => {
200-
container.create({
200+
it('should load DI includes provided as require paths', async () => {
201+
await container.create({
201202
include: {
202203
dummyPage: './data/dummy_page',
203204
},
@@ -207,7 +208,7 @@ describe('Container', () => {
207208
})
208209

209210
it('should load DI and inject I into PO', async () => {
210-
container.create({
211+
await container.create({
211212
include: {
212213
dummyPage: './data/dummy_page',
213214
I: './data/I',
@@ -219,8 +220,8 @@ describe('Container', () => {
219220
expect(container.support('dummyPage').getI()).to.have.keys('_init', 'doSomething')
220221
})
221222

222-
it('should load DI and inject custom I into PO', () => {
223-
container.create({
223+
it('should load DI and inject custom I into PO', async () => {
224+
await container.create({
224225
include: {
225226
dummyPage: './data/dummy_page',
226227
I: './data/I',
@@ -231,8 +232,8 @@ describe('Container', () => {
231232
expect(container.support('dummyPage')).to.include.keys('openDummyPage')
232233
})
233234

234-
it('should load DI includes provided as objects', () => {
235-
container.create({
235+
it('should load DI includes provided as objects', async () => {
236+
await container.create({
236237
include: {
237238
dummyPage: {
238239
openDummyPage: () => 'dummy page opened',
@@ -243,8 +244,8 @@ describe('Container', () => {
243244
expect(container.support('dummyPage')).to.include.keys('openDummyPage')
244245
})
245246

246-
it('should load DI includes provided as objects', () => {
247-
container.create({
247+
it('should load DI includes provided as objects', async () => {
248+
await container.create({
248249
include: {
249250
dummyPage: {
250251
openDummyPage: () => 'dummy page opened',
@@ -257,14 +258,14 @@ describe('Container', () => {
257258
})
258259

259260
describe('#append', () => {
260-
it('should be able to add new helper', () => {
261+
it('should be able to add new helper', async () => {
261262
const config = {
262263
helpers: {
263264
FileSystem: {},
264265
},
265266
}
266-
container.create(config)
267-
container.append({
267+
await container.create(config)
268+
await container.append({
268269
helpers: {
269270
AnotherHelper: { method: () => 'executed' },
270271
},
@@ -276,9 +277,9 @@ describe('Container', () => {
276277
expect(container.helpers('AnotherHelper').method()).is.eql('executed')
277278
})
278279

279-
it('should be able to add new support object', () => {
280-
container.create({})
281-
container.append({ support: { userPage: { login: '#login' } } })
280+
it('should be able to add new support object', async () => {
281+
await container.create({})
282+
await container.append({ support: { userPage: { login: '#login' } } })
282283
expect(container.support('I')).is.ok
283284
expect(container.support('userPage')).is.ok
284285
expect(container.support('userPage').login).is.eql('#login')

0 commit comments

Comments
 (0)