codeceptjs 3.6.4-beta.2 → 3.6.5-beta.1

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.
Files changed (92) hide show
  1. package/bin/codecept.js +84 -63
  2. package/lib/ai.js +47 -1
  3. package/lib/assert/empty.js +19 -19
  4. package/lib/assert/equal.js +32 -30
  5. package/lib/assert/error.js +14 -14
  6. package/lib/assert/include.js +42 -42
  7. package/lib/assert/throws.js +13 -11
  8. package/lib/assert/truth.js +17 -18
  9. package/lib/command/configMigrate.js +57 -52
  10. package/lib/command/definitions.js +88 -88
  11. package/lib/command/dryRun.js +65 -63
  12. package/lib/command/generate.js +191 -181
  13. package/lib/command/info.js +39 -37
  14. package/lib/command/init.js +289 -286
  15. package/lib/command/interactive.js +32 -32
  16. package/lib/command/list.js +26 -26
  17. package/lib/command/run-multiple.js +113 -93
  18. package/lib/command/run-rerun.js +22 -22
  19. package/lib/command/run-workers.js +63 -63
  20. package/lib/command/run.js +24 -26
  21. package/lib/command/utils.js +64 -63
  22. package/lib/data/context.js +60 -60
  23. package/lib/data/dataScenarioConfig.js +47 -47
  24. package/lib/data/dataTableArgument.js +29 -29
  25. package/lib/data/table.js +26 -20
  26. package/lib/helper/AI.js +114 -35
  27. package/lib/helper/ApiDataFactory.js +72 -69
  28. package/lib/helper/Appium.js +409 -379
  29. package/lib/helper/ExpectHelper.js +214 -248
  30. package/lib/helper/FileSystem.js +77 -78
  31. package/lib/helper/GraphQL.js +44 -43
  32. package/lib/helper/GraphQLDataFactory.js +49 -50
  33. package/lib/helper/JSONResponse.js +64 -62
  34. package/lib/helper/Mochawesome.js +28 -28
  35. package/lib/helper/MockServer.js +12 -12
  36. package/lib/helper/Nightmare.js +664 -572
  37. package/lib/helper/Playwright.js +1320 -1211
  38. package/lib/helper/Protractor.js +663 -629
  39. package/lib/helper/Puppeteer.js +1232 -1124
  40. package/lib/helper/REST.js +115 -69
  41. package/lib/helper/TestCafe.js +490 -491
  42. package/lib/helper/WebDriver.js +1294 -1156
  43. package/lib/history.js +16 -3
  44. package/lib/interfaces/bdd.js +38 -51
  45. package/lib/interfaces/featureConfig.js +19 -19
  46. package/lib/interfaces/gherkin.js +122 -111
  47. package/lib/interfaces/scenarioConfig.js +29 -29
  48. package/lib/listener/artifacts.js +9 -9
  49. package/lib/listener/config.js +24 -23
  50. package/lib/listener/exit.js +12 -12
  51. package/lib/listener/helpers.js +42 -42
  52. package/lib/listener/mocha.js +11 -11
  53. package/lib/listener/retry.js +32 -30
  54. package/lib/listener/steps.js +50 -51
  55. package/lib/listener/timeout.js +53 -53
  56. package/lib/pause.js +17 -3
  57. package/lib/plugin/allure.js +14 -14
  58. package/lib/plugin/autoDelay.js +29 -36
  59. package/lib/plugin/autoLogin.js +70 -66
  60. package/lib/plugin/commentStep.js +18 -18
  61. package/lib/plugin/coverage.js +92 -77
  62. package/lib/plugin/customLocator.js +20 -19
  63. package/lib/plugin/debugErrors.js +24 -24
  64. package/lib/plugin/eachElement.js +37 -37
  65. package/lib/plugin/fakerTransform.js +6 -6
  66. package/lib/plugin/heal.js +66 -63
  67. package/lib/plugin/pauseOnFail.js +10 -10
  68. package/lib/plugin/retryFailedStep.js +31 -38
  69. package/lib/plugin/retryTo.js +28 -28
  70. package/lib/plugin/screenshotOnFail.js +107 -86
  71. package/lib/plugin/selenoid.js +131 -117
  72. package/lib/plugin/standardActingHelpers.js +2 -8
  73. package/lib/plugin/stepByStepReport.js +102 -92
  74. package/lib/plugin/stepTimeout.js +23 -22
  75. package/lib/plugin/subtitles.js +34 -34
  76. package/lib/plugin/tryTo.js +39 -29
  77. package/lib/plugin/wdio.js +77 -72
  78. package/lib/template/heal.js +11 -14
  79. package/package.json +5 -3
  80. package/translations/de-DE.js +1 -1
  81. package/translations/fr-FR.js +1 -1
  82. package/translations/index.js +9 -9
  83. package/translations/it-IT.js +1 -1
  84. package/translations/ja-JP.js +1 -1
  85. package/translations/pl-PL.js +1 -1
  86. package/translations/pt-BR.js +1 -1
  87. package/translations/ru-RU.js +1 -1
  88. package/translations/zh-CN.js +1 -1
  89. package/translations/zh-TW.js +1 -1
  90. package/typings/index.d.ts +42 -19
  91. package/typings/promiseBasedTypes.d.ts +280 -1
  92. package/typings/types.d.ts +76 -1
