system-testing 1.0.21 → 1.0.22

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/system-test.js +66 -13
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "system-testing",
3
- "version": "1.0.21",
3
+ "version": "1.0.22",
4
4
  "description": "System testing with Selenium and browsers.",
5
5
  "keywords": [
6
6
  "system",
@@ -41,7 +41,7 @@ export default class SystemTest {
41
41
  await systemTest.visit("/blank")
42
42
 
43
43
  try {
44
- await systemTest.findByTestID("blankText")
44
+ await systemTest.findByTestID("blankText", {useBaseSelector: false})
45
45
  await callback(systemTest)
46
46
  } catch (error) {
47
47
  await systemTest.takeScreenshot()
@@ -72,6 +72,30 @@ export default class SystemTest {
72
72
  this.communicator = new SystemTestCommunicator({onCommand: this.onCommandReceived})
73
73
  }
74
74
 
75
+ /**
76
+ * Gets the base selector for scoping element searches
77
+ *
78
+ * @returns {string}
79
+ */
80
+ getBaseSelector() { return this._baseSelector }
81
+
82
+ /**
83
+ * Sets the base selector for scoping element searches
84
+ *
85
+ * @param {string} baseSelector
86
+ */
87
+ setBaseSelector(baseSelector) { this._baseSelector = baseSelector }
88
+
89
+ /**
90
+ * Gets a selector scoped to the base selector
91
+ *
92
+ * @param {string} selector
93
+ * @returns {string}
94
+ */
95
+ getSelector(selector) {
96
+ return this.getBaseSelector() ? `${this.getBaseSelector()} ${selector}` : selector
97
+ }
98
+
75
99
  /** Starts Scoundrel server which the browser connects to for remote evaluation in the browser */
76
100
  startScoundrel() {
77
101
  this.wss = new WebSocketServer({port: 8090})
@@ -93,8 +117,15 @@ export default class SystemTest {
93
117
  * @returns {import("selenium-webdriver").WebElement[]}
94
118
  */
95
119
  async all(selector, args = {}) {
96
- const {visible = true} = args
97
- const elements = await this.driver.findElements(By.css(selector))
120
+ const {visible = true, useBaseSelector = true, ...restArgs} = args
121
+ const restArgsKeys = Object.keys(restArgs)
122
+
123
+ if (restArgsKeys.length > 0) {
124
+ throw new Error(`Unknown arguments: ${restArgsKeys.join(", ")}`)
125
+ }
126
+
127
+ const actualSelector = useBaseSelector ? this.getSelector(selector) : selector
128
+ const elements = await this.driver.findElements(By.css(actualSelector))
98
129
  const activeElements = []
99
130
 
100
131
  for (const element of elements) {
@@ -142,15 +173,15 @@ export default class SystemTest {
142
173
  elements = await this.all(selector, args)
143
174
  } catch (error) {
144
175
  // Re-throw to recover stack trace
145
- throw new Error(`${error.message} (selector: ${selector})`)
176
+ throw new Error(`${error.message} (selector: ${this.getSelector(selector)})`)
146
177
  }
147
178
 
148
179
  if (elements.length > 1) {
149
- throw new Error(`More than 1 elements (${elements.length}) was found by CSS: ${selector}`)
180
+ throw new Error(`More than 1 elements (${elements.length}) was found by CSS: ${this.getSelector(selector)}`)
150
181
  }
151
182
 
152
183
  if (!elements[0]) {
153
- throw new ElementNotFoundError(`Element couldn't be found by CSS: ${selector}`)
184
+ throw new ElementNotFoundError(`Element couldn't be found after ${(this.getTimeouts() / 1000).toFixed(2)}s by CSS: ${this.getSelector(selector)}`)
154
185
  }
155
186
 
156
187
  return elements[0]
@@ -171,11 +202,11 @@ export default class SystemTest {
171
202
  * @param {string} selector
172
203
  * @returns {import("selenium-webdriver").WebElement}
173
204
  */
174
- async findNoWait(selector) {
205
+ async findNoWait(selector, args) {
175
206
  await this.driverSetTimeouts(0)
176
207
 
177
208
  try {
178
- return await this.find(selector)
209
+ return await this.find(selector, args)
179
210
  } finally {
180
211
  await this.restoreTimeouts()
181
212
  }
@@ -210,6 +241,8 @@ export default class SystemTest {
210
241
  return await this.driver.getCurrentUrl()
211
242
  }
212
243
 
244
+ getTimeouts() { return this._timeouts }
245
+
213
246
  /**
214
247
  * Interacts with an element by calling a method on it with the given arguments.
215
248
  * Retrying on ElementNotInteractableError.
@@ -283,7 +316,7 @@ export default class SystemTest {
283
316
  * @returns {Promise<string[]>}
284
317
  */
285
318
  async notificationMessages() {
286
- const notificationMessageElements = await this.all("[data-class='notification-message']")
319
+ const notificationMessageElements = await this.all("[data-class='notification-message']", {useBaseSelector: false})
287
320
  const notificationMessageTexts = []
288
321
 
289
322
  for (const notificationMessageElement of notificationMessageElements) {
@@ -372,8 +405,8 @@ export default class SystemTest {
372
405
  await this.driverVisit("/?systemTest=true")
373
406
 
374
407
  try {
375
- await this.find("body > #root")
376
- await this.find("[data-testid='systemTestingComponent']", {visible: null})
408
+ await this.find("body > #root", {useBaseSelector: false})
409
+ await this.find("[data-testid='systemTestingComponent']", {visible: null, useBaseSelector: false})
377
410
  } catch (error) {
378
411
  await systemTest.takeScreenshot()
379
412
 
@@ -384,17 +417,18 @@ export default class SystemTest {
384
417
  await this.waitForClientWebSocket()
385
418
 
386
419
  this._started = true
420
+ systemTest.setBaseSelector("[data-testid='systemTestingComponent'][data-focussed='true']")
387
421
  }
388
422
 
389
423
  /**
390
424
  * Restores previously set timeouts
391
425
  */
392
426
  async restoreTimeouts() {
393
- if (!this._timeouts) {
427
+ if (!this.getTimeouts()) {
394
428
  throw new Error("Timeouts haven't previously been set")
395
429
  }
396
430
 
397
- await this.driverSetTimeouts(this._timeouts)
431
+ await this.driverSetTimeouts(this.getTimeouts())
398
432
  }
399
433
 
400
434
  /**
@@ -440,10 +474,19 @@ export default class SystemTest {
440
474
  this.wss.on("close", this.onWebSocketClose)
441
475
  }
442
476
 
477
+ /**
478
+ * Sets the on command callback
479
+ */
443
480
  onCommand(callback) {
444
481
  this._onCommandCallback = callback
445
482
  }
446
483
 
484
+ /**
485
+ * Handles a command received from the browser
486
+ *
487
+ * @param {Object} data
488
+ * @returns {Promise<any>}
489
+ */
447
490
  onCommandReceived = async ({data}) => {
448
491
  const type = data.type
449
492
  let result
@@ -472,6 +515,11 @@ export default class SystemTest {
472
515
  return result
473
516
  }
474
517
 
518
+ /**
519
+ * Handles a new web socket connection
520
+ *
521
+ * @param {WebSocket} ws
522
+ */
475
523
  onWebSocketConnection = async (ws) => {
476
524
  this.ws = ws
477
525
  this.communicator.ws = ws
@@ -490,6 +538,11 @@ export default class SystemTest {
490
538
  this.communicator.ws = null
491
539
  }
492
540
 
541
+ /**
542
+ * Handles an error reported from the browser
543
+ *
544
+ * @param {Object} data
545
+ */
493
546
  handleError(data) {
494
547
  if (data.message.includes("Minified React error #419")) {
495
548
  // Ignore this error message