system-testing 1.0.24 → 1.0.25
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/README.md +63 -0
- package/package.json +1 -1
- package/src/system-test.js +49 -15
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# System testing
|
|
2
|
+
|
|
3
|
+
Rails inspired system testing for Expo apps.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install --save-dev system-testing
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import retry from "awaitery/src/retry.js"
|
|
15
|
+
import SystemTest from "system-testing/src/system-test.js"
|
|
16
|
+
import wait from "awaitery/src/wait.js"
|
|
17
|
+
import waitFor from "awaitery/src/wait-for.js"
|
|
18
|
+
|
|
19
|
+
import createUser from "@/src/testing/create-user.js"
|
|
20
|
+
import initialize from "@/src/initialize"
|
|
21
|
+
import Option from "@/src/models/option"
|
|
22
|
+
|
|
23
|
+
describe("Sign in page", () => {
|
|
24
|
+
test("it navigates to the sign in page and signs in", async () => {
|
|
25
|
+
await initialize()
|
|
26
|
+
|
|
27
|
+
await SystemTest.run(async (systemTest) => {
|
|
28
|
+
await createUser(userAttributes)
|
|
29
|
+
|
|
30
|
+
await systemTest.visit("/")
|
|
31
|
+
await systemTest.findByTestID("frontpageScreen", {useBaseSelector: false})
|
|
32
|
+
await wait(250)
|
|
33
|
+
|
|
34
|
+
await retry(async () => {
|
|
35
|
+
await systemTest.click("[data-testid='signInButton']")
|
|
36
|
+
await systemTest.findByTestID("app/sign-in")
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
await systemTest.interact("[data-testid='signInEmailInput']", "sendKeys", "user@example.com")
|
|
40
|
+
await systemTest.interact("[data-testid='signInPasswordInput']", "sendKeys", "password")
|
|
41
|
+
|
|
42
|
+
const emailInputValue = await systemTest.interact("[data-testid='signInEmailInput']", "getAttribute", "value")
|
|
43
|
+
const passwordInputValue = await systemTest.interact("[data-testid='signInPasswordInput']", "getAttribute", "value")
|
|
44
|
+
|
|
45
|
+
expect(emailInputValue).toEqual("user@example.com")
|
|
46
|
+
expect(passwordInputValue).toEqual("password")
|
|
47
|
+
|
|
48
|
+
await systemTest.click("[data-testid='signInSubmitButton']")
|
|
49
|
+
await systemTest.expectNotificationMessage("You were signed in.")
|
|
50
|
+
|
|
51
|
+
await waitFor(async () => {
|
|
52
|
+
const optionUserID = await Option.findBy({key: "userID"})
|
|
53
|
+
|
|
54
|
+
if (!optionUserID) {
|
|
55
|
+
throw new Error("Option for user ID didn't exist")
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
expect(optionUserID.value()).toEqual("805")
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
```
|
package/package.json
CHANGED
package/src/system-test.js
CHANGED
|
@@ -151,14 +151,31 @@ export default class SystemTest {
|
|
|
151
151
|
*
|
|
152
152
|
* @param {import("selenium-webdriver").WebElement} element
|
|
153
153
|
**/
|
|
154
|
-
async click(
|
|
155
|
-
|
|
156
|
-
element = await this.find(element)
|
|
157
|
-
}
|
|
154
|
+
async click(elementOrIdentifier) {
|
|
155
|
+
let tries = 0
|
|
158
156
|
|
|
159
|
-
|
|
157
|
+
while (true) {
|
|
158
|
+
tries++
|
|
160
159
|
|
|
161
|
-
|
|
160
|
+
try {
|
|
161
|
+
const element = await this._findElement(elementOrIdentifier)
|
|
162
|
+
const actions = this.driver.actions({async: true})
|
|
163
|
+
|
|
164
|
+
await actions.move({origin: element}).click().perform()
|
|
165
|
+
break
|
|
166
|
+
} catch (error) {
|
|
167
|
+
if (error.constructor.name === "ElementNotInteractableError") {
|
|
168
|
+
if (tries >= 3) {
|
|
169
|
+
throw new Error(`Element ${element.constructor.name} click failed after ${tries} tries - ${error.constructor.name}: ${error.message}`)
|
|
170
|
+
} else {
|
|
171
|
+
await wait(50)
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
// Re-throw with un-corrupted stack trace
|
|
175
|
+
throw new Error(`Element ${element.constructor.name} click failed - ${error.constructor.name}: ${error.message}`)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
162
179
|
}
|
|
163
180
|
|
|
164
181
|
/**
|
|
@@ -198,6 +215,18 @@ export default class SystemTest {
|
|
|
198
215
|
*/
|
|
199
216
|
async findByTestID(testID, args) { return await this.find(`[data-testid='${testID}']`, args) }
|
|
200
217
|
|
|
218
|
+
async _findElement(elementOrIdentifier) {
|
|
219
|
+
let element
|
|
220
|
+
|
|
221
|
+
if (typeof elementOrIdentifier == "string") {
|
|
222
|
+
element = await this.find(elementOrIdentifier)
|
|
223
|
+
} else {
|
|
224
|
+
element = elementOrIdentifier
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return element
|
|
228
|
+
}
|
|
229
|
+
|
|
201
230
|
/**
|
|
202
231
|
* Finds a single element by CSS selector without waiting
|
|
203
232
|
*
|
|
@@ -256,20 +285,17 @@ export default class SystemTest {
|
|
|
256
285
|
* @returns {Promise<any>}
|
|
257
286
|
*/
|
|
258
287
|
async interact(elementOrIdentifier, methodName, ...args) {
|
|
259
|
-
let element
|
|
260
288
|
let tries = 0
|
|
261
289
|
|
|
262
290
|
while (true) {
|
|
263
291
|
tries++
|
|
264
292
|
|
|
265
|
-
|
|
266
|
-
element = await this.find(elementOrIdentifier)
|
|
267
|
-
} else {
|
|
268
|
-
element = elementOrIdentifier
|
|
269
|
-
}
|
|
293
|
+
const element = await this._findElement(elementOrIdentifier)
|
|
270
294
|
|
|
271
295
|
if (!element[methodName]) {
|
|
272
|
-
|
|
296
|
+
throw new Error(`${element.constructor.name} hasn't an attribute named: ${methodName}`)
|
|
297
|
+
} else if (typeof element[methodName] != "function") {
|
|
298
|
+
throw new Error(`${element.constructor.name}#${methodName} is not a function`)
|
|
273
299
|
}
|
|
274
300
|
|
|
275
301
|
try {
|
|
@@ -278,9 +304,17 @@ export default class SystemTest {
|
|
|
278
304
|
if (error.constructor.name === "ElementNotInteractableError") {
|
|
279
305
|
// Retry finding the element and interacting with it
|
|
280
306
|
if (tries >= 3) {
|
|
281
|
-
|
|
307
|
+
let elementDescription
|
|
308
|
+
|
|
309
|
+
if (typeof elementOrIdentifier == "string") {
|
|
310
|
+
elementDescription = `CSS selector ${elementOrIdentifier}`
|
|
311
|
+
} else {
|
|
312
|
+
elementDescription = `${element.constructor.name}`
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
throw new Error(`${elementDescription} ${methodName} failed after ${tries} tries - ${error.constructor.name}: ${error.message}`)
|
|
282
316
|
} else {
|
|
283
|
-
await wait(
|
|
317
|
+
await wait(50)
|
|
284
318
|
}
|
|
285
319
|
} else {
|
|
286
320
|
// Re-throw with un-corrupted stack trace
|