@@ -1,14 +1,14 @@
1
- const debug = require('debug')('codeceptjs:heal');
2
- const colors = require('chalk');
3
- const recorder = require('../recorder');
4
- const event = require('../event');
5
- const output = require('../output');
6
- const heal = require('../heal');
7
- const store = require('../store');
1
+ const debug = require('debug')('codeceptjs:heal')
2
+ const colors = require('chalk')
3
+ const recorder = require('../recorder')
4
+ const event = require('../event')
5
+ const output = require('../output')
6
+ const heal = require('../heal')
7
+ const store = require('../store')
8
8
 
9
9
  const defaultConfig = {
10
10
  healLimit: 2,
11
- };
11
+ }
12
12
 
13
13
  /**
14
14
  * Self-healing tests with AI.
@@ -31,88 +31,91 @@ const defaultConfig = {
31
31
  module.exports = function (config = {}) {
32
32
  if (store.debugMode && !process.env.DEBUG) {
33
33
  event.dispatcher.on(event.test.failed, () => {
34
- output.plugin('heal', 'Healing is disabled in --debug mode, use DEBUG="codeceptjs:heal" to enable it in debug mode');
35
- });
36
- return;
34
+ output.plugin(
35
+ 'heal',
36
+ 'Healing is disabled in --debug mode, use DEBUG="codeceptjs:heal" to enable it in debug mode',
37
+ )
38
+ })
39
+ return
37
40
  }
38
41
 
39
- let currentTest = null;
40
- let currentStep = null;
41
- let healedSteps = 0;
42
- let caughtError;
43
- let healTries = 0;
44
- let isHealing = false;
42
+ let currentTest = null
43
+ let currentStep = null
44
+ let healedSteps = 0
45
+ let caughtError
46
+ let healTries = 0
47
+ let isHealing = false
45
48
 
46
- config = Object.assign(defaultConfig, config);
49
+ config = Object.assign(defaultConfig, config)
47
50
 
48
51
  event.dispatcher.on(event.test.before, (test) => {
49
- currentTest = test;
50
- healedSteps = 0;
51
- caughtError = null;
52
- });
52
+ currentTest = test
53
+ healedSteps = 0
54
+ caughtError = null
55
+ })
53
56
 
54
- event.dispatcher.on(event.step.started, step => currentStep = step);
57
+ event.dispatcher.on(event.step.started, (step) => (currentStep = step))
55
58
 
56
59
  event.dispatcher.on(event.step.after, (step) => {
57
- if (isHealing) return;
58
- if (healTries >= config.healLimit) return; // out of limit
60
+ if (isHealing) return
61
+ if (healTries >= config.healLimit) return // out of limit
59
62
 
60
- if (!heal.hasCorrespondingRecipes(step)) return;
63
+ if (!heal.hasCorrespondingRecipes(step)) return
61
64
 
62
65
  recorder.catchWithoutStop(async (err) => {
63
- isHealing = true;
64
- if (caughtError === err) throw err; // avoid double handling
65
- caughtError = err;
66
+ isHealing = true
67
+ if (caughtError === err) throw err // avoid double handling
68
+ caughtError = err
66
69
 
67
- const test = currentTest;
70
+ const test = currentTest
68
71
 
69
- recorder.session.start('heal');
72
+ recorder.session.start('heal')
70
73
 
71
- debug('Self-healing started', step.toCode());
74
+ debug('Self-healing started', step.toCode())
72
75
 
73
- await heal.healStep(step, err, { test });
76
+ await heal.healStep(step, err, { test })
74
77
 
75
- healTries++;
78
+ healTries++
76
79
 
77
80
  recorder.add('close healing session', () => {
78
- recorder.reset();
79
- recorder.session.restore('heal');
80
- recorder.ignoreErr(err);
81
- });
82
- await recorder.promise();
81
+ recorder.reset()
82
+ recorder.session.restore('heal')
83
+ recorder.ignoreErr(err)
84
+ })
85
+ await recorder.promise()
83
86
 
84
- isHealing = false;
85
- });
86
- });
87
+ isHealing = false
88
+ })
89
+ })
87
90
 
88
91
  event.dispatcher.on(event.all.result, () => {
89
- if (!heal.fixes?.length) return;
92
+ if (!heal.fixes?.length) return
90
93
 
91
- const { print } = output;
94
+ const { print } = output
92
95
 
93
- print('');
94
- print('===================');
95
- print(colors.bold.green('Self-Healing Report:'));
96
+ print('')
97
+ print('===================')
98
+ print(colors.bold.green('Self-Healing Report:'))
96
99
 
97
- print(`${colors.bold(heal.fixes.length)} ${heal.fixes.length === 1 ? 'step was' : 'steps were'} healed`);
100
+ print(`${colors.bold(heal.fixes.length)} ${heal.fixes.length === 1 ? 'step was' : 'steps were'} healed`)
98
101
 
99
- const suggestions = heal.fixes.filter(fix => fix.recipe && heal.recipes[fix.recipe].suggest);
102
+ const suggestions = heal.fixes.filter((fix) => fix.recipe && heal.recipes[fix.recipe].suggest)
100
103
 
101
- if (!suggestions.length) return;
104
+ if (!suggestions.length) return
102
105
 
103
- let i = 1;
104
- print('');
105
- print('Suggested changes:');
106
- print('');
106
+ let i = 1
107
+ print('')
108
+ print('Suggested changes:')
109
+ print('')
107
110
 
108
111
  for (const suggestion of suggestions) {
109
- print(`${i}. To fix ${colors.bold.magenta(suggestion.test?.title)}`);
110
- print(' Replace the failed code:', colors.gray(`(suggested by ${colors.bold(suggestion.recipe)})`));
111
- print(colors.red(`- ${suggestion.step.toCode()}`));
112
- print(colors.green(`+ ${suggestion.snippet}`));
113
- print(suggestion.step.line());
114
- print('');
115
- i++;
112
+ print(`${i}. To fix ${colors.bold.magenta(suggestion.test?.title)}`)
113
+ print(' Replace the failed code:', colors.gray(`(suggested by ${colors.bold(suggestion.recipe)})`))
114
+ print(colors.red(`- ${suggestion.step.toCode()}`))
115
+ print(colors.green(`+ ${suggestion.snippet}`))
116
+ print(suggestion.step.line())
117
+ print('')
118
+ i++
116
119
  }
117
- });
118
- };
120
+ })
121
+ }
@@ -1,5 +1,5 @@
1
- const event = require('../event');
2
- const pause = require('../pause');
1
+ const event = require('../event')
2
+ const pause = require('../pause')
3
3
 
4
4
  /**
5
5
  * Automatically launches [interactive pause](/basics/#pause) when a test fails.
@@ -22,17 +22,17 @@ const pause = require('../pause');
22
22
  *
23
23
  */
