Skip to content

Commit 10f24cc

Browse files
authored
feat: module separation of worker module (#60)
1 parent 6a0e94c commit 10f24cc

File tree

15 files changed

+153
-44
lines changed

15 files changed

+153
-44
lines changed

infra/compiler/src/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ if (entryPoints.length < 1) {
6060
throw new Error(`No export module found to build at: ${absWorkingDir}`)
6161
}
6262

63+
const outdir = path.resolve(absWorkingDir, 'dist')
64+
6365
const ctx = await context({
6466
sourceRoot: absWorkingDir,
6567
entryPoints,
@@ -69,10 +71,11 @@ const ctx = await context({
6971
sourcemap: !options.production,
7072
sourcesContent: false,
7173
platform: 'node',
72-
outdir: path.resolve(absWorkingDir, 'dist'),
74+
outdir,
7375
outExtension: { '.js': '.cjs' },
7476
external: ['vscode'],
7577
logLevel: 'silent',
78+
metafile: true,
7679
plugins: [
7780
/* add to the end of plugins array */
7881
esbuildProblemMatcherPlugin,
@@ -81,6 +84,10 @@ const ctx = await context({
8184
if (options.watch) {
8285
await ctx.watch()
8386
} else {
84-
await ctx.rebuild()
87+
const result = await ctx.rebuild()
8588
await ctx.dispose()
89+
90+
if (!options.production) {
91+
fss.writeFileSync(path.join(outdir, 'meta.json'), JSON.stringify(result.metafile))
92+
}
8693
}

packages/vscode-wdio-worker/package.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@
66
"exports": {
77
".": {
88
"import": "./dist/index.js"
9+
},
10+
"./windows": {
11+
"import": "./dist/config.js"
12+
},
13+
"./parser/ast": {
14+
"import": "./dist/parsers/js.js"
15+
},
16+
"./parser/cucumber": {
17+
"import": "./dist/parsers/cucumber.js"
918
}
1019
},
1120
"scripts": {

packages/vscode-wdio-worker/src/config.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import * as t from '@babel/types'
77
import recast from 'recast'
88

99
const reporterIdentifierName = 'VscodeJsonReporter'
10-
const VSCODE_REPORTER_PATH = path.resolve(__dirname, 'reporter.cjs')
10+
11+
// This file is bundle as parser/ats.js at the package of vscode-webdriverio
12+
// So, the correct reporter path is parent directory
13+
const VSCODE_REPORTER_PATH = path.resolve(__dirname, '../reporter.cjs')
1114
/**
1215
* Since Windows cannot import by reporter file path due to issues with
1316
* the `initializePlugin` method of wdio-utils, the policy is to create a temporary configuration file.

packages/vscode-wdio-worker/src/parsers/cucumber.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import type { CucumberTestData, StepType, WorkerMetaContext } from '@vscode-wdio
1212
* @returns Array of test case information
1313
*/
1414
export function parseCucumberFeature(this: WorkerMetaContext, fileContent: string, uri: string) {
15-
this.log.debug('Cucumber parser is used.')
15+
this.log.debug(`Start parsing the cucumber feature file: ${uri}`)
1616
try {
1717
// Initialize the parser components
1818
const builder = new AstBuilder(IdGenerator.uuid())

packages/vscode-wdio-worker/src/parsers/index.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
import * as fs from 'node:fs/promises'
22
import path from 'node:path'
33

4-
import { parseCucumberFeature } from './cucumber.js'
5-
import { parseTestCases } from './js.js'
4+
import { getAstParser, getCucumberParser } from './utils.js'
65
import type { ReadSpecsOptions } from '@vscode-wdio/types/api'
76
import type { WorkerMetaContext } from '@vscode-wdio/types/worker'
87

8+
async function parseFeatureFile(context: WorkerMetaContext, contents: string, normalizeSpecPath: string) {
9+
const p = await getCucumberParser(context)
10+
return p.call(context, contents, normalizeSpecPath)
11+
}
12+
13+
async function parseJsFile(context: WorkerMetaContext, contents: string, normalizeSpecPath: string) {
14+
const p = await getAstParser(context)
15+
return p.call(context, contents, normalizeSpecPath)
16+
}
17+
918
export async function parse(this: WorkerMetaContext, options: ReadSpecsOptions) {
1019
return await Promise.all(
1120
options.specs.map(async (spec) => {
@@ -14,8 +23,8 @@ export async function parse(this: WorkerMetaContext, options: ReadSpecsOptions)
1423
const contents = await fs.readFile(normalizeSpecPath, { encoding: 'utf8' })
1524
try {
1625
const testCases = isCucumberFeatureFile(normalizeSpecPath)
17-
? parseCucumberFeature.call(this, contents, normalizeSpecPath) // Parse Cucumber feature file
18-
: parseTestCases.call(this, contents, normalizeSpecPath) // Parse JavaScript/TypeScript test file
26+
? await parseFeatureFile(this, contents, normalizeSpecPath) // Parse Cucumber feature file
27+
: await parseJsFile(this, contents, normalizeSpecPath) // Parse JavaScript/TypeScript test file
1928

2029
this.log.debug(`Successfully parsed: ${normalizeSpecPath}`)
2130
return {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import path from 'node:path'
2+
3+
import { dynamicLoader } from '../utils.js'
4+
import type { WorkerMetaContext } from '@vscode-wdio/types/worker'
5+
import type { parseCucumberFeature } from './cucumber.js'
6+
import type { parseTestCases } from './js.js'
7+
8+
export type CucumberParser = typeof parseCucumberFeature
9+
export type AstParser = typeof parseTestCases
10+
11+
const CUCUMBER_PARSER_PATH = path.resolve(__dirname, 'parser/cucumber.cjs')
12+
const AST_PARSER_PATH = path.resolve(__dirname, 'parser/ast.cjs')
13+
14+
let cucumberParser: CucumberParser | undefined
15+
let astParser: AstParser | undefined
16+
17+
export async function getCucumberParser(context: WorkerMetaContext): Promise<CucumberParser> {
18+
return (await dynamicLoader(
19+
context,
20+
cucumberParser,
21+
CUCUMBER_PARSER_PATH,
22+
'parseCucumberFeature'
23+
)) as CucumberParser
24+
}
25+
26+
export async function getAstParser(context: WorkerMetaContext): Promise<AstParser> {
27+
return (await dynamicLoader(context, astParser, AST_PARSER_PATH, 'parseTestCases')) as AstParser
28+
}

packages/vscode-wdio-worker/src/test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as os from 'node:os'
33
import { dirname, isAbsolute, join, resolve } from 'node:path'
44

55
import { getLauncherInstance } from './cli.js'
6-
import { createTempConfigFile, isWindows } from './config.js'
6+
import { getTempConfigCreator, isWindows } from './utils.js'
77
import type { RunTestOptions, TestResultData } from '@vscode-wdio/types/api'
88
import type { ResultSet } from '@vscode-wdio/types/reporter'
99
import type { LoggerInterface } from '@vscode-wdio/types/utils'
@@ -43,7 +43,8 @@ export async function runTest(this: WorkerMetaContext, options: RunTestOptions):
4343
}
4444

4545
if (isWindows()) {
46-
configFile = await createTempConfigFile(options.configPath, outputDir.json!)
46+
const creator = await getTempConfigCreator(this)
47+
configFile = await creator(options.configPath, outputDir.json!)
4748
options.configPath = configFile
4849
wdioArgs.configPath = configFile
4950
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import path from 'node:path'
2+
import { pathToFileURL } from 'node:url'
3+
4+
import type { WorkerMetaContext } from '@vscode-wdio/types'
5+
import type { createTempConfigFile } from './config.js'
6+
7+
export type TempConfigFileCreator = typeof createTempConfigFile
8+
9+
const VSCODE_WINDOWS_CONFIG_CREATOR_PATH = path.resolve(__dirname, 'parser/ast.cjs')
10+
11+
let tempConfigCreator: TempConfigFileCreator | undefined
12+
13+
export async function getTempConfigCreator(context: WorkerMetaContext): Promise<TempConfigFileCreator> {
14+
return (await dynamicLoader(
15+
context,
16+
tempConfigCreator,
17+
VSCODE_WINDOWS_CONFIG_CREATOR_PATH,
18+
'createTempConfigFile'
19+
)) as TempConfigFileCreator
20+
}
21+
22+
export function isWindows() {
23+
return process.platform === 'win32'
24+
}
25+
26+
export async function dynamicLoader(
27+
context: WorkerMetaContext,
28+
libModule: unknown,
29+
modulePath: string,
30+
fnName: string
31+
): Promise<unknown> {
32+
if (libModule) {
33+
context.log.debug(`Use cached ${path.dirname(modulePath)}`)
34+
return libModule
35+
}
36+
context.log.debug(`Import ${path.basename(modulePath)}`)
37+
libModule = (await import(pathToFileURL(modulePath).href))[fnName]
38+
return libModule
39+
}

packages/vscode-wdio-worker/tests/config.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ vi.mock('node:path', async (importOriginal) => {
2626
return {
2727
default: {
2828
...actual,
29-
resolve: vi.fn((_, f) => `/path/to/${f}`),
29+
resolve: vi.fn((_, f) => path.posix.resolve(`/path/to/parser/${f}`)),
3030
},
3131
}
3232
})
3333

3434
describe('config.ts', () => {
35-
const VSCODE_REPORTER_PATH = path.resolve(__dirname, 'reporter.cjs')
35+
const VSCODE_REPORTER_PATH = path.resolve(__dirname, '../reporter.cjs')
3636
const reporterPathUrl = pathToFileURL(VSCODE_REPORTER_PATH).href
3737

3838
beforeEach(() => {

packages/vscode-wdio-worker/tests/parsers/cucumber.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,9 @@ describe('Cucumber Parser', () => {
340340
parseCucumberFeature.call(mockContext, basicFeatureContent, 'basic-feature.feature')
341341

342342
// Verify debug log was called
343-
expect(mockContext.log.debug).toHaveBeenCalledWith('Cucumber parser is used.')
343+
expect(mockContext.log.debug).toHaveBeenCalledWith(
344+
'Start parsing the cucumber feature file: basic-feature.feature'
345+
)
344346
})
345347

346348
it('should include proper source ranges for each element', () => {

packages/vscode-wdio-worker/tests/parsers/index.test.ts

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,22 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
55

66
// Import parse function from parsers
77

8-
import { parseCucumberFeature } from '../../src/parsers/cucumber.js'
98
import { parse } from '../../src/parsers/index.js'
10-
import { parseTestCases } from '../../src/parsers/js.js'
9+
import { getAstParser, getCucumberParser } from '../../src/parsers/utils.js'
1110
import type { ReadSpecsOptions } from '@vscode-wdio/types/api'
1211
import type { WorkerMetaContext, TestData, CucumberTestData } from '@vscode-wdio/types/worker'
1312

14-
// Import the types
1513
// Mock fs module
1614
vi.mock('node:fs/promises', () => ({
1715
readFile: vi.fn(),
1816
}))
1917

2018
// Mock the parsers
21-
vi.mock('../../src/parsers/cucumber.js', () => ({
22-
parseCucumberFeature: vi.fn(),
19+
vi.mock('../../src/parsers/utils.js', () => ({
20+
getCucumberParser: vi.fn(),
21+
getAstParser: vi.fn(),
2322
}))
2423

25-
vi.mock('../../src/parsers/js.js', () => ({
26-
parseTestCases: vi.fn(),
27-
}))
28-
29-
// Import mocked modules
30-
3124
describe('Parser Index', () => {
3225
// Create mock context
3326
const mockContext: WorkerMetaContext = {
@@ -59,6 +52,7 @@ describe('Parser Index', () => {
5952
],
6053
},
6154
]
55+
const mockAstParser = vi.fn(() => jsMockTestData)
6256

6357
const cucumberMockTestData: CucumberTestData[] = [
6458
{
@@ -87,13 +81,15 @@ describe('Parser Index', () => {
8781
metadata: {},
8882
},
8983
]
84+
const mockCucumberParser = vi.fn(() => cucumberMockTestData)
9085

9186
beforeEach(() => {
9287
vi.resetAllMocks()
9388

9489
// Mock the parseTestCases and parseCucumberFeature functions
95-
vi.mocked(parseTestCases).mockReturnValue(jsMockTestData)
96-
vi.mocked(parseCucumberFeature).mockReturnValue(cucumberMockTestData)
90+
// vi.mocked(parseTestCases).mockReturnValue(jsMockTestData)
91+
vi.mocked(getCucumberParser).mockResolvedValue(mockCucumberParser)
92+
vi.mocked(getAstParser).mockResolvedValue(mockAstParser)
9793
})
9894

9995
afterEach(() => {
@@ -119,8 +115,8 @@ describe('Parser Index', () => {
119115
expect(result[0].tests).toEqual(jsMockTestData)
120116

121117
// Verify the correct parser was called
122-
expect(parseTestCases).toHaveBeenCalledWith(jsTestContent, path.normalize('/path/to/test.js'))
123-
expect(parseCucumberFeature).not.toHaveBeenCalled()
118+
expect(mockAstParser).toHaveBeenCalledWith(jsTestContent, path.normalize('/path/to/test.js'))
119+
expect(mockCucumberParser).not.toHaveBeenCalled()
124120

125121
// Verify logging
126122
expect(mockContext.log.debug).toHaveBeenCalledWith(`Parse spec file: ${path.normalize('/path/to/test.js')}`)
@@ -147,8 +143,8 @@ describe('Parser Index', () => {
147143
expect(result[0].tests).toEqual(jsMockTestData)
148144

149145
// Verify the correct parser was called
150-
expect(parseTestCases).toHaveBeenCalledWith(jsTestContent, path.normalize('/path/to/test.ts'))
151-
expect(parseCucumberFeature).not.toHaveBeenCalled()
146+
expect(mockAstParser).toHaveBeenCalledWith(jsTestContent, path.normalize('/path/to/test.ts'))
147+
expect(mockCucumberParser).not.toHaveBeenCalled()
152148
})
153149

154150
it('should parse Cucumber feature files correctly', async () => {
@@ -169,11 +165,11 @@ describe('Parser Index', () => {
169165
expect(result[0].tests).toEqual(cucumberMockTestData)
170166

171167
// Verify the correct parser was called
172-
expect(parseCucumberFeature).toHaveBeenCalledWith(
168+
expect(mockCucumberParser).toHaveBeenCalledWith(
173169
cucumberFeatureContent,
174170
path.normalize('/path/to/test.feature')
175171
)
176-
expect(parseTestCases).not.toHaveBeenCalled()
172+
expect(mockAstParser).not.toHaveBeenCalled()
177173
})
178174

179175
it('should handle uppercase feature file extensions', async () => {
@@ -194,11 +190,11 @@ describe('Parser Index', () => {
194190
expect(result[0].tests).toEqual(cucumberMockTestData)
195191

196192
// Verify the correct parser was called
197-
expect(parseCucumberFeature).toHaveBeenCalledWith(
193+
expect(mockCucumberParser).toHaveBeenCalledWith(
198194
cucumberFeatureContent,
199195
path.normalize('/path/to/test.FEATURE')
200196
)
201-
expect(parseTestCases).not.toHaveBeenCalled()
197+
expect(mockAstParser).not.toHaveBeenCalled()
202198
})
203199

204200
it('should parse multiple spec files', async () => {
@@ -231,8 +227,8 @@ describe('Parser Index', () => {
231227
expect(result[1].tests).toEqual(cucumberMockTestData)
232228

233229
// Verify the correct parsers were called
234-
expect(parseTestCases).toHaveBeenCalledWith(jsTestContent, path.normalize('/path/to/test.js'))
235-
expect(parseCucumberFeature).toHaveBeenCalledWith(
230+
expect(mockAstParser).toHaveBeenCalledWith(jsTestContent, path.normalize('/path/to/test.js'))
231+
expect(mockCucumberParser).toHaveBeenCalledWith(
236232
cucumberFeatureContent,
237233
path.normalize('/path/to/test.feature')
238234
)
@@ -268,7 +264,7 @@ describe('Parser Index', () => {
268264
expect(result[0].spec).toBe(path.normalize('C:\\path\\to\\test.js'))
269265

270266
// Verify the parser was called with the normalized path
271-
expect(parseTestCases).toHaveBeenCalledWith(jsTestContent, path.normalize('C:\\path\\to\\test.js'))
267+
expect(mockAstParser).toHaveBeenCalledWith(jsTestContent, path.normalize('C:\\path\\to\\test.js'))
272268
})
273269

274270
it('should handle empty specs array', async () => {
@@ -283,8 +279,8 @@ describe('Parser Index', () => {
283279
// Verify
284280
expect(result).toEqual([])
285281
expect(fs.readFile).not.toHaveBeenCalled()
286-
expect(parseTestCases).not.toHaveBeenCalled()
287-
expect(parseCucumberFeature).not.toHaveBeenCalled()
282+
expect(mockAstParser).not.toHaveBeenCalled()
283+
expect(mockCucumberParser).not.toHaveBeenCalled()
288284
})
289285
})
290286
})

0 commit comments

Comments
 (0)