@bucky24/jsbehave 0.12.9 → 0.13.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.
- package/README.md +65 -66
- package/package.json +1 -1
- package/src/index.js +66 -22
package/README.md
CHANGED
|
@@ -9,23 +9,77 @@ In order to use this, you must have the webdriver for your chosen browser access
|
|
|
9
9
|
|
|
10
10
|
Running `jsbehave` directly will locate all files that end in `.behave` and will run them.
|
|
11
11
|
|
|
12
|
+
## Blocks
|
|
13
|
+
|
|
14
|
+
### Test Block
|
|
15
|
+
|
|
16
|
+
Defines a block of operations that runs when the test framework is triggered.
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
[test <test name>]
|
|
20
|
+
...
|
|
21
|
+
[endtest]
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Action Block
|
|
25
|
+
|
|
26
|
+
Defines an Action. This is similar to a test in that it is a block of operations. Actions are not run automatically, however, and require a specific Operation to run them.
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
[action <action name>]`
|
|
30
|
+
...
|
|
31
|
+
[endaction]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Before and After blocks
|
|
35
|
+
|
|
36
|
+
Code in these blocks looks like the following:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
[before all]
|
|
40
|
+
open chrome
|
|
41
|
+
[endbefore]
|
|
42
|
+
|
|
43
|
+
[before each]
|
|
44
|
+
reload page
|
|
45
|
+
[endbefore]
|
|
46
|
+
|
|
47
|
+
[test blah]
|
|
48
|
+
|
|
49
|
+
[endtest]
|
|
50
|
+
|
|
51
|
+
[after each]
|
|
52
|
+
# cleanup
|
|
53
|
+
[endafter]
|
|
54
|
+
|
|
55
|
+
[after all]
|
|
56
|
+
close browser
|
|
57
|
+
[endafter]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`[before all]` blocks will run before all the tests. `[before each]` runs before each test. `[after each]` runs after each test, and `[after all]` runs after all the tests are done. This is similar to most other test systems.
|
|
61
|
+
|
|
12
62
|
## Operations
|
|
13
63
|
|
|
14
64
|
`open <browser>` (note the name for this browser is `default`)
|
|
15
65
|
|
|
66
|
+
`open <browser> as <name>` - opens a new browser and attaches its session to the given name
|
|
67
|
+
|
|
68
|
+
`set active browser to <name>` - sets the current active browser (the one that operations will be run on)
|
|
69
|
+
|
|
70
|
+
`close browser` - closes the active browser
|
|
71
|
+
|
|
72
|
+
`close browser <name>` - closes browser with given name
|
|
73
|
+
|
|
16
74
|
`navigate to <url>`
|
|
17
75
|
|
|
18
76
|
`type <text> into <selector>`
|
|
19
77
|
|
|
20
78
|
`wait for title to be <text>`
|
|
21
79
|
|
|
22
|
-
`[test <string>]`
|
|
23
|
-
|
|
24
|
-
`[endtest]`
|
|
25
|
-
|
|
26
80
|
`click <selector>`
|
|
27
81
|
|
|
28
|
-
`sleep <number>`
|
|
82
|
+
`sleep <number of seconds, can be fractional>`
|
|
29
83
|
|
|
30
84
|
`wait until located <selector>`
|
|
31
85
|
|
|
@@ -37,39 +91,29 @@ Running `jsbehave` directly will locate all files that end in `.behave` and will
|
|
|
37
91
|
|
|
38
92
|
`expect element <selector> to not exist`
|
|
39
93
|
|
|
40
|
-
`close browser`
|
|
41
|
-
|
|
42
94
|
`reload page`
|
|
43
95
|
|
|
44
|
-
`require test <test name>` runs the test only if it has not already been run
|
|
96
|
+
`require test <test name>` - runs the test only if it has not already been run
|
|
45
97
|
|
|
46
98
|
`expect elements <selector> to have count of <count>`
|
|
47
99
|
|
|
48
100
|
`expect variable <variable> to match <text>`
|
|
49
101
|
|
|
50
|
-
`open <browser> as <name>`
|
|
51
|
-
|
|
52
|
-
`close browser <name>`
|
|
53
|
-
|
|
54
|
-
`set active browser to <name>`
|
|
55
|
-
|
|
56
102
|
`expect element <selector> to have content <text>`
|
|
57
103
|
|
|
58
104
|
`set variable <variable name> to <text>`
|
|
59
105
|
|
|
60
106
|
`concat variable <variable name> with <text>`
|
|
61
107
|
|
|
62
|
-
`
|
|
63
|
-
|
|
64
|
-
`[action <action name>]`
|
|
108
|
+
`concat variables <variable name> and <variable name>` - concats two variables, storing the result in the first variable
|
|
65
109
|
|
|
66
|
-
`
|
|
110
|
+
`run test <test name>` - runs the test regardless if it has been run before
|
|
67
111
|
|
|
68
|
-
`run action <action name>` runs the given action
|
|
112
|
+
`run action <action name>` - runs the given action
|
|
69
113
|
|
|
70
|
-
`switch to window <index>` switches context to the window handle at the index (useful for popups)
|
|
114
|
+
`switch to window <index>` - switches context to the window handle at the index (useful for popups)
|
|
71
115
|
|
|
72
|
-
`read content from element <selector> into variable <variable name>` Takes the value or inner html from the element and stores it in the given variable
|
|
116
|
+
`read content from element <selector> into variable <variable name>` - Takes the value or inner html from the element and stores it in the given variable
|
|
73
117
|
|
|
74
118
|
## Tests
|
|
75
119
|
|
|
@@ -134,51 +178,6 @@ The following are configs that the jsbehave system will use for various operatio
|
|
|
134
178
|
| screenshotDirectory | The directory where screenshots will be saved. Defaults to `.` |
|
|
135
179
|
| screenshotOnFailure | Boolean. If true (default), takes a screenshot when the test fails. |
|
|
136
180
|
|
|
137
|
-
## Before and After blocks
|
|
138
|
-
|
|
139
|
-
Code in these blocks looks like the following:
|
|
140
|
-
|
|
141
|
-
```
|
|
142
|
-
[before all]
|
|
143
|
-
open chrome
|
|
144
|
-
[endbefore]
|
|
145
|
-
|
|
146
|
-
[before each]
|
|
147
|
-
reload page
|
|
148
|
-
[endbefore]
|
|
149
|
-
|
|
150
|
-
[test blah]
|
|
151
|
-
|
|
152
|
-
[endtest]
|
|
153
|
-
|
|
154
|
-
[after each]
|
|
155
|
-
# cleanup
|
|
156
|
-
[endafter]
|
|
157
|
-
|
|
158
|
-
[after all]
|
|
159
|
-
close browser
|
|
160
|
-
[endafter]
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
`[before all]` blocks will run before all the tests. `[before each]` runs before each test. `[after each]` runs after each test, and `[after all]` runs after all the tests are done. This is similar to most other test systems.
|
|
164
|
-
|
|
165
|
-
## Action blocks
|
|
166
|
-
|
|
167
|
-
Code in these blocks looks like the following:
|
|
168
|
-
```
|
|
169
|
-
[action some action]
|
|
170
|
-
open chrome
|
|
171
|
-
[endaction]
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
These actions are identical to test blocks, except they are not automatically run when tests are run. They can be run as follows:
|
|
175
|
-
|
|
176
|
-
```
|
|
177
|
-
[test a test]
|
|
178
|
-
run action some action
|
|
179
|
-
[endtest]
|
|
180
|
-
```
|
|
181
|
-
|
|
182
181
|
## Custom code
|
|
183
182
|
|
|
184
183
|
In order to load custom code, put `load funcs <filename>` in your test file. Functions can be async.
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -22,6 +22,7 @@ if (process.argv.length > 2) {
|
|
|
22
22
|
.filter(e => {
|
|
23
23
|
return e.isFile() && e.name.endsWith(".behave");
|
|
24
24
|
})
|
|
25
|
+
.filter(e => !e.path.includes('node_modules'))
|
|
25
26
|
.map(e => path.join(e.path, e.name));
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -251,7 +252,7 @@ function closeBrowser() {
|
|
|
251
252
|
const activeBrowser = getVariable("jsbehave.active_driver");
|
|
252
253
|
const driver = getVariable(`jsbehave.driver.${activeBrowser}`);
|
|
253
254
|
if (!driver) {
|
|
254
|
-
throw new Error("Unable to close
|
|
255
|
+
throw new Error("Unable to close active browser: no driver found");
|
|
255
256
|
}
|
|
256
257
|
delete variables[`jsbehave.driver.${activeBrowser}`];
|
|
257
258
|
return driver.close();
|
|
@@ -268,15 +269,18 @@ async function noop() {
|
|
|
268
269
|
|
|
269
270
|
async function runTest(name, showTitle=false) {
|
|
270
271
|
for (const before of beforeEach) {
|
|
271
|
-
await handleLines(before);
|
|
272
|
+
const result = await handleLines(before);
|
|
273
|
+
if (!result) return false;
|
|
272
274
|
}
|
|
273
275
|
if (showTitle) {
|
|
274
276
|
console.log("Running '" + name + "'");
|
|
275
277
|
}
|
|
276
278
|
const content = allTests[name];
|
|
277
|
-
await handleLines(content);
|
|
279
|
+
const result = await handleLines(content);
|
|
280
|
+
if (!result) return false;
|
|
278
281
|
for (const after of afterEach) {
|
|
279
|
-
await handleLines(after);
|
|
282
|
+
const result = await handleLines(after);
|
|
283
|
+
if (!result) return false;
|
|
280
284
|
}
|
|
281
285
|
|
|
282
286
|
const testsRun = getVariable("jsbehave.run_tests");
|
|
@@ -284,6 +288,8 @@ async function runTest(name, showTitle=false) {
|
|
|
284
288
|
...testsRun,
|
|
285
289
|
name,
|
|
286
290
|
];
|
|
291
|
+
|
|
292
|
+
return true;
|
|
287
293
|
}
|
|
288
294
|
|
|
289
295
|
async function runAction(name, showTitle=false) {
|
|
@@ -404,11 +410,11 @@ async function compareContent([ selector, text ]) {
|
|
|
404
410
|
if (text instanceof RegExp && text.test(value)) {
|
|
405
411
|
return;
|
|
406
412
|
}
|
|
407
|
-
if (value
|
|
413
|
+
if (value?.includes(text)) {
|
|
408
414
|
return;
|
|
409
415
|
}
|
|
410
416
|
|
|
411
|
-
throw new Error(`Expected element to have inner html of "${text}". Instead it had inner html of "${html}"`);
|
|
417
|
+
throw new Error(`Expected element to have inner html of "${text}". Instead it had inner html of "${html}" and value of "${value}"`);
|
|
412
418
|
}
|
|
413
419
|
|
|
414
420
|
function doSetVariable([ key, input ]) {
|
|
@@ -423,6 +429,12 @@ function concatVariable([ key, input ]) {
|
|
|
423
429
|
setVariable(key, `${oldValue}${finalInput}`);
|
|
424
430
|
}
|
|
425
431
|
|
|
432
|
+
function concatVariable([ key, key2 ]) {
|
|
433
|
+
const var1 = getVariable(key) || '';
|
|
434
|
+
const var2 = getVariable(key2) || "";
|
|
435
|
+
setVariable(key, `${var1}${var2}`);
|
|
436
|
+
}
|
|
437
|
+
|
|
426
438
|
async function executeJS(code) {
|
|
427
439
|
return driver().executeScript(code);
|
|
428
440
|
}
|
|
@@ -526,6 +538,7 @@ const operations = {
|
|
|
526
538
|
"expect element (.+) to have content (.+)": compareContent,
|
|
527
539
|
"set variable (.+) to (.+)": doSetVariable,
|
|
528
540
|
"concat variable (.+) with (.+)": concatVariable,
|
|
541
|
+
"concat variables (.+) and (.+)": concatVariables,
|
|
529
542
|
"run test (.+)": doRunTest,
|
|
530
543
|
"run action (.+)": doRunAction,
|
|
531
544
|
[startActionRegex]: startBlock,
|
|
@@ -536,7 +549,7 @@ const operations = {
|
|
|
536
549
|
|
|
537
550
|
async function handleLines(lines) {
|
|
538
551
|
for (let i=0;i<lines.length;i++) {
|
|
539
|
-
const line = lines[i];
|
|
552
|
+
const { lineNum, line } = lines[i];
|
|
540
553
|
if (line === "") {
|
|
541
554
|
continue;
|
|
542
555
|
}
|
|
@@ -574,8 +587,15 @@ async function handleLines(lines) {
|
|
|
574
587
|
const test = variables["jsbehave.activeBlock"];
|
|
575
588
|
if (test) {
|
|
576
589
|
console.log(`Test ${test} - FAILURE`);
|
|
577
|
-
console.log(`Failed on line ${
|
|
578
|
-
|
|
590
|
+
console.log(`Failed on line ${lineNum}: "${line}" for "${operation}"`);
|
|
591
|
+
const errorType = error.constructor.name;
|
|
592
|
+
if (errorType === "NoSuchElementError") {
|
|
593
|
+
console.log(`Could not find any matching element`);
|
|
594
|
+
} else {
|
|
595
|
+
console.log(error.constructor.name, error);
|
|
596
|
+
}
|
|
597
|
+
// newline
|
|
598
|
+
console.log();
|
|
579
599
|
const screenshotOnFailure = getVariable("screenshotOnFailure") === 'true';
|
|
580
600
|
if (screenshotOnFailure) {
|
|
581
601
|
const screenshot = await takeScreenshot(test);
|
|
@@ -584,7 +604,7 @@ async function handleLines(lines) {
|
|
|
584
604
|
} else {
|
|
585
605
|
console.error(error);
|
|
586
606
|
}
|
|
587
|
-
return;
|
|
607
|
+
return false;
|
|
588
608
|
}
|
|
589
609
|
handled = true;
|
|
590
610
|
break;
|
|
@@ -595,9 +615,12 @@ async function handleLines(lines) {
|
|
|
595
615
|
console.log(`Unable to handle "${line}"`);
|
|
596
616
|
}
|
|
597
617
|
}
|
|
618
|
+
|
|
619
|
+
return true;
|
|
598
620
|
}
|
|
599
621
|
|
|
600
622
|
(async function main() {
|
|
623
|
+
const allFailures = [];
|
|
601
624
|
for (const fileName of fileNames) {
|
|
602
625
|
const contents = fs.readFileSync(fileName, "utf-8");
|
|
603
626
|
const lines = contents.split(EOL);
|
|
@@ -617,7 +640,8 @@ async function handleLines(lines) {
|
|
|
617
640
|
let testName = null;
|
|
618
641
|
let allOrEach = null;
|
|
619
642
|
let inAction = false;
|
|
620
|
-
for (
|
|
643
|
+
for (let i=0;i<lines.length;i++) {
|
|
644
|
+
const line = lines[i];
|
|
621
645
|
if (line === "") {
|
|
622
646
|
continue;
|
|
623
647
|
}
|
|
@@ -660,7 +684,10 @@ async function handleLines(lines) {
|
|
|
660
684
|
}
|
|
661
685
|
}
|
|
662
686
|
|
|
663
|
-
testLines.push(
|
|
687
|
+
testLines.push({
|
|
688
|
+
lineNum: i+1,
|
|
689
|
+
line,
|
|
690
|
+
});
|
|
664
691
|
|
|
665
692
|
if (line.startsWith("[endtest")) {
|
|
666
693
|
inTest = false;
|
|
@@ -697,6 +724,8 @@ async function handleLines(lines) {
|
|
|
697
724
|
endLines = [...testLines];
|
|
698
725
|
}
|
|
699
726
|
|
|
727
|
+
let anyError = false;
|
|
728
|
+
|
|
700
729
|
if (specificTest) {
|
|
701
730
|
if (!allTests[specificTest]) {
|
|
702
731
|
console.log("No test case found for '" + specificTest + "'");
|
|
@@ -704,34 +733,49 @@ async function handleLines(lines) {
|
|
|
704
733
|
return;
|
|
705
734
|
}
|
|
706
735
|
|
|
707
|
-
await handleLines(startLines);
|
|
736
|
+
let result = await handleLines(startLines);
|
|
737
|
+
if (!result) anyError = true;
|
|
708
738
|
console.log("Running beforeAll");
|
|
709
739
|
for (const before of beforeAll) {
|
|
710
|
-
await handleLines(before);
|
|
740
|
+
result = await handleLines(before);
|
|
741
|
+
if (!result) anyError = true;
|
|
711
742
|
}
|
|
712
|
-
await runTest(specificTest, true);
|
|
743
|
+
result = await runTest(specificTest, true);
|
|
744
|
+
if (!result) anyError = true;
|
|
713
745
|
console.log("Running afterAll");
|
|
714
746
|
for (const after of afterAll) {
|
|
715
|
-
await handleLines(after);
|
|
747
|
+
result = await handleLines(after);
|
|
748
|
+
if (!result) anyError = true;
|
|
716
749
|
}
|
|
717
|
-
await handleLines(endLines);
|
|
750
|
+
const anyError = await handleLines(endLines);
|
|
718
751
|
} else {
|
|
719
|
-
await handleLines(startLines);
|
|
752
|
+
let result = await handleLines(startLines);
|
|
753
|
+
if (!result) anyError = true;
|
|
720
754
|
console.log("Running beforeAll");
|
|
721
755
|
for (const before of beforeAll) {
|
|
722
|
-
await handleLines(before);
|
|
756
|
+
result = await handleLines(before);
|
|
757
|
+
if (!result) anyError = true;
|
|
723
758
|
}
|
|
724
759
|
for (const testName in allTests) {
|
|
725
|
-
await runTest(testName, true);
|
|
760
|
+
result = await runTest(testName, true);
|
|
761
|
+
if (!result) anyError = true;
|
|
726
762
|
}
|
|
727
763
|
console.log("Running afterAll");
|
|
728
764
|
for (const after of afterAll) {
|
|
729
|
-
await handleLines(after);
|
|
765
|
+
result = await handleLines(after);
|
|
766
|
+
if (!result) anyError = true;
|
|
730
767
|
}
|
|
731
|
-
await handleLines(endLines);
|
|
768
|
+
result = await handleLines(endLines);
|
|
769
|
+
if (!result) anyError = true;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
if (anyError) {
|
|
773
|
+
allFailures.push(fileName);
|
|
732
774
|
}
|
|
733
775
|
}
|
|
734
776
|
|
|
777
|
+
console.log(`All failing tests:\n${allFailures.join("\n")}`);
|
|
778
|
+
|
|
735
779
|
// force terminate
|
|
736
780
|
process.exit(0);
|
|
737
781
|
})();
|