@serenity-js/webdriverio 2.32.2 → 3.0.0-rc.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.
Files changed (240) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/lib/adapter/WebdriverIOFrameworkAdapter.js +1 -1
  3. package/lib/adapter/WebdriverIOFrameworkAdapter.js.map +1 -1
  4. package/lib/adapter/WebdriverIONotifier.d.ts +35 -1
  5. package/lib/adapter/WebdriverIONotifier.js +174 -13
  6. package/lib/adapter/WebdriverIONotifier.js.map +1 -1
  7. package/lib/index.d.ts +0 -3
  8. package/lib/index.js +0 -3
  9. package/lib/index.js.map +1 -1
  10. package/lib/screenplay/abilities/{BrowseTheWeb.d.ts → BrowseTheWebWithWebdriverIO.d.ts} +79 -23
  11. package/lib/screenplay/abilities/{BrowseTheWeb.js → BrowseTheWebWithWebdriverIO.js} +160 -25
  12. package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.js.map +1 -0
  13. package/lib/screenplay/abilities/index.d.ts +1 -1
  14. package/lib/screenplay/abilities/index.js +1 -1
  15. package/lib/screenplay/abilities/index.js.map +1 -1
  16. package/lib/screenplay/index.d.ts +1 -2
  17. package/lib/screenplay/index.js +1 -2
  18. package/lib/screenplay/index.js.map +1 -1
  19. package/lib/screenplay/models/WebdriverIOCookie.d.ts +8 -0
  20. package/lib/screenplay/models/WebdriverIOCookie.js +39 -0
  21. package/lib/screenplay/models/WebdriverIOCookie.js.map +1 -0
  22. package/lib/screenplay/models/WebdriverIOModalDialog.d.ts +11 -0
  23. package/lib/screenplay/models/WebdriverIOModalDialog.js +40 -0
  24. package/lib/screenplay/models/WebdriverIOModalDialog.js.map +1 -0
  25. package/lib/screenplay/models/WebdriverIONativeElementRoot.d.ts +2 -0
  26. package/lib/screenplay/{interactions/EnterBuilder.js → models/WebdriverIONativeElementRoot.js} +1 -1
  27. package/lib/screenplay/models/WebdriverIONativeElementRoot.js.map +1 -0
  28. package/lib/screenplay/models/WebdriverIOPage.d.ts +24 -0
  29. package/lib/screenplay/models/WebdriverIOPage.js +98 -0
  30. package/lib/screenplay/models/WebdriverIOPage.js.map +1 -0
  31. package/lib/screenplay/models/WebdriverIOPageElement.d.ts +22 -0
  32. package/lib/screenplay/models/WebdriverIOPageElement.js +75 -0
  33. package/lib/screenplay/models/WebdriverIOPageElement.js.map +1 -0
  34. package/lib/screenplay/models/WebdriverIOPageElements.d.ts +15 -0
  35. package/lib/screenplay/models/WebdriverIOPageElements.js +65 -0
  36. package/lib/screenplay/models/WebdriverIOPageElements.js.map +1 -0
  37. package/lib/screenplay/models/index.d.ts +6 -0
  38. package/lib/{input → screenplay/models}/index.js +6 -1
  39. package/lib/screenplay/models/index.js.map +1 -0
  40. package/package.json +22 -32
  41. package/src/adapter/WebdriverIOFrameworkAdapter.ts +2 -0
  42. package/src/adapter/WebdriverIONotifier.ts +225 -23
  43. package/src/index.ts +0 -3
  44. package/src/screenplay/abilities/{BrowseTheWeb.ts → BrowseTheWebWithWebdriverIO.ts} +200 -31
  45. package/src/screenplay/abilities/index.ts +1 -1
  46. package/src/screenplay/index.ts +1 -2
  47. package/src/screenplay/models/WebdriverIOCookie.ts +44 -0
  48. package/src/screenplay/models/WebdriverIOModalDialog.ts +45 -0
  49. package/src/screenplay/models/WebdriverIONativeElementRoot.ts +3 -0
  50. package/src/screenplay/models/WebdriverIOPage.ts +120 -0
  51. package/src/screenplay/models/WebdriverIOPageElement.ts +92 -0
  52. package/src/screenplay/models/WebdriverIOPageElements.ts +91 -0
  53. package/src/screenplay/models/index.ts +6 -0
  54. package/lib/expectations/ElementExpectation.d.ts +0 -11
  55. package/lib/expectations/ElementExpectation.js +0 -27
  56. package/lib/expectations/ElementExpectation.js.map +0 -1
  57. package/lib/expectations/index.d.ts +0 -6
  58. package/lib/expectations/index.js +0 -19
  59. package/lib/expectations/index.js.map +0 -1
  60. package/lib/expectations/isActive.d.ts +0 -15
  61. package/lib/expectations/isActive.js +0 -21
  62. package/lib/expectations/isActive.js.map +0 -1
  63. package/lib/expectations/isClickable.d.ts +0 -20
  64. package/lib/expectations/isClickable.js +0 -26
  65. package/lib/expectations/isClickable.js.map +0 -1
  66. package/lib/expectations/isEnabled.d.ts +0 -14
  67. package/lib/expectations/isEnabled.js +0 -20
  68. package/lib/expectations/isEnabled.js.map +0 -1
  69. package/lib/expectations/isPresent.d.ts +0 -15
  70. package/lib/expectations/isPresent.js +0 -21
  71. package/lib/expectations/isPresent.js.map +0 -1
  72. package/lib/expectations/isSelected.d.ts +0 -14
  73. package/lib/expectations/isSelected.js +0 -20
  74. package/lib/expectations/isSelected.js.map +0 -1
  75. package/lib/expectations/isVisible.d.ts +0 -14
  76. package/lib/expectations/isVisible.js +0 -20
  77. package/lib/expectations/isVisible.js.map +0 -1
  78. package/lib/input/Key.d.ts +0 -73
  79. package/lib/input/Key.js +0 -84
  80. package/lib/input/Key.js.map +0 -1
  81. package/lib/input/index.d.ts +0 -1
  82. package/lib/input/index.js.map +0 -1
  83. package/lib/screenplay/abilities/BrowseTheWeb.js.map +0 -1
  84. package/lib/screenplay/interactions/Clear.d.ts +0 -79
  85. package/lib/screenplay/interactions/Clear.js +0 -97
  86. package/lib/screenplay/interactions/Clear.js.map +0 -1
  87. package/lib/screenplay/interactions/Click.d.ts +0 -73
  88. package/lib/screenplay/interactions/Click.js +0 -84
  89. package/lib/screenplay/interactions/Click.js.map +0 -1
  90. package/lib/screenplay/interactions/DoubleClick.d.ts +0 -90
  91. package/lib/screenplay/interactions/DoubleClick.js +0 -101
  92. package/lib/screenplay/interactions/DoubleClick.js.map +0 -1
  93. package/lib/screenplay/interactions/Enter.d.ts +0 -73
  94. package/lib/screenplay/interactions/Enter.js +0 -87
  95. package/lib/screenplay/interactions/Enter.js.map +0 -1
  96. package/lib/screenplay/interactions/EnterBuilder.d.ts +0 -25
  97. package/lib/screenplay/interactions/EnterBuilder.js.map +0 -1
  98. package/lib/screenplay/interactions/ExecuteScript.d.ts +0 -206
  99. package/lib/screenplay/interactions/ExecuteScript.js +0 -311
  100. package/lib/screenplay/interactions/ExecuteScript.js.map +0 -1
  101. package/lib/screenplay/interactions/Hover.d.ts +0 -78
  102. package/lib/screenplay/interactions/Hover.js +0 -89
  103. package/lib/screenplay/interactions/Hover.js.map +0 -1
  104. package/lib/screenplay/interactions/Navigate.d.ts +0 -141
  105. package/lib/screenplay/interactions/Navigate.js +0 -197
  106. package/lib/screenplay/interactions/Navigate.js.map +0 -1
  107. package/lib/screenplay/interactions/Press.d.ts +0 -84
  108. package/lib/screenplay/interactions/Press.js +0 -152
  109. package/lib/screenplay/interactions/Press.js.map +0 -1
  110. package/lib/screenplay/interactions/PressBuilder.d.ts +0 -26
  111. package/lib/screenplay/interactions/PressBuilder.js +0 -3
  112. package/lib/screenplay/interactions/PressBuilder.js.map +0 -1
  113. package/lib/screenplay/interactions/RightClick.d.ts +0 -89
  114. package/lib/screenplay/interactions/RightClick.js +0 -100
  115. package/lib/screenplay/interactions/RightClick.js.map +0 -1
  116. package/lib/screenplay/interactions/Scroll.d.ts +0 -75
  117. package/lib/screenplay/interactions/Scroll.js +0 -86
  118. package/lib/screenplay/interactions/Scroll.js.map +0 -1
  119. package/lib/screenplay/interactions/Wait.d.ts +0 -143
  120. package/lib/screenplay/interactions/Wait.js +0 -247
  121. package/lib/screenplay/interactions/Wait.js.map +0 -1
  122. package/lib/screenplay/interactions/WaitBuilder.d.ts +0 -32
  123. package/lib/screenplay/interactions/WaitBuilder.js +0 -3
  124. package/lib/screenplay/interactions/WaitBuilder.js.map +0 -1
  125. package/lib/screenplay/interactions/WebElementInteraction.d.ts +0 -37
  126. package/lib/screenplay/interactions/WebElementInteraction.js +0 -52
  127. package/lib/screenplay/interactions/WebElementInteraction.js.map +0 -1
  128. package/lib/screenplay/interactions/index.d.ts +0 -13
  129. package/lib/screenplay/interactions/index.js +0 -26
  130. package/lib/screenplay/interactions/index.js.map +0 -1
  131. package/lib/screenplay/questions/Attribute.d.ts +0 -82
  132. package/lib/screenplay/questions/Attribute.js +0 -102
  133. package/lib/screenplay/questions/Attribute.js.map +0 -1
  134. package/lib/screenplay/questions/CSSClasses.d.ts +0 -92
  135. package/lib/screenplay/questions/CSSClasses.js +0 -112
  136. package/lib/screenplay/questions/CSSClasses.js.map +0 -1
  137. package/lib/screenplay/questions/LastScriptExecution.d.ts +0 -14
  138. package/lib/screenplay/questions/LastScriptExecution.js +0 -22
  139. package/lib/screenplay/questions/LastScriptExecution.js.map +0 -1
  140. package/lib/screenplay/questions/NestedTargetBuilder.d.ts +0 -27
  141. package/lib/screenplay/questions/NestedTargetBuilder.js +0 -3
  142. package/lib/screenplay/questions/NestedTargetBuilder.js.map +0 -1
  143. package/lib/screenplay/questions/TargetBuilder.d.ts +0 -25
  144. package/lib/screenplay/questions/TargetBuilder.js +0 -3
  145. package/lib/screenplay/questions/TargetBuilder.js.map +0 -1
  146. package/lib/screenplay/questions/Text.d.ts +0 -95
  147. package/lib/screenplay/questions/Text.js +0 -130
  148. package/lib/screenplay/questions/Text.js.map +0 -1
  149. package/lib/screenplay/questions/Value.d.ts +0 -63
  150. package/lib/screenplay/questions/Value.js +0 -78
  151. package/lib/screenplay/questions/Value.js.map +0 -1
  152. package/lib/screenplay/questions/Website.d.ts +0 -21
  153. package/lib/screenplay/questions/Website.js +0 -31
  154. package/lib/screenplay/questions/Website.js.map +0 -1
  155. package/lib/screenplay/questions/index.d.ts +0 -10
  156. package/lib/screenplay/questions/index.js +0 -23
  157. package/lib/screenplay/questions/index.js.map +0 -1
  158. package/lib/screenplay/questions/lists.d.ts +0 -86
  159. package/lib/screenplay/questions/lists.js +0 -137
  160. package/lib/screenplay/questions/lists.js.map +0 -1
  161. package/lib/screenplay/questions/locators.d.ts +0 -196
  162. package/lib/screenplay/questions/locators.js +0 -219
  163. package/lib/screenplay/questions/locators.js.map +0 -1
  164. package/lib/screenplay/questions/targets.d.ts +0 -254
  165. package/lib/screenplay/questions/targets.js +0 -334
  166. package/lib/screenplay/questions/targets.js.map +0 -1
  167. package/lib/stage/crew/index.d.ts +0 -1
  168. package/lib/stage/crew/index.js +0 -14
  169. package/lib/stage/crew/index.js.map +0 -1
  170. package/lib/stage/crew/photographer/Photographer.d.ts +0 -83
  171. package/lib/stage/crew/photographer/Photographer.js +0 -102
  172. package/lib/stage/crew/photographer/Photographer.js.map +0 -1
  173. package/lib/stage/crew/photographer/index.d.ts +0 -2
  174. package/lib/stage/crew/photographer/index.js +0 -15
  175. package/lib/stage/crew/photographer/index.js.map +0 -1
  176. package/lib/stage/crew/photographer/strategies/PhotoTakingStrategy.d.ts +0 -28
  177. package/lib/stage/crew/photographer/strategies/PhotoTakingStrategy.js +0 -65
  178. package/lib/stage/crew/photographer/strategies/PhotoTakingStrategy.js.map +0 -1
  179. package/lib/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.d.ts +0 -18
  180. package/lib/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.js +0 -30
  181. package/lib/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.js.map +0 -1
  182. package/lib/stage/crew/photographer/strategies/TakePhotosOfFailures.d.ts +0 -17
  183. package/lib/stage/crew/photographer/strategies/TakePhotosOfFailures.js +0 -28
  184. package/lib/stage/crew/photographer/strategies/TakePhotosOfFailures.js.map +0 -1
  185. package/lib/stage/crew/photographer/strategies/TakePhotosOfInteractions.d.ts +0 -19
  186. package/lib/stage/crew/photographer/strategies/TakePhotosOfInteractions.js +0 -28
  187. package/lib/stage/crew/photographer/strategies/TakePhotosOfInteractions.js.map +0 -1
  188. package/lib/stage/crew/photographer/strategies/index.d.ts +0 -4
  189. package/lib/stage/crew/photographer/strategies/index.js +0 -17
  190. package/lib/stage/crew/photographer/strategies/index.js.map +0 -1
  191. package/lib/stage/index.d.ts +0 -1
  192. package/lib/stage/index.js +0 -14
  193. package/lib/stage/index.js.map +0 -1
  194. package/src/expectations/ElementExpectation.ts +0 -31
  195. package/src/expectations/index.ts +0 -6
  196. package/src/expectations/isActive.ts +0 -21
  197. package/src/expectations/isClickable.ts +0 -26
  198. package/src/expectations/isEnabled.ts +0 -19
  199. package/src/expectations/isPresent.ts +0 -20
  200. package/src/expectations/isSelected.ts +0 -19
  201. package/src/expectations/isVisible.ts +0 -19
  202. package/src/input/Key.ts +0 -83
  203. package/src/input/index.ts +0 -1
  204. package/src/screenplay/interactions/Clear.ts +0 -102
  205. package/src/screenplay/interactions/Click.ts +0 -85
  206. package/src/screenplay/interactions/DoubleClick.ts +0 -102
  207. package/src/screenplay/interactions/Enter.ts +0 -93
  208. package/src/screenplay/interactions/EnterBuilder.ts +0 -27
  209. package/src/screenplay/interactions/ExecuteScript.ts +0 -344
  210. package/src/screenplay/interactions/Hover.ts +0 -90
  211. package/src/screenplay/interactions/Navigate.ts +0 -208
  212. package/src/screenplay/interactions/Press.ts +0 -172
  213. package/src/screenplay/interactions/PressBuilder.ts +0 -28
  214. package/src/screenplay/interactions/RightClick.ts +0 -100
  215. package/src/screenplay/interactions/Scroll.ts +0 -87
  216. package/src/screenplay/interactions/Wait.ts +0 -267
  217. package/src/screenplay/interactions/WaitBuilder.ts +0 -34
  218. package/src/screenplay/interactions/WebElementInteraction.ts +0 -56
  219. package/src/screenplay/interactions/index.ts +0 -13
  220. package/src/screenplay/questions/Attribute.ts +0 -112
  221. package/src/screenplay/questions/CSSClasses.ts +0 -116
  222. package/src/screenplay/questions/LastScriptExecution.ts +0 -21
  223. package/src/screenplay/questions/NestedTargetBuilder.ts +0 -30
  224. package/src/screenplay/questions/TargetBuilder.ts +0 -27
  225. package/src/screenplay/questions/Text.ts +0 -140
  226. package/src/screenplay/questions/Value.ts +0 -82
  227. package/src/screenplay/questions/Website.ts +0 -34
  228. package/src/screenplay/questions/index.ts +0 -10
  229. package/src/screenplay/questions/lists.ts +0 -161
  230. package/src/screenplay/questions/locators.ts +0 -254
  231. package/src/screenplay/questions/targets.ts +0 -401
  232. package/src/stage/crew/index.ts +0 -1
  233. package/src/stage/crew/photographer/Photographer.ts +0 -108
  234. package/src/stage/crew/photographer/index.ts +0 -2
  235. package/src/stage/crew/photographer/strategies/PhotoTakingStrategy.ts +0 -103
  236. package/src/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.ts +0 -28
  237. package/src/stage/crew/photographer/strategies/TakePhotosOfFailures.ts +0 -26
  238. package/src/stage/crew/photographer/strategies/TakePhotosOfInteractions.ts +0 -26
  239. package/src/stage/crew/photographer/strategies/index.ts +0 -4
  240. package/src/stage/index.ts +0 -1
