Skip to content

Commit 989467c

Browse files
authored
feat: load and unload env variables at worker (#67)
1 parent 05c7134 commit 989467c

44 files changed

Lines changed: 786 additions & 151 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,10 @@ jobs:
5959
uses: ./.github/workflows/ci-smoke.yml
6060
with:
6161
scenario: 'timeout'
62+
63+
smoke-env:
64+
name: Smoke - Load .env files
65+
needs: [lint, build, e2e]
66+
uses: ./.github/workflows/ci-smoke.yml
67+
with:
68+
scenario: 'env'

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,13 @@ For example:
7878

7979
This extension contributes the following settings:
8080

81-
- `webdriverio.nodeExecutable`: The path to the Node.js executable. If not assigned, WebdriverIO try to resolve the node path from environment valuables of `PATH`.
8281
- `webdriverio.configFilePattern`: Glob pattern for WebdriverIO configuration file
82+
- `webdriverio.nodeExecutable`: The path to the Node.js executable. If not assigned, WebdriverIO try to resolve the node path from environment valuables of `PATH`.
8383
- `webdriverio.workerIdleTimeout`: If no processing is performed in the Worker for the set amount of time(defined by seconds), the Worker is terminated. If processing is requested again, it will be started automatically.
84-
- `webdriverio.logLevel`: Set the logLevel
84+
- `webdriverio.envFiles`: A list of `.env` files, from which environment variables are loaded when WebdriverIO is run from the file set in this parameter.<br>If a variable is defined in more than one `.env` file, the first value set will take precedence unless the `webdriverio.overrideEnv` is set.
85+
- `webdriverio.overrideEnv`: Override any environment variables that have already been set on your machine with values from your `.env` file(s).<br>See also `webdriverio.envFiles`
8586
- `webdriverio.showOutput`: Show WebdriverIO output in the test result when set `true` this option
87+
- `webdriverio.logLevel`: Set the logLevel
8688

8789
## Remarks
8890

e2e/helpers/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,15 @@ export async function clearAllTestResults(workbench: Workbench) {
103103
}
104104
}
105105