24
24
  module.exports = () => {
25
- let failed = false;
25
+ let failed = false
26
26
 
27
27
  event.dispatcher.on(event.test.started, () => {
28
- failed = false;
29
- });
28
+ failed = false
29
+ })
30
30
 
31
31
  event.dispatcher.on(event.step.failed, () => {
32
- failed = true;
33
- });
32
+ failed = true
33
+ })
34
34
 
35
35
  event.dispatcher.on(event.test.after, () => {
36
- if (failed) pause();
37
- });
38
- };
36
+ if (failed) pause()
37
+ })
38
+ }
@@ -1,21 +1,14 @@
1
- const event = require('../event');
2
- const recorder = require('../recorder');
3
- const container = require('../container');
4
- const { log } = require('../output');
1
+ const event = require('../event')
2
+ const recorder = require('../recorder')
3
+ const container = require('../container')
4
+ const { log } = require('../output')
5
5
 
6
6
  const defaultConfig = {
7
7
  retries: 3,
8
- defaultIgnoredSteps: [
9
- 'amOnPage',
10
- 'wait*',
11
- 'send*',
12
- 'execute*',
13
- 'run*',
14
- 'have*',
15
- ],
8
+ defaultIgnoredSteps: ['amOnPage', 'wait*', 'send*', 'execute*', 'run*', 'have*'],
16
9
  factor: 1.5,
17
10
  ignoredSteps: [],
18
- };
11
+ }
19
12
 