@@ -1,7 +1,8 @@
1
1
  import { LogicError, Stage, StageCrewMember } from '@serenity-js/core';
2
- import { DomainEvent, SceneFinished, SceneStarts, TestSuiteFinished, TestSuiteStarts } from '@serenity-js/core/lib/events';
2
+ import { AsyncOperationAttempted, AsyncOperationCompleted, DomainEvent, SceneFinished, SceneStarts, TestRunFinishes, TestSuiteFinished, TestSuiteStarts } from '@serenity-js/core/lib/events';
3
3
  import {
4
4
  CorrelationId,
5
+ Description,
5
6
  ExecutionCompromised,
6
7
  ExecutionFailedWithAssertionError,
7
8
  ExecutionFailedWithError,
@@ -12,20 +13,35 @@ import {
12
13
  ProblemIndication,
13
14
  TestSuiteDetails,
14
15
  } from '@serenity-js/core/lib/model';
15
- import { Suite } from '@wdio/reporter/build/stats/suite';
16
- import { Test } from '@wdio/reporter/build/stats/test';
16
+ import { Suite as suiteStats } from '@wdio/reporter/build/stats/suite';
17
+ import { Test as testStats } from '@wdio/reporter/build/stats/test';
18
+ import { RemoteCapability } from '@wdio/types/build/Capabilities';
19
+ import * as frameworks from '@wdio/types/build/Frameworks';
17
20
  import type { EventEmitter } from 'events';
18
21
  import { match } from 'tiny-types';
19
22
 
23
+ import { WebdriverIOConfig } from './WebdriverIOConfig';
24
+
20
25
  /**
21
26
  * @package
22
27
  */
23
28
  export class WebdriverIONotifier implements StageCrewMember {
24
29
 
30
+ /**
31
+ * We don't have access to the "context" object produced by Mocha,
32
+ * and can't assume that other test runners have a similar concept.
33
+ * Since, at the time of writing, none of the WebdriverIO rely on this parameter
34
+ * using a dummy seems to be sufficient.
35
+ * @private
36
+ */
37
+ private static dummmyContext = {};
38
+
25
39
  private readonly events = new EventLog();
26
40
  private readonly suites: TestSuiteDetails[] = [];
27
41
 
28
42
  constructor(
43
+ private readonly config: WebdriverIOConfig,
44
+ private readonly capabilities: RemoteCapability,
29
45
  private readonly reporter: EventEmitter,
30
46
  private readonly successThreshold: Outcome | { Code: number },
31
47
  private readonly cid: string,
@@ -46,28 +62,42 @@ export class WebdriverIONotifier implements StageCrewMember {
46
62
  .when(TestSuiteFinished, WebdriverIONotifier.prototype.onTestSuiteFinished.bind(this))
47
63
  .when(SceneStarts, WebdriverIONotifier.prototype.onSceneStarts.bind(this))
48
64
  .when(SceneFinished, WebdriverIONotifier.prototype.onSceneFinished.bind(this))
65
+ .when(TestRunFinishes, WebdriverIONotifier.prototype.onTestRunFinishes.bind(this))
49
66
  .else(() => void 0);
50
67
  }
51
68
 
69
+ private onTestRunFinishes(): Promise<any> {
70
+ return this.invokeHooks('after', this.config.after, [this.failures, this.capabilities, this.specs]);
71
+ }
72
+
52
73
  failureCount(): number {
53
74
  return this.failures;
54
75
  }
55
76
 
56
- private onTestSuiteStarts(started: TestSuiteStarts) {
77
+ private onTestSuiteStarts(started: TestSuiteStarts): Promise<any> {
57
78
  this.events.record(started.details.correlationId, started);
58
- this.reporter.emit('suite:start', this.suiteStartEventFrom(started));
79
+
80
+ const suite = this.suiteStartEventFrom(started);
81
+
82
+ this.reporter.emit('suite:start', suite);
59
83
 
60
84
  this.suites.push(started.details);
85
+
86
+ return this.invokeHooks('beforeSuite', this.config.beforeSuite, [suite as any]); // todo: correct types
61
87
  }
62
88
 
63
- private onTestSuiteFinished(finished: TestSuiteFinished) {
89
+ private onTestSuiteFinished(finished: TestSuiteFinished): Promise<any> {
64
90
  this.suites.pop();
65
91
 
66
92
  const started = this.events.getByCorrelationId<TestSuiteStarts>(finished.details.correlationId);
67
- this.reporter.emit('suite:end', this.suiteEndEventFrom(started, finished));
93
+ const suite = this.suiteEndEventFrom(started, finished);
94
+
95
+ this.reporter.emit('suite:end', suite);
96
+
97
+ return this.invokeHooks('afterSuite', this.config.afterSuite, [suite as any]); // todo: correct types
68
98
  }
69
99
 
70
- private suiteStartEventFrom(started: TestSuiteStarts): Suite {
100
+ private suiteStartEventFrom(started: TestSuiteStarts): suiteStats & frameworks.Suite {
71
101
  return {
72
102
  type: 'suite:start',
73
103
  uid: started.details.correlationId.value,
@@ -85,7 +115,7 @@ export class WebdriverIONotifier implements StageCrewMember {
85
115
  return this.suites.map(suite => suite.name.value).concat(name).join(' ');
86
116
  }
87
117
 
88
- private suiteEndEventFrom(started: TestSuiteStarts, finished: TestSuiteFinished): Suite {
118
+ private suiteEndEventFrom(started: TestSuiteStarts, finished: TestSuiteFinished): suiteStats & frameworks.Suite {
89
119
  return {
90
120
  ...this.suiteStartEventFrom(started),
91
121
  type: 'suite:end',
@@ -99,6 +129,8 @@ export class WebdriverIONotifier implements StageCrewMember {
99
129
  this.events.record(started.sceneId, started);
100
130
 
101
131
  this.reporter.emit(test.type, test);
132
+
133
+ return this.invokeHooks('beforeTest', this.config.beforeTest, [ this.testFrom(started), WebdriverIONotifier.dummmyContext ]);
102
134
  }
103
135
 
104
136
  private onSceneFinished(finished: SceneFinished) {
@@ -108,37 +140,59 @@ export class WebdriverIONotifier implements StageCrewMember {
108
140
  }
109
141
 
110
142
  const started = this.events.getByCorrelationId<SceneStarts>(finished.sceneId);
143
+ let testEnd: testStats;
111
144
 
112
145
  if (this.willBeRetried(finished.outcome)) {
113
- const testResult = this.testEndEventFrom(started, finished);
146
+ testEnd = this.testEndEventFrom(started, finished);
114
147
 
115
148
  const type = 'test:retry';
116
149
 
117
150
  this.reporter.emit(type, {
118
- ...testResult,
151
+ ...testEnd,
119
152
  type,
120
153
  error: this.errorFrom(finished.outcome),
121
154
  });
122
155
 
123
156
  } else {
124
157
 
125
- const testResult = this.testResultEventFrom(started, finished);
126
- this.reporter.emit(testResult.type, testResult);
158
+ const testResultEvent = this.testResultEventFrom(started, finished);
159
+ this.reporter.emit(testResultEvent.type, testResultEvent);
127
160
 
128
- const testEnd = this.testEndEventFrom(started, finished);
161
+ testEnd = this.testEndEventFrom(started, finished);
129
162
  this.reporter.emit(testEnd.type, testEnd);
130
163
  }
164
+
165
+ return this.invokeHooks('afterTest', this.config.afterTest, [ this.testFrom(started), WebdriverIONotifier.dummmyContext, this.testResultFrom(started, finished) ]);
131
166
  }
132
167
 
133
168
  private willBeRetried(outcome: Outcome): outcome is ExecutionIgnored {
134
169
  return outcome instanceof ExecutionIgnored;
135
170
  }
136
171
 
137
- private testStartEventFrom(started: SceneStarts): Test {
138
- const title = started.details.name.value
172
+ private testShortTitleFrom(started: SceneStarts): string {
173
+ return started.details.name.value
139
174
  .replace(new RegExp(`^.*?(${ this.parentSuiteName() })`), '')
140
175
  .trim();
176
+ }
177
+
178
+ private testFrom(started: SceneStarts): frameworks.Test {
179
+ const
180
+ title = this.testShortTitleFrom(started);
141
181
 
182
+ return {
183
+ ctx: WebdriverIONotifier.dummmyContext,
184
+ file: started.details.location.path.value,
185
+ fullName: this.suiteNamesConcatenatedWith(title),
186
+ fullTitle: this.suiteNamesConcatenatedWith(title),
187
+ parent: this.parentSuiteName(),
188
+ pending: false,
189
+ title,
190
+ type: 'test' // I _think_ it's either 'test' or 'hook' - https://github.com/mochajs/mocha/blob/0ea732c1169c678ef116c3eb452cc94758fff150/lib/test.js#L31
191
+ }
192
+ }
193
+
194
+ private testStartEventFrom(started: SceneStarts): testStats {
195
+ const title = this.testShortTitleFrom(started);
142
196
  return {
143
197
  type: 'test:start',
144
198
  title,
@@ -156,7 +210,95 @@ export class WebdriverIONotifier implements StageCrewMember {
156
210
  return this.suites[this.suites.length - 1]?.name.value || '';
157
211
  }
158
212
 
159
- private testEndEventFrom(started: SceneStarts, finished: SceneFinished): Test {
213
+ /**
214
+ * test status is 'passed' | 'pending' | 'skipped' | 'failed' | 'broken' | 'canceled'
215
+ * Since this is not documented, we're mimicking other WebdriverIO reporters, for example:
216
+ * https://github.com/webdriverio/webdriverio/blob/7415f3126e15a733b51721492e4995ceafae6046/packages/wdio-allure-reporter/src/constants.ts#L3-L9
217
+ *
218
+ * @param started
219
+ * @param finished
220
+ * @private
221
+ */
222
+ private testResultFrom(started: SceneStarts, finished: SceneFinished): frameworks.TestResult {
223
+ const duration = finished.timestamp.diff(started.timestamp).inMilliseconds();
224
+ const defaultRetries = { attempts: 0, limit: 0 };
225
+
226
+ const passedOrFailed = (outcome: Outcome): boolean =>
227
+ this.whenSuccessful<boolean>(outcome, true, false);
228
+
229
+ return match<Outcome, frameworks.TestResult>(finished.outcome)
230
+ .when(ExecutionCompromised, (outcome: ExecutionCompromised) => {
231
+ const error = this.errorFrom(outcome);
232
+ return {
233
+ duration,
234
+ error,
235
+ exception: error.message,
236
+ passed: passedOrFailed(outcome),
237
+ status: 'broken',
238
+ retries: defaultRetries
239
+ }
240
+ })
241
+ .when(ExecutionFailedWithError, (outcome: ExecutionFailedWithError) => {
242
+ const error = this.errorFrom(outcome);
243
+ return {
244
+ duration,
245
+ error,
246
+ exception: error.message,
247
+ passed: passedOrFailed(outcome),
248
+ status: 'broken',
249
+ retries: defaultRetries
250
+ }
251
+ })
252
+ .when(ExecutionFailedWithAssertionError, (outcome: ExecutionFailedWithAssertionError) => {
253
+ const error = this.errorFrom(outcome);
254
+ return {
255
+ duration,
256
+ error,
257
+ exception: error.message,
258
+ passed: passedOrFailed(outcome),
259
+ status: 'failed',
260
+ retries: defaultRetries
261
+ }
262
+ })
263
+ .when(ImplementationPending, (outcome: ImplementationPending) => {
264
+ const error = this.errorFrom(outcome);
265
+ return {
266
+ duration,
267
+ error,
268
+ exception: error.message,
269
+ passed: passedOrFailed(outcome),
270
+ status: 'pending',
271
+ retries: defaultRetries
272
+ }
273
+ })
274
+ .when(ExecutionIgnored, (outcome: ExecutionIgnored) => {
275
+ const error = this.errorFrom(outcome);
276
+ return {
277
+ duration,
278
+ error,
279
+ exception: error.message,
280
+ passed: passedOrFailed(outcome),
281
+ status: 'canceled', // fixme: mark as canceled for now for the lack of a better alternative;
282
+ retries: defaultRetries // consider capturing info about retries from Mocha and putting it on the ExecutionIgnored event so we can pass it on
283
+ }
284
+ })
285
+ .when(ExecutionSkipped, (outcome: ExecutionSkipped) => ({
286
+ duration,
287
+ exception: '',
288
+ passed: passedOrFailed(outcome),
289
+ status: 'skipped',
290
+ retries: defaultRetries
291
+ }))
292
+ .else(() => ({
293
+ duration,
294
+ exception: '',
295
+ passed: true,
296
+ status: 'passed',
297
+ retries: defaultRetries
298
+ }));
299
+ }
300
+
301
+ private testEndEventFrom(started: SceneStarts, finished: SceneFinished): testStats {
160
302
  const duration = finished.timestamp.diff(started.timestamp).inMilliseconds();
161
303
  return {
162
304
  ...this.testStartEventFrom(started),
@@ -165,15 +307,19 @@ export class WebdriverIONotifier implements StageCrewMember {
165
307
  };
166
308
  }
167
309
 
168
- private testResultEventFrom(started: SceneStarts, finished: SceneFinished): Test {
310
+ private whenSuccessful<O>(outcome: Outcome, resultWhenSuccessful: O, resultWhenNotSuccessful: O): O {
311
+ return ! outcome.isWorseThan(this.successThreshold) && (outcome instanceof ProblemIndication)
312
+ ? resultWhenSuccessful
313
+ : resultWhenNotSuccessful
314
+ }
315
+
316
+ private testResultEventFrom(started: SceneStarts, finished: SceneFinished): testStats {
169
317
  const test = this.testEndEventFrom(started, finished)
170
318
 
171
- const unlessSuccessful = (outcome: Outcome, type: Test['type']) =>
172
- ! outcome.isWorseThan(this.successThreshold) && (outcome instanceof ProblemIndication)
173
- ? 'test:pass'
174
- : type;
319
+ const unlessSuccessful = (outcome: Outcome, type: testStats['type']) =>
320
+ this.whenSuccessful<testStats['type']>(outcome, 'test:pass', type);
175
321
 
176
- return match<Outcome, Test>(finished.outcome)
322
+ return match<Outcome, testStats>(finished.outcome)
177
323
  .when(ExecutionCompromised, (outcome: ExecutionCompromised) => ({
178
324
  ...test,
179
325
  type: unlessSuccessful(outcome, 'test:fail'),
@@ -231,6 +377,62 @@ export class WebdriverIONotifier implements StageCrewMember {
231
377
  actual: error.actual
232
378
  }
233
379
  }
380
+
381
+ /**
382
+ * @see https://github.com/webdriverio/webdriverio/blob/main/packages/wdio-utils/src/shim.ts
383
+ * @param hookName
384
+ * @param hookFunctions
385
+ * @param args
386
+ * @private
387
+ */
388
+ private invokeHooks<Result, InnerArguments extends any[]>(
389
+ hookName: string,
390
+ hookFunctions: ((...parameters: InnerArguments) => Promise<Result> | Result) | Array<((...parameters: InnerArguments) => Result)>,
391
+ args: InnerArguments
392
+ ): Promise<Array<Result | Error>> {
393
+
394
+ const hooks = ! Array.isArray(hookFunctions)
395
+ ? [ hookFunctions ]
396
+ : hookFunctions;
397
+
398
+ const asyncOperationId = CorrelationId.create();
399
+
400
+ this.stage.announce(new AsyncOperationAttempted(
401
+ new Description(`[WebdriverIONotifier#invokeHooks] Invoking ${ hookName } hook`),
402
+ asyncOperationId,
403
+ ));
404
+
405
+ return Promise.all(hooks.map((hook) => new Promise<Result | Error>((resolve) => {
406
+ let result
407
+
408
+ try {
409
+ result = hook(...args);
410
+ } catch (error) {
411
+ return resolve(error);
412
+ }
413
+
414
+ /**
415
+ * if a promise is returned make sure we don't have a catch handler
416
+ * so in case of a rejection it won't cause the hook to fail
417
+ */
418
+ if (result && typeof result.then === 'function') {
419
+ return result.then(resolve, (error: Error) => {
420
+ resolve(error);
421
+ })
422
+ }
423
+
424
+ resolve(result);
425
+ }))).
426
+ then(results => {
427
+
428
+ this.stage.announce(new AsyncOperationCompleted(
429
+ new Description(`[WebdriverIONotifier#invokeHooks] Invoking ${ hookName } hook completed`),
430
+ asyncOperationId,
431
+ ));
432
+
433
+ return results;
434
+ });
435
+ }
234
436
  }
235
437
 
236
438
  class EventLog {
package/src/index.ts CHANGED
@@ -12,7 +12,4 @@ const adapterFactory = new WebdriverIOFrameworkAdapterFactory(
12
12
  export default adapterFactory;
13
13
 
14
14
  export { WebdriverIOConfig } from './adapter';
15
- export * from './expectations';
16
- export * from './input';
17
15
  export * from './screenplay';
18
- export * from './stage';