Skip to content

Commit e334603

Browse files
committed
feat: Introduce a new instruction break to interrupt a loop
1 parent 4c8b597 commit e334603

File tree

7 files changed

+111
-17
lines changed

7 files changed

+111
-17
lines changed

.vscode/launch.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
"type": "node",
99
"request": "launch",
1010
"name": "grunt",
11-
"program": "${workspaceFolder}/node_modules/grunt/bin/grunt"
11+
"program": "${workspaceFolder}/node_modules/grunt/bin/grunt",
12+
"args": [
13+
"--verbose"
14+
]
1215
}
1316
]
1417
}

Gruntfile.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -450,9 +450,19 @@ module.exports = function (grunt) {
450450
},
451451
{
452452
repeat: 2,
453-
do: {
454-
click: 'input'
455-
}
453+
do: [
454+
{
455+
click: 'input'
456+
},
457+
{
458+
if: {
459+
isFocused: 'input'
460+
},
461+
then: {
462+
break: 'input is in focus'
463+
}
464+
}
465+
]
456466
},
457467
{
458468
isFocused: 'input'

INSTRUCTIONS.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ One of the instructions has to be present in every command. These properties are
3838
- [isNotSelected](#isnotselected)
3939
- [isNotVisible](#isnotvisible)
4040
- [isNotVisibleWithinViewport](#isnotvisiblewithinviewport)
41+
- [break](#break)
4142
- [abort](#abort)
4243
- [file](#file)
4344

@@ -782,10 +783,49 @@ The input string should contain selector of the element to check.
782783
}
783784
```
784785

786+
## break
787+
Type: `String`
788+
789+
Interrupts executing commands in a loop and advances to the next command on the level of the interrupted loop.
790+
791+
```js
792+
{
793+
url: 'https://google.com',
794+
wait: '#lst-ib'
795+
},
796+
{
797+
repeat: 10,
798+
do: [
799+
{
800+
click: '#lst-ib'
801+
},
802+
{
803+
if: {
804+
isFocused: '#lst-ib'
805+
},
806+
then: {
807+
break: 'input is in focus'
808+
}
809+
}
810+
]
811+
}
812+
```
813+
785814
## abort
786815
Type: `String`
787816

788-
Stops executing firther commands and fails current Grunt task with the specified message. It can be used to stop the tests at a specific point and investigate the situation in the web browser.
817+
Stops executing further commands and fails current Grunt task with the specified message. It can be used to stop the tests at a specific point and investigate the situation in the web browser.
818+
819+
```js
820+
{
821+
url: 'https://google.com',
822+
wait: '#lst-ib',
823+
file: 'google'
824+
},
825+
{
826+
abort: 'after the page loads'
827+
}
828+
```
789829

790830
## file
791831
Type: `String`

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ One of the [instructions] has to be present in every command, otherwise its exec
308308
* [isNotSelected](INSTRUCTIONS.md#isnotselected)
309309
* [isNotVisible](INSTRUCTIONS.md#isnotvisible)
310310
* [isNotVisibleWithinViewport](INSTRUCTIONS.md#isnotvisiblewithinviewport)
311+
* [break](INSTRUCTIONS.md#break)
311312
* [abort](INSTRUCTIONS.md#abort)
312313
* [file](INSTRUCTIONS.md#file)
313314

@@ -609,7 +610,7 @@ your code using Grunt.
609610
610611
## Release History
611612
612-
* 2019-07-20 [v3.0.0] Report unrecognised instructions as errors
613+
* 2019-07-21 [v3.0.0] Report unrecognised instructions as errors, introduce new instructions (focus, while-do, do-until, repeat-do, break)
613614
* 2019-07-08 [v2.2.0] Optionally hang the browser in case of failure to be able to inspect the web page in developer tools
614615
* 2018-11-26 [v2.0.0] Use headless Chrome instead of PhantomJS by default, introduce conditional if-then-else instructions
615616
* 2018-05-14 [v1.3.0] Allow saving snapshots to sub-directories, file numbering per-directory, add `scroll` instruction

tasks/html-dom-snapshot.js

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const instructionKeys = [
1515
'isEnabled', 'isExisting', 'isFocused', 'isSelected', 'isVisible',
1616
'isVisibleWithinViewport', 'isNotEnabled', 'isNotExisting',
1717
'isNotFocused', 'isNotSelected', 'isNotVisible',
18-
'isNotVisibleWithinViewport', 'abort'
18+
'isNotVisibleWithinViewport', 'break', 'abort'
1919
]
2020
const instructions = instructionKeys.map(instruction =>
2121
require('./instructions/' + instruction))
@@ -242,10 +242,12 @@ module.exports = grunt => {
242242

243243
function performConditionalCommand (ifCommands, command) {
244244
grunt.verbose.writeln('Testing a condition.')
245-
const promise = new Promise(resolve => {
245+
const promise = new Promise((resolve, reject) => {
246246
performCommands(ifCommands)
247-
.then(() => resolve(performConditionalBranch(command.then, true)))
248-
.catch(() => resolve(performConditionalBranch(command.else, false)))
247+
.then(() => performConditionalBranch(command.then, true)
248+
.then(resolve, reject))
249+
.catch(() => performConditionalBranch(command.else, false)
250+
.then(resolve, reject))
249251
})
250252
promise.finally(() => grunt.verbose.writeln('The conditional command ended.'))
251253
return promise
@@ -269,8 +271,15 @@ module.exports = grunt => {
269271
performCommands(whileCommands)
270272
.then(() => {
271273
performLoopBody(command.do, 'Continuing with')
272-
.then(() => resolve(runWhile()))
273-
.catch(error => reject(error))
274+
.then(() => runWhile()
275+
.then(resolve, reject))
276+
.catch(error => {
277+
if (error.break) {
278+
resolve()
279+
} else {
280+
reject(error)
281+
}
282+
})
274283
})
275284
.catch(() => resolve())
276285
})
@@ -291,9 +300,16 @@ module.exports = grunt => {
291300
grunt.verbose.writeln('Testing a condition after loop.')
292301
performCommands(untilCommands)
293302
.then(() => resolve())
294-
.catch(() => resolve(runUntil()))
303+
.catch(() => runUntil()
304+
.then(resolve, reject))
305+
})
306+
.catch(error => {
307+
if (error.break) {
308+
resolve()
309+
} else {
310+
reject(error)
311+
}
295312
})
296-
.catch(error => reject(error))
297313
})
298314
}
299315

@@ -309,8 +325,15 @@ module.exports = grunt => {
309325
updatePromise(reject)
310326
if (counter++ < totalCount) {
311327
performLoopBody(command.do, 'Repeating ' + counter + '/' + totalCount)
312-
.then(() => resolve(runRepeat(totalCount)))
313-
.catch(error => reject(error))
328+
.then(() => runRepeat(totalCount)
329+
.then(resolve, reject))
330+
.catch(error => {
331+
if (error.break) {
332+
resolve()
333+
} else {
334+
reject(error)
335+
}
336+
})
314337
} else {
315338
resolve()
316339
}

tasks/instructions/abort.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ module.exports = {
66
},
77

88
perform: function (grunt, target, client, command) {
9-
throw new Error('Aborted: "' + command.abort +
9+
const reason = command.abort
10+
grunt.verbose.writeln('Aborting: "' + reason + '".')
11+
throw new Error('Aborted: "' + reason +
1012
'" in the target "' + target + '".\n' +
1113
JSON.stringify(command))
1214
}

tasks/instructions/break.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use strict'
2+
3+
module.exports = {
4+
detect: function (command) {
5+
return !!command.break
6+
},
7+
8+
perform: function (grunt, target, client, command) {
9+
const reason = command.break
10+
grunt.verbose.writeln('Breaking the loop: "' + reason + '".')
11+
var error = new Error('Break the loop')
12+
error.break = reason
13+
throw error
14+
}
15+
}

0 commit comments

Comments
 (0)