106-
export async function clickTitleActionButton(titlePart: ViewTitlePart, label: string) {
106+
export async function clickTitleActionButton(titlePart: ViewTitlePart, label: string | RegExp) {
107107
const elements = (await titlePart.elem.$$(
108108
(titlePart.locatorMap.ViewSection.actionConstructor as Function)()
109109
)) as WebdriverIO.Element[]
110110

111+
const regExp = typeof label === 'string' ? new RegExp(label) : label
111112
for (const element of elements) {
112-
if ((await element.getAttribute('aria-label')) === label) {
113+
const actualLabel = await element.getAttribute('aria-label')
114+
if (regExp.test(actualLabel)) {
113115
await element.click()
114116
break
115117
}

e2e/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"test:smoke": "run-s test:smoke:*",
2020
"test:smoke:config": "cross-env VSCODE_WDIO_E2E_SCENARIO=config xvfb-maybe wdio run ./wdioSmoke.conf.ts",
2121
"test:smoke:timeout": "cross-env VSCODE_WDIO_E2E_SCENARIO=timeout xvfb-maybe wdio run ./wdioSmoke.conf.ts",
22+
"test:smoke:env": "cross-env VSCODE_WDIO_E2E_SCENARIO=env xvfb-maybe wdio run ./wdioSmoke.conf.ts",
2223
"wdio": "wdio run ./wdio.conf.ts"
2324
},
2425
"devDependencies": {

e2e/tests/envEnable.spec.ts

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import path from 'node:path'
2+
import url from 'node:url'
3+
4+
import { browser, expect } from '@wdio/globals'
5+
import shell from 'shelljs'
6+
7+
import {
8+
STATUS,
9+
clearAllTestResults,
10+
clickTitleActionButton,
11+
clickTreeItemButton,
12+
collapseAllTests,
13+
getTestingSection,
14+
openTestingView,
15+
waitForResolved,
16+
waitForTestStatus,
17+
} from '../helpers/index.ts'
18+
19+
import type { SideBarView, Workbench } from 'wdio-vscode-service'
20+
21+
const __dirname = path.dirname(url.fileURLToPath(import.meta.url))
22+
const rootDir = path.resolve(__dirname, '..', '..')
23+
const workspacePath = path.resolve(rootDir, 'samples/smoke/env')
24+
const envPath = path.resolve(workspacePath, '.env')
25+
26+
describe('VS Code Extension Testing (EnableEnv)', function () {
27+
let workbench: Workbench
28+
let sideBarView: SideBarView<any>
29+
30+
beforeEach(async function () {
31+
workbench = await browser.getWorkbench()
32+
await openTestingView(workbench)
33+
sideBarView = workbench.getSideBar()
34+
35+
const testingSection = await getTestingSection(sideBarView.getContent())
36+
await collapseAllTests(testingSection)
37+
38+
await browser.waitUntil(async () => (await testingSection.getVisibleItems()).length === 1)
39+
})
40+
41+
afterEach(async function () {
42+
await new Promise((resolve) => setTimeout(resolve, 1000))
43+
await clearAllTestResults(workbench)
44+
})
45+
46+
after(function () {
47+
shell.exec(`git checkout ${envPath}`)
48+
})
49+
50+
it('should be resolved the defined tests before run tests', async function () {
51+
const testingSection = await getTestingSection(sideBarView.getContent())
52+
const items = await testingSection.getVisibleItems()
53+
54+
await waitForResolved(browser, items[0])
55+
56+
await expect(items).toMatchTreeStructure([
57+
{
58+
text: 'wdio.conf.ts',
59+
status: STATUS.NOT_YET_RUN,
60+
children: [
61+
{
62+
text: 'enableEnv.spec.ts',
63+
status: STATUS.NOT_YET_RUN,
64+
children: [
65+
{
66+
text: 'Enable Environment variables',
67+
status: STATUS.NOT_YET_RUN,
68+
children: [
69+
{
70+
text: 'should set the environment variables SMOKE_TEST_SCENARIO',
71+
status: STATUS.NOT_YET_RUN,
72+
},
73+
{
74+
text: 'should set the environment variables SMOKE_TEST_ENV_TEST_01',
75+
status: STATUS.NOT_YET_RUN,
76+
},
77+
],
78+
},
79+
],
80+
},
81+
],
82+
},
83+
])
84+
})
85+
86+
it('should run tests successfully with env files', async function () {
87+
const testingSection = await getTestingSection(sideBarView.getContent())
88+
const items = await testingSection.getVisibleItems()
89+
90+
await waitForResolved(browser, items[0])
91+
92+
await clickTreeItemButton(browser, items[0], 'Run Test')
93+
94+
await waitForTestStatus(browser, items[0], STATUS.PASSED)
95+
96+
await expect(items).toMatchTreeStructure([
97+
{
98+
text: 'wdio.conf.ts',
99+
status: STATUS.PASSED,
100+
children: [
101+
{
102+
text: 'enableEnv.spec.ts',
103+
status: STATUS.PASSED,
104+
children: [
105+
{
106+
text: 'Enable Environment variables',
107+
status: STATUS.PASSED,
108+
children: [
109+
{
110+
text: 'should set the environment variables SMOKE_TEST_SCENARIO',
111+
status: STATUS.PASSED,
112+
},
113+
{
114+
text: 'should set the environment variables SMOKE_TEST_ENV_TEST_01',
115+
status: STATUS.PASSED,
116+
},
117+
],
118+
},
119+
],
120+
},
121+
],
122+
},
123+
])
124+
})
125+
126+
it('should be reflected the changes of env file to the WDIO configuration files', async function () {
127+
shell.rm('-f', envPath)
128+
await clickTitleActionButton(sideBarView.getTitlePart(), /Refresh Tests.*/)
129+
130+
const testingSection = await getTestingSection(sideBarView.getContent())
131+
const items = await testingSection.getVisibleItems()
132+
133+
await waitForResolved(browser, items[0])
134+
135+
await new Promise((resolve) => setTimeout(resolve, 1000))
136+
await expect(items).toMatchTreeStructure([
137+
{
138+
text: 'wdio.conf.ts',
139+
status: STATUS.NOT_YET_RUN,
140+
children: [
141+
{
142+
text: 'disableEnv.spec.ts',
143+
status: STATUS.NOT_YET_RUN,
144+
children: [
145+
{
146+
text: 'Enable Environment variables',
147+
status: STATUS.NOT_YET_RUN,
148+
children: [
149+
{
150+
text: 'should not set the environment variables SMOKE_TEST_SCENARIO',
151+
status: STATUS.NOT_YET_RUN,
152+
},
153+
{
154+
text: 'should not set the environment variables SMOKE_TEST_ENV_TEST_01',
155+
status: STATUS.NOT_YET_RUN,
156+
},
157+
],
158+
},
159+
],
160+
},
161+
],
162+
},
163+
])
164+
})
165+
})

e2e/wdioSmoke.conf.ts

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,42 @@
11
import { createBaseConfig } from './wdio.conf.ts'
22

3-
type TestTargets = 'config' | 'timeout'
3+
type TestTargets = 'config' | 'timeout' | 'env'
44

55
const target = (process.env.VSCODE_WDIO_E2E_SCENARIO || 'config') as TestTargets
66

7-
const workspace = target === 'config' ? '../samples/smoke/update-config' : '../samples/e2e/cucumber'
8-
9-
function defineSpecs(target: TestTargets) {
7+
function defineSmokePrams(target: TestTargets) {
108
switch (target) {
119
case 'config':
12-
return [
13-
'./tests/updateConfig.spec.ts',
14-
'./tests/updateSpec.spec.ts',
15-
'./tests/updateErrorSpec.spec.ts',
16-
'./tests/updateErrorConfig.spec.ts',
17-
]
10+
return {
11+
specs: [
12+
'./tests/updateConfig.spec.ts',
13+
'./tests/updateSpec.spec.ts',
14+
'./tests/updateErrorSpec.spec.ts',
15+
'./tests/updateErrorConfig.spec.ts',
16+
],
17+
workspace: '../samples/smoke/update-config',
18+
settings: {},
19+
}
20+
case 'timeout':
21+
return {
22+
specs: ['./tests/workerIdleTimeout.spec.ts'],
23+
workspace: '../samples/e2e/cucumber',
24+
settings: { 'webdriverio.logLevel': 'debug', 'webdriverio.workerIdleTimeout': 2 },
25+
}
26+
case 'env':
27+
return {
28+
specs: ['./tests/envEnable.spec.ts'],
29+
workspace: '../samples/smoke/env',
30+
settings: { 'webdriverio.envFiles': ['.env'] },
31+
}
1832
default:
19-
return ['./tests/workerIdleTimeout.spec.ts']
33+
throw new Error(`Not defined scenario: ${target}`)
2034
}
2135
}
2236

23-
const specs = defineSpecs(target)
24-
25-
const settings = target === 'timeout' ? { 'webdriverio.logLevel': 'debug', 'webdriverio.workerIdleTimeout': 2 } : {}
26-
37+
const params = defineSmokePrams(target)
2738
export const config: WebdriverIO.Config = {
28-
...createBaseConfig(workspace, settings),
29-
specs,
39+
...createBaseConfig(params.workspace, params.settings),
40+
specs: params.specs,
3041
maxInstances: 1,
3142
}

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export class ExtensionConfigManager extends EventEmitter implements IExtensionCo
2121
const config = vscode.workspace.getConfiguration(EXTENSION_ID)
2222

2323
const configFilePattern = config.get<string[]>('configFilePattern')
24+
const envFiles = config.get<string[]>('envFiles')
2425

2526
this._globalConfig = {
2627
nodeExecutable: config.get<string | undefined>('nodeExecutable', DEFAULT_CONFIG_VALUES.nodeExecutable),
@@ -29,6 +30,8 @@ export class ExtensionConfigManager extends EventEmitter implements IExtensionCo
2930
? configFilePattern
3031
: [...DEFAULT_CONFIG_VALUES.configFilePattern],
3132
workerIdleTimeout: config.get<number>('workerIdleTimeout', DEFAULT_CONFIG_VALUES.workerIdleTimeout),
33+
envFiles: envFiles && envFiles.length > 0 ? envFiles : [...DEFAULT_CONFIG_VALUES.envFiles],
34+
overrideEnv: this.resolveBooleanConfig(config, 'overrideEnv', DEFAULT_CONFIG_VALUES.overrideEnv),
3235
showOutput: this.resolveBooleanConfig(config, 'showOutput', DEFAULT_CONFIG_VALUES.showOutput),
3336
logLevel: config.get<string>('logLevel', DEFAULT_CONFIG_VALUES.logLevel),
3437
}
@@ -114,12 +117,12 @@ export class ExtensionConfigManager extends EventEmitter implements IExtensionCo
114117
const normalizedConfigPath = normalizePath(configPath)
115118
const workspaceFolders = this.getWorkspaces()
116119

117-
const result: vscode.Uri[] = []
120+
const result: vscode.WorkspaceFolder[] = []
118121
for (const workspaceFolder of workspaceFolders) {
119122
const workspaceInfo = this._workspaceConfigMap.get(workspaceFolder)
120123
if (workspaceInfo && workspaceInfo.has(normalizedConfigPath)) {
121124
log.debug(`detected workspace "${workspaceFolder.uri.fsPath}"`)
122-
result.push(workspaceFolder.uri)
125+
result.push(workspaceFolder)
123126
}
124127
}
125128
return result
@@ -136,13 +139,13 @@ export class ExtensionConfigManager extends EventEmitter implements IExtensionCo
136139

137140
public removeWdioConfig(configPath: string) {
138141
const normalizedConfigPath = normalizePath(configPath)
139-
const result: vscode.Uri[] = []
142+
const result: vscode.WorkspaceFolder[] = []
140143
const workspaceFolders = this.getWorkspaces()
141144
for (const workspaceFolder of workspaceFolders) {
142145
const workspaceInfo = this._workspaceConfigMap.get(workspaceFolder)
143146
if (workspaceInfo && workspaceInfo.delete(normalizedConfigPath)) {
144147
log.debug(`Remove the config file "${normalizedConfigPath}" from "${workspaceFolder.uri.fsPath}"`)
145-
result.push(workspaceFolder.uri)
148+
result.push(workspaceFolder)
146149
}
147150
}
148151
this._wdioConfigPathSet.delete(normalizedConfigPath)

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ export class ConfigFileWatcher extends FileWatcherManager {
2626

2727
protected async handleFileCreate(uri: vscode.Uri): Promise<void> {
2828
const wdioConfigPath = normalizePath(convertUriToPath(uri))
29-
const workspaceUris = await this.configManager.addWdioConfig(wdioConfigPath)
29+
const workspaceFolders = await this.configManager.addWdioConfig(wdioConfigPath)
3030
await Promise.all(
31-
workspaceUris.map(
32-
async (workspaceUri) => await this.repositoryManager.addWdioConfig(workspaceUri, wdioConfigPath)
31+
workspaceFolders.map(
32+
async (workspaceFolder) => await this.repositoryManager.addWdioConfig(workspaceFolder, wdioConfigPath)
3333
)
3434
)
3535

@@ -50,9 +50,9 @@ export class ConfigFileWatcher extends FileWatcherManager {
5050

5151
protected async handleFileDelete(uri: vscode.Uri): Promise<void> {
5252
const wdioConfigPath = normalizePath(convertUriToPath(uri))
53-
const workspaceUris = this.configManager.removeWdioConfig(wdioConfigPath)
54-
for (const workspaceUri of workspaceUris) {
55-
this.repositoryManager.removeWdioConfig(workspaceUri, wdioConfigPath)
53+
const workspaceFolders = this.configManager.removeWdioConfig(wdioConfigPath)
54+
for (const workspaceFolder of workspaceFolders) {
55+
this.repositoryManager.removeWdioConfig(workspaceFolder, wdioConfigPath)
5656
await this.workerManager.reorganize(this.configManager.getWdioConfigPaths())
5757
}
5858
this.testfileWatcher.refreshWatchers()

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ describe('ExtensionConfigManager', () => {
6767
const customConfigFilePattern = ['custom/path/wdio.*.conf.ts']
6868
const customShowOutput = false
6969
const customLogLevel = 'warn'
70+
const customEnvFiles = ['.env', '.env.local']
71+
const customOverrideEnv = true
7072

7173
mockConfiguration.get.mockImplementation((key, defaultValue) => {
7274
if (key === 'configFilePattern') {
@@ -78,6 +80,12 @@ describe('ExtensionConfigManager', () => {
7880
if (key === 'logLevel') {
7981
return customLogLevel
8082
}
83+
if (key === 'envFiles') {
84+
return customEnvFiles
85+
}
86+
if (key === 'overrideEnv') {
87+
return customOverrideEnv
88+
}
8189
return defaultValue
8290
})
8391

@@ -88,6 +96,8 @@ describe('ExtensionConfigManager', () => {
8896
expect(instance.globalConfig).toEqual({
8997
configFilePattern: customConfigFilePattern,
9098
nodeExecutable: undefined,
99+
envFiles: customEnvFiles,
100+
overrideEnv: customOverrideEnv,
91101
showOutput: customShowOutput,
92102
logLevel: customLogLevel,
93103
workerIdleTimeout: 600,

0 commit comments

Comments
 (0)