20
13
  /**
21
14
  * Retries each failed step in a test.
@@ -84,45 +77,45 @@ const defaultConfig = {
84
77
  *
85
78
  */
86
79
  module.exports = (config) => {
87
- config = Object.assign(defaultConfig, config);
88
- config.ignoredSteps = config.ignoredSteps.concat(config.defaultIgnoredSteps);
89
- const customWhen = config.when;
80
+ config = Object.assign(defaultConfig, config)
81
+ config.ignoredSteps = config.ignoredSteps.concat(config.defaultIgnoredSteps)
82
+ const customWhen = config.when
90
83
 
91
- let enableRetry = false;
84
+ let enableRetry = false
92
85
 
93
86
  const when = (err) => {
94
- if (!enableRetry) return;
95
- const store = require('../store');
96
- if (store.debugMode) return false;
97
- if (customWhen) return customWhen(err);
98
- return true;
99
- };
100
- config.when = when;
87
+ if (!enableRetry) return
88
+ const store = require('../store')
89
+ if (store.debugMode) return false
90
+ if (customWhen) return customWhen(err)
91
+ return true
92
+ }
93
+ config.when = when
101
94
 
102
95
  event.dispatcher.on(event.step.started, (step) => {
103
96
  if (process.env.TRY_TO === 'true') {
104
- log('Info: RetryFailedStep plugin is disabled inside tryTo block');
105
- return;
97
+ log('Info: RetryFailedStep plugin is disabled inside tryTo block')
98
+ return
106
99
  }
107
100
 
108
101
  // if a step is ignored - return
109
102
  for (const ignored of config.ignoredSteps) {
110
- if (step.name === ignored) return;
103
+ if (step.name === ignored) return
111
104
  if (ignored instanceof RegExp) {
112
- if (step.name.match(ignored)) return;
113
- } else if (ignored.indexOf('*') && step.name.startsWith(ignored.slice(0, -1))) return;
105
+ if (step.name.match(ignored)) return
106
+ } else if (ignored.indexOf('*') && step.name.startsWith(ignored.slice(0, -1))) return
114
107
  }
115
- enableRetry = true; // enable retry for a step
116
- });
108
+ enableRetry = true // enable retry for a step
109
+ })
117
110
 
118
111
  event.dispatcher.on(event.step.finished, () => {
119
- enableRetry = false;
120
- });
112
+ enableRetry = false
113
+ })
121
114
 
122
115
  event.dispatcher.on(event.test.before, (test) => {
123
- if (test && test.disableRetryFailedStep) return; // disable retry when a test is not active
116
+ if (test && test.disableRetryFailedStep) return // disable retry when a test is not active
124
117
  // this env var is used to set the retries inside _before() block of helpers
125
- process.env.FAILED_STEP_RETRIES = config.retries;
126
- recorder.retry(config);
127
- });
128
- };
118
+ process.env.FAILED_STEP_RETRIES = config.retries
119
+ recorder.retry(config)
120
+ })
121
+ }
@@ -1,10 +1,10 @@
1
- const recorder = require('../recorder');
2
- const { debug } = require('../output');
1
+ const recorder = require('../recorder')
2
+ const { debug } = require('../output')
3
3
 
4
4
  const defaultConfig = {
5
5
  registerGlobal: true,
6
6
  pollInterval: 200,
7
- };
7
+ }
8
8
 
9
9
  /**
10
10
  *
@@ -74,54 +74,54 @@ const defaultConfig = {
74
74
  *
75
75
  */
