@wdio/cli 8.11.3 → 8.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/index.js +2 -2
- package/build/commands/config.d.ts.map +1 -1
- package/build/commands/config.js +2 -1
- package/build/commands/run.d.ts.map +1 -1
- package/build/commands/run.js +3 -2
- package/build/constants.d.ts +119 -56
- package/build/constants.d.ts.map +1 -1
- package/build/constants.js +110 -42
- package/build/templates/exampleFiles/cucumber/step_definitions/steps.js.ejs +6 -6
- package/build/templates/exampleFiles/mochaJasmine/test.e2e.js.ejs +11 -0
- package/build/templates/exampleFiles/pageobjects/login.page.js.ejs +9 -9
- package/build/templates/exampleFiles/pageobjects/page.js.ejs +2 -2
- package/build/templates/exampleFiles/pageobjects/secure.page.js.ejs +5 -5
- package/build/templates/snippets/capabilities.ejs +46 -0
- package/build/templates/snippets/electronTest.js.ejs +9 -0
- package/build/templates/snippets/macosTest.js.ejs +11 -0
- package/build/templates/snippets/services.ejs +18 -0
- package/build/templates/snippets/testWithPO.js.ejs +20 -0
- package/build/templates/snippets/testWithoutPO.js.ejs +16 -0
- package/build/templates/snippets/vscodeTest.js.ejs +9 -0
- package/build/templates/wdio.conf.tpl.ejs +23 -29
- package/build/types.d.ts +7 -2
- package/build/types.d.ts.map +1 -1
- package/build/utils.d.ts.map +1 -1
- package/build/utils.js +18 -11
- package/package.json +2 -2
- package/build/templates/exampleFiles/jasmine/example.e2e.js.ejs +0 -42
- package/build/templates/exampleFiles/mocha/example.e2e.js.ejs +0 -42
- /package/build/templates/{afterTest.ejs → snippets/afterTest.ejs} +0 -0
- /package/build/templates/{reporters.ejs → snippets/reporters.ejs} +0 -0
package/build/constants.js
CHANGED
|
@@ -58,8 +58,11 @@ export const COMPILER_OPTIONS = {
|
|
|
58
58
|
*/
|
|
59
59
|
export const SUPPORTED_PACKAGES = {
|
|
60
60
|
runner: [
|
|
61
|
-
{ name: '
|
|
62
|
-
{ name: '
|
|
61
|
+
{ name: 'E2E Testing - of Web or Mobile Applications', value: '@wdio/local-runner$--$local$--$e2e' },
|
|
62
|
+
{ name: 'Component or Unit Testing - in the browser\n > https://webdriver.io/docs/component-testing', value: '@wdio/browser-runner$--$browser$--$component' },
|
|
63
|
+
{ name: 'Desktop Testing - of Electron Applications\n > https://webdriver.io/docs/desktop-testing/electron', value: '@wdio/local-runner$--$local$--$electron' },
|
|
64
|
+
{ name: 'Desktop Testing - of MacOS Applications\n > https://webdriver.io/docs/desktop-testing/macos', value: '@wdio/local-runner$--$local$--$macos' },
|
|
65
|
+
{ name: 'VS Code Extension Testing\n > https://webdriver.io/docs/vscode-extension-testing', value: '@wdio/local-runner$--$local$--$vscode' }
|
|
63
66
|
],
|
|
64
67
|
framework: [
|
|
65
68
|
{ name: 'Mocha (https://mochajs.org/)', value: '@wdio/mocha-framework$--$mocha' },
|
|
@@ -99,17 +102,18 @@ export const SUPPORTED_PACKAGES = {
|
|
|
99
102
|
{ name: 'edgedriver', value: 'wdio-edgedriver-service$--$edgedriver' },
|
|
100
103
|
{ name: 'safaridriver', value: 'wdio-safaridriver-service$--$safaridriver' },
|
|
101
104
|
// internal
|
|
102
|
-
{ name: '
|
|
103
|
-
{ name: '
|
|
104
|
-
{ name: '
|
|
105
|
-
{ name: 'electron', value: 'wdio-electron-service$--$electron' },
|
|
105
|
+
{ name: 'firefox-profile', value: '@wdio/firefox-profile-service$--$firefox-profile' },
|
|
106
|
+
{ name: 'gmail', value: '@wdio/gmail-service$--$gmail' },
|
|
107
|
+
{ name: 'vite', value: 'wdio-vite-service$--$vite' },
|
|
106
108
|
{ name: 'devtools', value: '@wdio/devtools-service$--$devtools' },
|
|
107
109
|
{ name: 'sauce', value: '@wdio/sauce-service$--$sauce' },
|
|
108
110
|
{ name: 'testingbot', value: '@wdio/testingbot-service$--$testingbot' },
|
|
109
111
|
{ name: 'crossbrowsertesting', value: '@wdio/crossbrowsertesting-service$--$crossbrowsertesting' },
|
|
110
112
|
{ name: 'browserstack', value: '@wdio/browserstack-service$--$browserstack' },
|
|
111
|
-
{ name: '
|
|
112
|
-
{ name: '
|
|
113
|
+
{ name: 'vscode', value: 'wdio-vscode-service$--$vscode' },
|
|
114
|
+
{ name: 'electron', value: 'wdio-electron-service$--$electron' },
|
|
115
|
+
{ name: 'appium', value: '@wdio/appium-service$--$appium' },
|
|
116
|
+
{ name: 'selenium-standalone', value: '@wdio/selenium-standalone-service$--$selenium-standalone' },
|
|
113
117
|
// external
|
|
114
118
|
{ name: 'eslinter-service', value: 'wdio-eslinter-service$--$eslinter' },
|
|
115
119
|
{ name: 'lambdatest', value: 'wdio-lambdatest-service$--$lambdatest' },
|
|
@@ -174,12 +178,30 @@ export const REGION_OPTION = [
|
|
|
174
178
|
'eu',
|
|
175
179
|
'apac'
|
|
176
180
|
];
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
181
|
+
export const E2E_ENVIRONMENTS = [
|
|
182
|
+
{ name: 'Web - web applications in the browser', value: 'web' },
|
|
183
|
+
{ name: 'Mobile - native, hybrid and mobile web apps, on Android or iOS', value: 'mobile' }
|
|
184
|
+
];
|
|
185
|
+
export const MOBILE_ENVIRONMENTS = [
|
|
186
|
+
{ name: 'Android - native, hybrid and mobile web apps, tested on emulators and real devices\n > using UiAutomator2 (https://www.npmjs.com/package/appium-uiautomator2-driver)', value: 'android' },
|
|
187
|
+
{ name: 'iOS - applications on iOS, iPadOS, and tvOS\n > using XCTest (https://appium.github.io/appium-xcuitest-driver)', value: 'ios' }
|
|
188
|
+
];
|
|
189
|
+
export const BROWSER_ENVIRONMENTS = [
|
|
190
|
+
{ name: 'Chrome', value: 'chrome', driver: 'chromedriver' },
|
|
191
|
+
{ name: 'Firefox', value: 'firefox', driver: 'geckodriver' },
|
|
192
|
+
{ name: 'Safari', value: 'safari', driver: 'safaridriver' },
|
|
193
|
+
{ name: 'Microsoft Edge', value: 'MicrosoftEdge', driver: 'edgedriver' }
|
|
194
|
+
];
|
|
180
195
|
function isBrowserRunner(answers) {
|
|
181
196
|
return answers.runner === SUPPORTED_PACKAGES.runner[1].value;
|
|
182
197
|
}
|
|
198
|
+
function getTestingPurpose(answers) {
|
|
199
|
+
return convertPackageHashToObject(answers.runner).purpose;
|
|
200
|
+
}
|
|
201
|
+
function getBrowserDriver(browserName) {
|
|
202
|
+
const driverName = BROWSER_ENVIRONMENTS.find((browser) => browser.value === browserName)?.driver;
|
|
203
|
+
return SUPPORTED_PACKAGES.service.find((svc) => svc.name === driverName)?.value;
|
|
204
|
+
}
|
|
183
205
|
function selectDefaultService(serviceName) {
|
|
184
206
|
return [SUPPORTED_PACKAGES.service.find(
|
|
185
207
|
/* istanbul ignore next */
|
|
@@ -193,10 +215,8 @@ function prioServiceOrderFor(serviceName) {
|
|
|
193
215
|
export const QUESTIONNAIRE = [{
|
|
194
216
|
type: 'list',
|
|
195
217
|
name: 'runner',
|
|
196
|
-
message: '
|
|
197
|
-
choices: SUPPORTED_PACKAGES.runner
|
|
198
|
-
// only ask if there are more than 1 runner to pick from
|
|
199
|
-
when: /* istanbul ignore next */ () => SUPPORTED_PACKAGES.runner.length > 1
|
|
218
|
+
message: 'What type of testing would you like to do?',
|
|
219
|
+
choices: SUPPORTED_PACKAGES.runner
|
|
200
220
|
}, {
|
|
201
221
|
type: 'list',
|
|
202
222
|
name: 'preset',
|
|
@@ -215,38 +235,52 @@ export const QUESTIONNAIRE = [{
|
|
|
215
235
|
* Only show if Testing Library has an add-on for framework
|
|
216
236
|
*/
|
|
217
237
|
answers.preset && TESTING_LIBRARY_PACKAGES[convertPackageHashToObject(answers.preset).short])
|
|
238
|
+
}, {
|
|
239
|
+
type: 'input',
|
|
240
|
+
name: 'appPath',
|
|
241
|
+
message: 'What is the path to your compiled Electron app?',
|
|
242
|
+
default: './dist',
|
|
243
|
+
when: /* istanbul ignore next */ (answers) => getTestingPurpose(answers) === 'electron'
|
|
218
244
|
}, {
|
|
219
245
|
type: 'list',
|
|
220
246
|
name: 'backend',
|
|
221
247
|
message: 'Where is your automation backend located?',
|
|
222
|
-
choices:
|
|
223
|
-
|
|
224
|
-
* browser runner currently supports only local testing
|
|
225
|
-
* until we have tunnel support for other cloud vendors
|
|
226
|
-
*/
|
|
227
|
-
if (isBrowserRunner(answers)) {
|
|
228
|
-
return BACKEND_CHOICES.slice(0, 1);
|
|
229
|
-
}
|
|
230
|
-
return BACKEND_CHOICES;
|
|
231
|
-
}
|
|
248
|
+
choices: BACKEND_CHOICES,
|
|
249
|
+
when: /* instanbul ignore next */ (answers) => getTestingPurpose(answers) === 'e2e'
|
|
232
250
|
}, {
|
|
233
|
-
type: '
|
|
234
|
-
name: '
|
|
235
|
-
message: '
|
|
236
|
-
|
|
237
|
-
|
|
251
|
+
type: 'list',
|
|
252
|
+
name: 'e2eEnvironment',
|
|
253
|
+
message: 'Which environment you would like to automate?',
|
|
254
|
+
choices: E2E_ENVIRONMENTS,
|
|
255
|
+
default: 'web',
|
|
256
|
+
when: /* istanbul ignore next */ (answers) => (getTestingPurpose(answers) === 'e2e' &&
|
|
238
257
|
answers.backend === BACKEND_CHOICES[0])
|
|
258
|
+
}, {
|
|
259
|
+
type: 'list',
|
|
260
|
+
name: 'mobileEnvironment',
|
|
261
|
+
message: 'Which mobile environment you\'ld like to automate?',
|
|
262
|
+
choices: MOBILE_ENVIRONMENTS,
|
|
263
|
+
when: /* instanbul ignore next */ (answers) => (getTestingPurpose(answers) === 'e2e' &&
|
|
264
|
+
answers.e2eEnvironment === 'mobile')
|
|
265
|
+
}, {
|
|
266
|
+
type: 'checkbox',
|
|
267
|
+
name: 'browserEnvironment',
|
|
268
|
+
message: 'With which browser should we start?',
|
|
269
|
+
choices: BROWSER_ENVIRONMENTS,
|
|
270
|
+
default: ['chrome'],
|
|
271
|
+
when: /* instanbul ignore next */ (answers) => (getTestingPurpose(answers) === 'e2e' &&
|
|
272
|
+
answers.e2eEnvironment === 'web')
|
|
239
273
|
}, {
|
|
240
274
|
type: 'input',
|
|
241
275
|
name: 'hostname',
|
|
242
276
|
message: 'What is the host address of that cloud service?',
|
|
243
|
-
when: /* istanbul ignore next */ (answers) => answers.backend.
|
|
277
|
+
when: /* istanbul ignore next */ (answers) => answers.backend && answers.backend.indexOf('different service') > -1
|
|
244
278
|
}, {
|
|
245
279
|
type: 'input',
|
|
246
280
|
name: 'port',
|
|
247
281
|
message: 'What is the port on which that service is running?',
|
|
248
282
|
default: '80',
|
|
249
|
-
when: /* istanbul ignore next */ (answers) => answers.backend.
|
|
283
|
+
when: /* istanbul ignore next */ (answers) => answers.backend && answers.backend.indexOf('different service') > -1
|
|
250
284
|
}, {
|
|
251
285
|
type: 'input',
|
|
252
286
|
name: 'expEnvAccessKey',
|
|
@@ -279,14 +313,14 @@ export const QUESTIONNAIRE = [{
|
|
|
279
313
|
name: 'env_user',
|
|
280
314
|
message: 'Environment variable for username',
|
|
281
315
|
default: 'LT_USERNAME',
|
|
282
|
-
when: /* istanbul ignore next */ (answers) => (answers.backend.
|
|
316
|
+
when: /* istanbul ignore next */ (answers) => (answers.backend && answers.backend.indexOf('LambdaTest') > -1 &&
|
|
283
317
|
answers.hostname.indexOf('lambdatest.com') > -1)
|
|
284
318
|
}, {
|
|
285
319
|
type: 'input',
|
|
286
320
|
name: 'env_key',
|
|
287
321
|
message: 'Environment variable for access key',
|
|
288
322
|
default: 'LT_ACCESS_KEY',
|
|
289
|
-
when: /* istanbul ignore next */ (answers) => (answers.backend.
|
|
323
|
+
when: /* istanbul ignore next */ (answers) => (answers.backend && answers.backend.indexOf('LambdaTest') > -1 &&
|
|
290
324
|
answers.hostname.indexOf('lambdatest.com') > -1)
|
|
291
325
|
}, {
|
|
292
326
|
type: 'input',
|
|
@@ -323,19 +357,19 @@ export const QUESTIONNAIRE = [{
|
|
|
323
357
|
name: 'hostname',
|
|
324
358
|
message: 'What is the IP or URI to your Selenium standalone or grid server?',
|
|
325
359
|
default: 'localhost',
|
|
326
|
-
when: /* istanbul ignore next */ (answers) => answers.backend.toString().indexOf('own Selenium cloud') > -1
|
|
360
|
+
when: /* istanbul ignore next */ (answers) => answers.backend && answers.backend.toString().indexOf('own Selenium cloud') > -1
|
|
327
361
|
}, {
|
|
328
362
|
type: 'input',
|
|
329
363
|
name: 'port',
|
|
330
364
|
message: 'What is the port which your Selenium standalone or grid server is running on?',
|
|
331
365
|
default: '4444',
|
|
332
|
-
when: /* istanbul ignore next */ (answers) => answers.backend.toString().indexOf('own Selenium cloud') > -1
|
|
366
|
+
when: /* istanbul ignore next */ (answers) => answers.backend && answers.backend.toString().indexOf('own Selenium cloud') > -1
|
|
333
367
|
}, {
|
|
334
368
|
type: 'input',
|
|
335
369
|
name: 'path',
|
|
336
370
|
message: 'What is the path to your browser driver or grid server?',
|
|
337
371
|
default: '/',
|
|
338
|
-
when: /* istanbul ignore next */ (answers) => answers.backend.toString().indexOf('own Selenium cloud') > -1
|
|
372
|
+
when: /* istanbul ignore next */ (answers) => answers.backend && answers.backend.toString().indexOf('own Selenium cloud') > -1
|
|
339
373
|
}, {
|
|
340
374
|
type: 'list',
|
|
341
375
|
name: 'framework',
|
|
@@ -359,7 +393,16 @@ export const QUESTIONNAIRE = [{
|
|
|
359
393
|
type: 'confirm',
|
|
360
394
|
name: 'generateTestFiles',
|
|
361
395
|
message: 'Do you want WebdriverIO to autogenerate some test files?',
|
|
362
|
-
default: true
|
|
396
|
+
default: true,
|
|
397
|
+
when: /* istanbul ignore next */ (answers) => {
|
|
398
|
+
/**
|
|
399
|
+
* we only have examples for Mocha and Jasmine
|
|
400
|
+
*/
|
|
401
|
+
if (['vscode', 'electron', 'macos'].includes(getTestingPurpose(answers)) && answers.framework.includes('cucumber')) {
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
363
406
|
}, {
|
|
364
407
|
type: 'input',
|
|
365
408
|
name: 'specs',
|
|
@@ -390,7 +433,12 @@ export const QUESTIONNAIRE = [{
|
|
|
390
433
|
/**
|
|
391
434
|
* page objects aren't common for component testing
|
|
392
435
|
*/
|
|
393
|
-
!isBrowserRunner(answers)
|
|
436
|
+
!isBrowserRunner(answers) &&
|
|
437
|
+
/**
|
|
438
|
+
* and also not needed when running VS Code tests since the service comes with
|
|
439
|
+
* its own page object implementation, nor when running Electron or MacOS tests
|
|
440
|
+
*/
|
|
441
|
+
!['vscode', 'electron', 'macos'].includes(getTestingPurpose(answers)))
|
|
394
442
|
}, {
|
|
395
443
|
type: 'input',
|
|
396
444
|
name: 'pages',
|
|
@@ -426,9 +474,18 @@ export const QUESTIONNAIRE = [{
|
|
|
426
474
|
else if (answers.backend === BACKEND_CHOICES[2]) {
|
|
427
475
|
return prioServiceOrderFor('sauce');
|
|
428
476
|
}
|
|
429
|
-
else if (answers.
|
|
477
|
+
else if (answers.e2eEnvironment === 'mobile') {
|
|
430
478
|
return prioServiceOrderFor('appium');
|
|
431
479
|
}
|
|
480
|
+
else if (getTestingPurpose(answers) === 'vscode') {
|
|
481
|
+
return [SUPPORTED_PACKAGES.service.find(({ name }) => name === 'vscode')];
|
|
482
|
+
}
|
|
483
|
+
else if (getTestingPurpose(answers) === 'electron') {
|
|
484
|
+
return [SUPPORTED_PACKAGES.service.find(({ name }) => name === 'electron')];
|
|
485
|
+
}
|
|
486
|
+
else if (getTestingPurpose(answers) === 'macos') {
|
|
487
|
+
return [SUPPORTED_PACKAGES.service.find(({ name }) => name === 'appium')];
|
|
488
|
+
}
|
|
432
489
|
return SUPPORTED_PACKAGES.service;
|
|
433
490
|
},
|
|
434
491
|
// @ts-ignore
|
|
@@ -439,9 +496,18 @@ export const QUESTIONNAIRE = [{
|
|
|
439
496
|
else if (answers.backend === BACKEND_CHOICES[2]) {
|
|
440
497
|
return selectDefaultService('sauce');
|
|
441
498
|
}
|
|
442
|
-
else if (answers.
|
|
499
|
+
else if (answers.browserEnvironment && answers.browserEnvironment.length) {
|
|
500
|
+
return answers.browserEnvironment.map((browserName) => getBrowserDriver(browserName));
|
|
501
|
+
}
|
|
502
|
+
else if (answers.e2eEnvironment === 'mobile' || getTestingPurpose(answers) === 'macos') {
|
|
443
503
|
return selectDefaultService('appium');
|
|
444
504
|
}
|
|
505
|
+
else if (getTestingPurpose(answers) === 'vscode') {
|
|
506
|
+
return selectDefaultService('vscode');
|
|
507
|
+
}
|
|
508
|
+
else if (getTestingPurpose(answers) === 'electron') {
|
|
509
|
+
return selectDefaultService('electron');
|
|
510
|
+
}
|
|
445
511
|
return selectDefaultService('chromedriver');
|
|
446
512
|
},
|
|
447
513
|
validate: /* istanbul ignore next */ (answers) => validateServiceAnswers(answers)
|
|
@@ -473,7 +539,9 @@ export const QUESTIONNAIRE = [{
|
|
|
473
539
|
// unit and component testing in the browser
|
|
474
540
|
!isBrowserRunner(answers) &&
|
|
475
541
|
// mobile testing with Appium
|
|
476
|
-
|
|
542
|
+
answers.e2eEnvironment !== 'mobile' &&
|
|
543
|
+
// nor for VS Code, Electron or MacOS testing
|
|
544
|
+
!['vscode', 'electron', 'macos'].includes(getTestingPurpose(answers)))
|
|
477
545
|
}, {
|
|
478
546
|
type: 'confirm',
|
|
479
547
|
name: 'npmInstall',
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
<%- isUsingTypeScript || esmSupport
|
|
1
|
+
<%- answers.isUsingTypeScript || answers.esmSupport
|
|
2
2
|
? "import { Given, When, Then } from '@wdio/cucumber-framework';"
|
|
3
3
|
: "const { Given, When, Then } = require('@wdio/cucumber-framework');" %>
|
|
4
4
|
<%
|
|
5
5
|
/**
|
|
6
6
|
* step definition without page objects
|
|
7
7
|
*/
|
|
8
|
-
if (usePageObjects) { %>
|
|
9
|
-
<%- isUsingTypeScript || esmSupport
|
|
10
|
-
? `import LoginPage from '${relativePath}/login.page${esmSupport ? '.js' : ''}';`
|
|
8
|
+
if (answers.usePageObjects) { %>
|
|
9
|
+
<%- answers.isUsingTypeScript || answers.esmSupport
|
|
10
|
+
? `import LoginPage from '${relativePath}/login.page${answers.esmSupport ? '.js' : ''}';`
|
|
11
11
|
: `const LoginPage = require('${relativePath}/login.page');` %>
|
|
12
|
-
<%- isUsingTypeScript || esmSupport
|
|
13
|
-
? `import SecurePage from '${relativePath}/secure.page${esmSupport ? '.js' : ''}';`
|
|
12
|
+
<%- answers.isUsingTypeScript || answers.esmSupport
|
|
13
|
+
? `import SecurePage from '${relativePath}/secure.page${answers.esmSupport ? '.js' : ''}';`
|
|
14
14
|
: `const SecurePage = require('${relativePath}/secure.page');` %>
|
|
15
15
|
|
|
16
16
|
const pages = {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<% if (answers.purpose === 'vscode') {
|
|
2
|
+
%><%- include('../../snippets/vscodeTest.js.ejs', { answers }) %><%
|
|
3
|
+
} else if (answers.purpose === 'electron') {
|
|
4
|
+
%><%- include('../../snippets/electronTest.js.ejs', { answers }) %><%
|
|
5
|
+
} else if (answers.purpose === 'macos') {
|
|
6
|
+
%><%- include('../../snippets/macosTest.js.ejs', { answers }) %><%
|
|
7
|
+
} else if (answers.usePageObjects) {
|
|
8
|
+
%><%- include('../../snippets/testWithPO.js.ejs', { answers }) %><%
|
|
9
|
+
} else if (!answers.usePageObjects) {
|
|
10
|
+
%><%- include('../../snippets/testWithoutPO.js.ejs', { answers }) %><%
|
|
11
|
+
} %>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
<%- isUsingTypeScript ? "import { ChainablePromiseElement } from 'webdriverio';" : "" %>
|
|
1
|
+
<%- answers.isUsingTypeScript ? "import { ChainablePromiseElement } from 'webdriverio';" : "" %>
|
|
2
2
|
|
|
3
|
-
<%- isUsingTypeScript || esmSupport
|
|
4
|
-
? `import Page from './page${esmSupport ? '.js' : ''}';`
|
|
3
|
+
<%- answers.isUsingTypeScript || answers.esmSupport
|
|
4
|
+
? `import Page from './page${answers.esmSupport ? '.js' : ''}';`
|
|
5
5
|
: "const Page = require('./page');" %>
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -11,15 +11,15 @@ class LoginPage extends Page {
|
|
|
11
11
|
/**
|
|
12
12
|
* define selectors using getter methods
|
|
13
13
|
*/
|
|
14
|
-
<%- isUsingTypeScript ? "public " : "" %>get inputUsername () {
|
|
14
|
+
<%- answers.isUsingTypeScript ? "public " : "" %>get inputUsername () {
|
|
15
15
|
return $('#username');
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
<%- isUsingTypeScript ? "public " : "" %>get inputPassword () {
|
|
18
|
+
<%- answers.isUsingTypeScript ? "public " : "" %>get inputPassword () {
|
|
19
19
|
return $('#password');
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
<%- isUsingTypeScript ? "public " : "" %>get btnSubmit () {
|
|
22
|
+
<%- answers.isUsingTypeScript ? "public " : "" %>get btnSubmit () {
|
|
23
23
|
return $('button[type="submit"]');
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -27,7 +27,7 @@ class LoginPage extends Page {
|
|
|
27
27
|
* a method to encapsule automation code to interact with the page
|
|
28
28
|
* e.g. to login using username and password
|
|
29
29
|
*/
|
|
30
|
-
<%- isUsingTypeScript ? "public " : "" %>async login (username<%- isUsingTypeScript ? ": string": "" %>, password<%- isUsingTypeScript ? ": string": "" %>) {
|
|
30
|
+
<%- answers.isUsingTypeScript ? "public " : "" %>async login (username<%- answers.isUsingTypeScript ? ": string": "" %>, password<%- answers.isUsingTypeScript ? ": string": "" %>) {
|
|
31
31
|
await this.inputUsername.setValue(username);
|
|
32
32
|
await this.inputPassword.setValue(password);
|
|
33
33
|
await this.btnSubmit.click();
|
|
@@ -36,9 +36,9 @@ class LoginPage extends Page {
|
|
|
36
36
|
/**
|
|
37
37
|
* overwrite specific options to adapt it to page object
|
|
38
38
|
*/
|
|
39
|
-
<%- isUsingTypeScript ? "public " : "" %>open () {
|
|
39
|
+
<%- answers.isUsingTypeScript ? "public " : "" %>open () {
|
|
40
40
|
return super.open('login');
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
<%- isUsingTypeScript || esmSupport ? "export default": "module.exports =" %> new LoginPage();
|
|
44
|
+
<%- answers.isUsingTypeScript || answers.esmSupport ? "export default": "module.exports =" %> new LoginPage();
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* main page object containing all methods, selectors and functionality
|
|
3
3
|
* that is shared across all page objects
|
|
4
4
|
*/
|
|
5
|
-
<%- isUsingTypeScript || esmSupport ? "export default" : "module.exports =" %> class Page {
|
|
5
|
+
<%- answers.isUsingTypeScript || answers.esmSupport ? "export default" : "module.exports =" %> class Page {
|
|
6
6
|
/**
|
|
7
7
|
* Opens a sub page of the page
|
|
8
8
|
* @param path path of the sub page (e.g. /path/to/page.html)
|
|
9
9
|
*/
|
|
10
|
-
<%- isUsingTypeScript ? "public " : "" %>open (path<%- isUsingTypeScript ? ": string" : "" %>) {
|
|
10
|
+
<%- answers.isUsingTypeScript ? "public " : "" %>open (path<%- answers.isUsingTypeScript ? ": string" : "" %>) {
|
|
11
11
|
return browser.url(`https://the-internet.herokuapp.com/${path}`)
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
<%- isUsingTypeScript ? "import { ChainablePromiseElement } from 'webdriverio';" : "" %>
|
|
1
|
+
<%- answers.isUsingTypeScript ? "import { ChainablePromiseElement } from 'webdriverio';" : "" %>
|
|
2
2
|
|
|
3
|
-
<%- isUsingTypeScript || esmSupport
|
|
4
|
-
? `import Page from './page${esmSupport ? '.js' : ''}';`
|
|
3
|
+
<%- answers.isUsingTypeScript || answers.esmSupport
|
|
4
|
+
? `import Page from './page${answers.esmSupport ? '.js' : ''}';`
|
|
5
5
|
: "const Page = require('./page');" %>
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -11,9 +11,9 @@ class SecurePage extends Page {
|
|
|
11
11
|
/**
|
|
12
12
|
* define selectors using getter methods
|
|
13
13
|
*/
|
|
14
|
-
<%- isUsingTypeScript ? "public " : "" %>get flashAlert () {
|
|
14
|
+
<%- answers.isUsingTypeScript ? "public " : "" %>get flashAlert () {
|
|
15
15
|
return $('#flash');
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
<%- isUsingTypeScript || esmSupport ? "export default": "module.exports =" %> new SecurePage();
|
|
19
|
+
<%- answers.isUsingTypeScript || answers.esmSupport ? "export default": "module.exports =" %> new SecurePage();
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
capabilities: [{<%
|
|
2
|
+
if (answers.expEnvAccessKey) { %>
|
|
3
|
+
// Experitest Access Key
|
|
4
|
+
// get more information at https://docs.experitest.com/display/TE/Obtaining+Access+Key
|
|
5
|
+
'experitest:accessKey': '<%- answers.expEnvAccessKey %>',<%
|
|
6
|
+
}
|
|
7
|
+
if (answers.browserEnvironment && answers.browserEnvironment.length) { %>
|
|
8
|
+
<%- answers.browserEnvironment.map((browserName) => `browserName: '${browserName}'`).join('\n }, {\n ') %><%
|
|
9
|
+
} else if (answers.mobileEnvironment === 'android') { %>
|
|
10
|
+
// capabilities for local Appium web tests on an Android Emulator
|
|
11
|
+
platformName: 'Android',
|
|
12
|
+
browserName: 'Chrome',
|
|
13
|
+
'appium:deviceName': 'Android GoogleAPI Emulator',
|
|
14
|
+
'appium:platformVersion': '12.0',
|
|
15
|
+
'appium:automationName': 'UiAutomator2'<%
|
|
16
|
+
} else if (answers.mobileEnvironment === 'ios') { %>
|
|
17
|
+
// capabilities for local Appium web tests on iOS
|
|
18
|
+
platformName: 'iOS',
|
|
19
|
+
browserName: 'Safari',
|
|
20
|
+
'appium:deviceName': 'iPhone Simulator',
|
|
21
|
+
'appium:platformVersion': '16.4',
|
|
22
|
+
'appium:automationName': 'XCUITest'<%
|
|
23
|
+
} else if (answers.purpose === 'macos') { %>
|
|
24
|
+
platformName: 'Mac',
|
|
25
|
+
'appium:automationName': 'Mac2',
|
|
26
|
+
'appium:bundleId': '<%= answers.generateTestFiles ? 'com.apple.calculator' : '...' %>'<%
|
|
27
|
+
} else if (answers.purpose === 'vscode') { %>
|
|
28
|
+
browserName: 'vscode',
|
|
29
|
+
browserVersion: 'stable', // also possible: "insiders" or a specific version e.g. "1.80.0"
|
|
30
|
+
'wdio:vscodeOptions': {
|
|
31
|
+
// points to directory where extension package.json is located
|
|
32
|
+
extensionPath: __dirname,
|
|
33
|
+
// optional VS Code settings
|
|
34
|
+
userSettings: {
|
|
35
|
+
"editor.fontSize": 14
|
|
36
|
+
}
|
|
37
|
+
}<%
|
|
38
|
+
} else if (answers.purpose === 'electron') { %>
|
|
39
|
+
// no need to define any capabilities for local Electron web tests
|
|
40
|
+
// since service plugin takes care of setting everything up<%
|
|
41
|
+
} else {
|
|
42
|
+
%>
|
|
43
|
+
// capabilities for local browser web tests
|
|
44
|
+
browserName: 'chrome' // or "firefox", "microsoftedge", "safari"<%
|
|
45
|
+
} %>
|
|
46
|
+
}],
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { browser } from '@wdio/globals'
|
|
2
|
+
|
|
3
|
+
describe('Electron Testing', () => {
|
|
4
|
+
it('should print application metadata', async () => {
|
|
5
|
+
const appName = await browser.electron.app('getName')
|
|
6
|
+
const appVersion = await browser.electron.app('getVersion')
|
|
7
|
+
console.log('Testing Electron app:', appName, appVersion)
|
|
8
|
+
})
|
|
9
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { expect, $ } from '@wdio/globals'
|
|
2
|
+
|
|
3
|
+
describe('MacOS Testing', () => {
|
|
4
|
+
it('should calculate the meaning of life', async function () {
|
|
5
|
+
await $('//XCUIElementTypeButton[@label="seven"]').click()
|
|
6
|
+
await $('//XCUIElementTypeButton[@label="multiply"]').click()
|
|
7
|
+
await $('//XCUIElementTypeButton[@label="six"]').click()
|
|
8
|
+
await $('//XCUIElementTypeButton[@title="="]').click()
|
|
9
|
+
await expect($('//XCUIElementTypeStaticText[@label="main display"]')).toHaveText('42')
|
|
10
|
+
})
|
|
11
|
+
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
services: [<%- answers.services.map((service) => {
|
|
2
|
+
if (service === 'electron') {
|
|
3
|
+
return /*js*/`[
|
|
4
|
+
'electron',
|
|
5
|
+
{
|
|
6
|
+
appPath: '${answers.appPath}',
|
|
7
|
+
appName: productName,
|
|
8
|
+
appArgs: ['foo', 'bar=baz'],
|
|
9
|
+
chromedriver: {
|
|
10
|
+
logFileName: 'wdio-chromedriver.log',
|
|
11
|
+
},
|
|
12
|
+
electronVersion: '23.1.0',
|
|
13
|
+
}
|
|
14
|
+
]`
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return `'${service}'`
|
|
18
|
+
}) %>],
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* test with page objects
|
|
3
|
+
*/
|
|
4
|
+
<%- answers.isUsingTypeScript || answers.esmSupport
|
|
5
|
+
? `import LoginPage from '${answers.relativePath}/login.page${answers.esmSupport ? '.js' : ''}'`
|
|
6
|
+
: `const LoginPage = require('${answers.relativePath}/login.page')` %>
|
|
7
|
+
<%- answers.isUsingTypeScript || answers.esmSupport
|
|
8
|
+
? `import SecurePage from '${answers.relativePath}/secure.page${answers.esmSupport ? '.js' : ''}'`
|
|
9
|
+
: `const SecurePage = require('${answers.relativePath}/secure.page')` %>
|
|
10
|
+
|
|
11
|
+
describe('My Login application', () => {
|
|
12
|
+
it('should login with valid credentials', async () => {
|
|
13
|
+
await LoginPage.open()
|
|
14
|
+
|
|
15
|
+
await LoginPage.login('tomsmith', 'SuperSecretPassword!')
|
|
16
|
+
await expect(SecurePage.flashAlert).toBeExisting()
|
|
17
|
+
await expect(SecurePage.flashAlert).toHaveTextContaining(
|
|
18
|
+
'You logged into a secure area!')
|
|
19
|
+
})
|
|
20
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* test without page objects
|
|
3
|
+
*/
|
|
4
|
+
describe('My Login application', () => {
|
|
5
|
+
it('should login with valid credentials', async () => {
|
|
6
|
+
await browser.url(`https://the-internet.herokuapp.com/login`)
|
|
7
|
+
|
|
8
|
+
await $('#username').setValue('tomsmith')
|
|
9
|
+
await $('#password').setValue('SuperSecretPassword!')
|
|
10
|
+
await $('button[type="submit"]').click()
|
|
11
|
+
|
|
12
|
+
await expect($('#flash')).toBeExisting()
|
|
13
|
+
await expect($('#flash')).toHaveTextContaining(
|
|
14
|
+
'You logged into a secure area!')
|
|
15
|
+
})
|
|
16
|
+
})
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { browser } from '@wdio/globals'
|
|
2
|
+
|
|
3
|
+
describe('VS Code Extension Testing', () => {
|
|
4
|
+
it('should be able to load VSCode', async () => {
|
|
5
|
+
const workbench = await browser.getWorkbench()
|
|
6
|
+
expect(await workbench.getTitleBar().getTitle())
|
|
7
|
+
.toContain('[Extension Development Host]')
|
|
8
|
+
})
|
|
9
|
+
})
|
|
@@ -1,7 +1,20 @@
|
|
|
1
|
-
<%
|
|
1
|
+
<%
|
|
2
|
+
if (answers.purpose === 'electron') {
|
|
3
|
+
%>import fs from 'node:fs'
|
|
4
|
+
<% }
|
|
5
|
+
|
|
6
|
+
if (answers.isUsingTypeScript) {
|
|
2
7
|
%>import type { Options } from '@wdio/types'
|
|
8
|
+
<% }
|
|
9
|
+
|
|
10
|
+
if (answers.purpose === 'electron') { %>
|
|
11
|
+
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf-8'))
|
|
12
|
+
const productName = packageJson.build.productName
|
|
13
|
+
|
|
14
|
+
<% }
|
|
3
15
|
|
|
4
|
-
|
|
16
|
+
if (answers.isUsingTypeScript) {
|
|
17
|
+
%>export const config: Options.Testrunner = {<%
|
|
5
18
|
} else if (answers.esmSupport) {
|
|
6
19
|
%>export const config = {<%
|
|
7
20
|
} else {
|
|
@@ -35,16 +48,15 @@ export const config: Options.Testrunner = {<%
|
|
|
35
48
|
transpileOnly: true
|
|
36
49
|
}
|
|
37
50
|
},
|
|
38
|
-
<% }
|
|
39
|
-
|
|
51
|
+
<% }
|
|
52
|
+
if(answers.expEnvAccessKey){ %>
|
|
40
53
|
hostname: '<%- answers.expEnvHostname %>',
|
|
41
54
|
<% if (answers.expEnvPort === '443'){%>protocol: 'https',
|
|
42
55
|
<%} else if (answers.expEnvPort === '80'){%>protocol: 'http',
|
|
43
56
|
<%} else { %>protocol: '<%- answers.expEnvProtocol %>',<%}%>
|
|
44
57
|
port: <%- answers.expEnvPort %>,
|
|
45
58
|
path: '/wd/hub',
|
|
46
|
-
<% } else if(answers.hostname && answers.port) {
|
|
47
|
-
//
|
|
59
|
+
<% } else if(answers.hostname && answers.port) { %>//
|
|
48
60
|
// =====================
|
|
49
61
|
// Server Configurations
|
|
50
62
|
// =====================
|
|
@@ -126,25 +138,7 @@ export const config: Options.Testrunner = {<%
|
|
|
126
138
|
// Sauce Labs platform configurator - a great tool to configure your capabilities:
|
|
127
139
|
// https://saucelabs.com/platform/platform-configurator
|
|
128
140
|
//
|
|
129
|
-
capabilities
|
|
130
|
-
if (answers.expEnvAccessKey) { %>
|
|
131
|
-
// Experitest Access Key
|
|
132
|
-
// get more information at https://docs.experitest.com/display/TE/Obtaining+Access+Key
|
|
133
|
-
'experitest:accessKey': '<%- answers.expEnvAccessKey %>',<%
|
|
134
|
-
}
|
|
135
|
-
if (answers.setupMobileEnvironment) { %>
|
|
136
|
-
// capabilities for local Appium web tests on an Android Emulator
|
|
137
|
-
platformName: 'Android', // or "iOS"
|
|
138
|
-
browserName: 'Chrome', // or "Safari"
|
|
139
|
-
'appium:deviceName': 'Android GoogleAPI Emulator', // or "iPhone Simulator"
|
|
140
|
-
'appium:platformVersion': '12.0', // or "16.2" (for running iOS v16)
|
|
141
|
-
'appium:automationName': 'UiAutomator2' // or "XCUITest"<%
|
|
142
|
-
} else {
|
|
143
|
-
%>
|
|
144
|
-
// capabilities for local browser web tests
|
|
145
|
-
browserName: 'chrome' // or "firefox", "microsoftedge", "safari"<%
|
|
146
|
-
} %>
|
|
147
|
-
}],
|
|
141
|
+
<%- include('snippets/capabilities', { answers }) %>
|
|
148
142
|
//
|
|
149
143
|
// ===================
|
|
150
144
|
// Test Configurations
|
|
@@ -193,8 +187,8 @@ export const config: Options.Testrunner = {<%
|
|
|
193
187
|
// your test setup with almost no effort. Unlike plugins, they don't add new
|
|
194
188
|
// commands. Instead, they hook themselves up into the test process.
|
|
195
189
|
<% if(answers.services.length) {
|
|
196
|
-
|
|
197
|
-
|
|
190
|
+
%><%- include('snippets/services', { answers }) %><%
|
|
191
|
+
} else {
|
|
198
192
|
%>// services: [],
|
|
199
193
|
//<% } %>
|
|
200
194
|
// Framework you want to run your specs with.
|
|
@@ -214,7 +208,7 @@ export const config: Options.Testrunner = {<%
|
|
|
214
208
|
// Whether or not retried spec files should be retried immediately or deferred to the end of the queue
|
|
215
209
|
// specFileRetriesDeferred: false,
|
|
216
210
|
//
|
|
217
|
-
<%- include('reporters', { reporters: answers.reporters }) %>
|
|
211
|
+
<%- include('snippets/reporters', { reporters: answers.reporters }) %>
|
|
218
212
|
<% if(answers.framework === 'mocha') { %>
|
|
219
213
|
//
|
|
220
214
|
// Options to be passed to Mocha.
|
|
@@ -351,7 +345,7 @@ export const config: Options.Testrunner = {<%
|
|
|
351
345
|
*/
|
|
352
346
|
// afterHook: function (test, context, { error, result, duration, passed, retries }) {
|
|
353
347
|
// },
|
|
354
|
-
<%- include('afterTest', { reporters: answers.reporters }) %>
|
|
348
|
+
<%- include('snippets/afterTest', { reporters: answers.reporters }) %>
|
|
355
349
|
/**
|
|
356
350
|
* Hook that gets executed after the suite has ended
|
|
357
351
|
* @param {object} suite suite details
|