76
76
  module.exports = function (config) {
77
- config = Object.assign(defaultConfig, config);
77
+ config = Object.assign(defaultConfig, config)
78
78
  function retryTo(callback, maxTries, pollInterval = config.pollInterval) {
79
79
  return new Promise((done, reject) => {
80
- let tries = 1;
80
+ let tries = 1
81
81
 
82
82
  function handleRetryException(err) {
83
- recorder.throw(err);
84
- reject(err);
83
+ recorder.throw(err)
84
+ reject(err)
85
85
  }
86
86
 
87
87
  const tryBlock = async () => {
88
- tries++;
89
- recorder.session.start(`retryTo ${tries}`);
88
+ tries++
89
+ recorder.session.start(`retryTo ${tries}`)
90
90
  try {
91
- await callback(tries);
91
+ await callback(tries)
92
92
  } catch (err) {
93
- handleRetryException(err);
93
+ handleRetryException(err)
94
94
  }
95
95
 
96
96
  // Call done if no errors
97
97
  recorder.add(() => {
98
- recorder.session.restore(`retryTo ${tries}`);
99
- done(null);
100
- });
98
+ recorder.session.restore(`retryTo ${tries}`)
99
+ done(null)
100
+ })
101
101
 
102
102
  // Catch errors and retry
103
103
  recorder.session.catch((err) => {
104
- recorder.session.restore(`retryTo ${tries}`);
104
+ recorder.session.restore(`retryTo ${tries}`)
105
105
  if (tries <= maxTries) {
106
- debug(`Error ${err}... Retrying`);
107
- recorder.add(`retryTo ${tries}`, () => setTimeout(tryBlock, pollInterval));
106
+ debug(`Error ${err}... Retrying`)
107
+ recorder.add(`retryTo ${tries}`, () => setTimeout(tryBlock, pollInterval))
108
108
  } else {
109
109
  // if maxTries reached
110
- handleRetryException(err);
110
+ handleRetryException(err)
111
111
  }
112
- });
113
- };
112
+ })
113
+ }
114
114
 
115
- recorder.add('retryTo', tryBlock).catch(err => {
116
- console.error('An error occurred:', err);
117
- done(null);
118
- });
119
- });
115
+ recorder.add('retryTo', tryBlock).catch((err) => {
116
+ console.error('An error occurred:', err)
117
+ done(null)
118
+ })
119
+ })
120
120
  }
121
121
 
122
122
  if (config.registerGlobal) {
123
- global.retryTo = retryTo;
123
+ global.retryTo = retryTo
124
124
  }
125
125
 
126
- return retryTo;
127
- };
126
+ return retryTo
127
+ }
@@ -1,20 +1,20 @@
1
- const fs = require('fs');
2
- const path = require('path');
1
+ const fs = require('fs')
2
+ const path = require('path')
3
3
 
4
- const Container = require('../container');
5
- const recorder = require('../recorder');
6
- const event = require('../event');
7
- const output = require('../output');
8
- const { fileExists, clearString } = require('../utils');
9
- const Codeceptjs = require('../index');
4
+ const Container = require('../container')
5
+ const recorder = require('../recorder')
6
+ const event = require('../event')
7
+ const output = require('../output')
8
+ const { fileExists, clearString } = require('../utils')
9
+ const Codeceptjs = require('../index')
10
10
 
11
11
  const defaultConfig = {
12
12
  uniqueScreenshotNames: false,
13
13
  disableScreenshots: false,
14
14
  fullPageScreenshots: false,
15
- };
15
+ }
16
16
 
17
- const supportedHelpers = require('./standardActingHelpers');
17
+ const supportedHelpers = require('./standardActingHelpers')
18
18
 
19
19
  /**
20
20
  * Creates screenshot on failure. Screenshot is saved into `output` directory.
@@ -43,118 +43,139 @@ const supportedHelpers = require('./standardActingHelpers');
43
43
  *
44
44
  */
45
45
  module.exports = function (config) {
46
- const helpers = Container.helpers();
47
- let helper;
46
+ const helpers = Container.helpers()
47
+ let helper
48
48
 
49
49
  for (const helperName of supportedHelpers) {
50
50
  if (Object.keys(helpers).indexOf(helperName) > -1) {
51
- helper = helpers[helperName];
51
+ helper = helpers[helperName]
52
52
  }
53
53
  }
54
54
 
55
- if (!helper) return; // no helpers for screenshot
55
+ if (!helper) return // no helpers for screenshot
56
56
 
57
- const options = Object.assign(defaultConfig, helper.options, config);
57
+ const options = Object.assign(defaultConfig, helper.options, config)
58
58
 
59
59
  if (helpers.Mochawesome) {
60
60
  if (helpers.Mochawesome.config) {
61
- options.uniqueScreenshotNames = helpers.Mochawesome.config.uniqueScreenshotNames;
61
+ options.uniqueScreenshotNames = helpers.Mochawesome.config.uniqueScreenshotNames
62
62
  }
63
63
  }
64
64
 
65
65
  if (Codeceptjs.container.mocha()) {
66
- options.reportDir = Codeceptjs.container.mocha().options.reporterOptions
67
- && Codeceptjs.container.mocha().options.reporterOptions.reportDir;
66
+ options.reportDir =
67
+ Codeceptjs.container.mocha().options.reporterOptions &&
68
+ Codeceptjs.container.mocha().options.reporterOptions.reportDir
68
69
  }
69
70
 
70
71
  if (options.disableScreenshots) {
71
72
  // old version of disabling screenshots
72
- return;
73
+ return
73
74
  }
74
75
 
75
76
  event.dispatcher.on(event.test.failed, (test) => {
76
77
  if (test.ctx?._runnable.title.includes('hook: ')) {
77
- output.plugin('screenshotOnFail', 'BeforeSuite/AfterSuite do not have any access to the browser, hence it could not take screenshot.');
78
- return;
78
+ output.plugin(
79
+ 'screenshotOnFail',
80
+ 'BeforeSuite/AfterSuite do not have any access to the browser, hence it could not take screenshot.',
81
+ )
82
+ return
79
83
  }
80
- recorder.add('screenshot of failed test', async () => {
81
- let fileName = clearString(test.title);
82
- const dataType = 'image/png';
83
- // This prevents data driven to be included in the failed screenshot file name
84
- if (fileName.indexOf('{') !== -1) {
85
- fileName = fileName.substr(0, (fileName.indexOf('{') - 3)).trim();
86
- }
87
- if (test.ctx && test.ctx.test && test.ctx.test.type === 'hook') fileName = clearString(`${test.title}_${test.ctx.test.title}`);
88
- if (options.uniqueScreenshotNames && test) {
89
- const uuid = _getUUID(test);
90
- fileName = `${fileName.substring(0, 10)}_${uuid}.failed.png`;
91
- } else {
92
- fileName += '.failed.png';
93
- }
94
- output.plugin('screenshotOnFail', 'Test failed, try to save a screenshot');
95
-
96
- try {
97
- if (options.reportDir) {
98
- fileName = path.join(options.reportDir, fileName);
99
- const mochaReportDir = path.resolve(process.cwd(), options.reportDir);
100
- if (!fileExists(mochaReportDir)) {
101
- fs.mkdirSync(mochaReportDir);
102
- }
84
+ recorder.add(
85
+ 'screenshot of failed test',
86
+ async () => {
87
+ let fileName = clearString(test.title)
88
+ const dataType = 'image/png'
89
+ // This prevents data driven to be included in the failed screenshot file name
90
+ if (fileName.indexOf('{') !== -1) {
91
+ fileName = fileName.substr(0, fileName.indexOf('{') - 3).trim()
103
92
  }
104
- await helper.saveScreenshot(fileName, options.fullPageScreenshots);
105
-
106
- if (!test.artifacts) test.artifacts = {};
107
- test.artifacts.screenshot = path.join(global.output_dir, fileName);
108
- if (Container.mocha().options.reporterOptions['mocha-junit-reporter'] && Container.mocha().options.reporterOptions['mocha-junit-reporter'].options.attachments) {
109
- test.attachments = [path.join(global.output_dir, fileName)];
93
+ if (test.ctx && test.ctx.test && test.ctx.test.type === 'hook')
94
+ fileName = clearString(`${test.title}_${test.ctx.test.title}`)
95
+ if (options.uniqueScreenshotNames && test) {
96
+ const uuid = _getUUID(test)
97
+ fileName = `${fileName.substring(0, 10)}_${uuid}.failed.png`
98
+ } else {
99
+ fileName += '.failed.png'
110
100
  }
101
+ output.plugin('screenshotOnFail', 'Test failed, try to save a screenshot')
102
+
103
+ try {
104
+ if (options.reportDir) {
105
+ fileName = path.join(options.reportDir, fileName)
106
+ const mochaReportDir = path.resolve(process.cwd(), options.reportDir)
107
+ if (!fileExists(mochaReportDir)) {
108
+ fs.mkdirSync(mochaReportDir)
109
+ }
110
+ }
111
+ await helper.saveScreenshot(fileName, options.fullPageScreenshots)
112
+
113
+ if (!test.artifacts) test.artifacts = {}
114
+ test.artifacts.screenshot = path.join(global.output_dir, fileName)
115
+ if (
116
+ Container.mocha().options.reporterOptions['mocha-junit-reporter'] &&
117
+ Container.mocha().options.reporterOptions['mocha-junit-reporter'].options.attachments
118
+ ) {
119
+ test.attachments = [path.join(global.output_dir, fileName)]
120
+ }
111
121
 
112
- const allureReporter = Container.plugins('allure');
113
- if (allureReporter) {
114
- allureReporter.addAttachment('Main session - Last Seen Screenshot', fs.readFileSync(path.join(global.output_dir, fileName)), dataType);
115
-
116
- if (helper.activeSessionName) {
117
- const sessions = helper.sessionPages || helper.sessionWindows;
118
- for (const sessionName in sessions) {
119
- const screenshotFileName = `${sessionName}_${fileName}`;
120
- test.artifacts[`${sessionName.replace(/ /g, '_')}_screenshot`] = path.join(global.output_dir, screenshotFileName);
121
- allureReporter.addAttachment(`${sessionName} - Last Seen Screenshot`, fs.readFileSync(path.join(global.output_dir, screenshotFileName)), dataType);
122
+ const allureReporter = Container.plugins('allure')
123
+ if (allureReporter) {
124
+ allureReporter.addAttachment(
125
+ 'Main session - Last Seen Screenshot',
126
+ fs.readFileSync(path.join(global.output_dir, fileName)),
127
+ dataType,
128
+ )
129
+
130
+ if (helper.activeSessionName) {
131
+ const sessions = helper.sessionPages || helper.sessionWindows
132
+ for (const sessionName in sessions) {
133
+ const screenshotFileName = `${sessionName}_${fileName}`
134
+ test.artifacts[`${sessionName.replace(/ /g, '_')}_screenshot`] = path.join(
135
+ global.output_dir,
136
+ screenshotFileName,
137
+ )
138
+ allureReporter.addAttachment(
139
+ `${sessionName} - Last Seen Screenshot`,
140
+ fs.readFileSync(path.join(global.output_dir, screenshotFileName)),
141
+ dataType,
142
+ )
143
+ }
122
144
  }
123
145
  }
124
- }
125
146
 
126
- const cucumberReporter = Container.plugins('cucumberJsonReporter');
127
- if (cucumberReporter) {
128
- cucumberReporter.addScreenshot(test.artifacts.screenshot);
129
- }
130
- } catch (err) {
131
- output.plugin(err);
132
- if (
133
- err
134
- && err.type
135
- && err.type === 'RuntimeError'
136
- && err.message
137
- && (
138
- err.message.indexOf('was terminated due to') > -1
139
- || err.message.indexOf('no such window: target window already closed') > -1
140
- )
141
- ) {
142
- output.log(`Can't make screenshot, ${err}`);
143
- helper.isRunning = false;
147
+ const cucumberReporter = Container.plugins('cucumberJsonReporter')
148
+ if (cucumberReporter) {
149
+ cucumberReporter.addScreenshot(test.artifacts.screenshot)
150
+ }
151
+ } catch (err) {
152
+ output.plugin(err)
153
+ if (
154
+ err &&
155
+ err.type &&
156
+ err.type === 'RuntimeError' &&
157
+ err.message &&
158
+ (err.message.indexOf('was terminated due to') > -1 ||
159
+ err.message.indexOf('no such window: target window already closed') > -1)
160
+ ) {
161
+ output.log(`Can't make screenshot, ${err}`)
162
+ helper.isRunning = false
163
+ }
144
164
  }
145
- }
146
- }, true);
147
- });
165
+ },
166
+ true,
167
+ )
168
+ })
148
169
 
149
170
  function _getUUID(test) {
150
171
  if (test.uuid) {
151
- return test.uuid;
172
+ return test.uuid
152
173
  }
153
174
 
154
175
  if (test.ctx && test.ctx.test.uuid) {
155
- return test.ctx.test.uuid;
176
+ return test.ctx.test.uuid
156
177
  }
157
178
 
158
- return Math.floor(new Date().getTime() / 1000);
179
+ return Math.floor(new Date().getTime() / 1000)
159
180
  }
160
- };
181
+ }