Skip to content

Commit

Permalink
feat: Introduce a new instruction break to interrupt a loop
Browse files Browse the repository at this point in the history
  • Loading branch information
prantlf committed Jul 21, 2019
1 parent 4c8b597 commit e334603
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 17 deletions.
5 changes: 4 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
"type": "node",
"request": "launch",
"name": "grunt",
"program": "${workspaceFolder}/node_modules/grunt/bin/grunt"
"program": "${workspaceFolder}/node_modules/grunt/bin/grunt",
"args": [
"--verbose"
]
}
]
}
16 changes: 13 additions & 3 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -450,9 +450,19 @@ module.exports = function (grunt) {
},
{
repeat: 2,
do: {
click: 'input'
}
do: [
{
click: 'input'
},
{
if: {
isFocused: 'input'
},
then: {
break: 'input is in focus'
}
}
]
},
{
isFocused: 'input'
Expand Down
42 changes: 41 additions & 1 deletion INSTRUCTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ One of the instructions has to be present in every command. These properties are
- [isNotSelected](#isnotselected)
- [isNotVisible](#isnotvisible)
- [isNotVisibleWithinViewport](#isnotvisiblewithinviewport)
- [break](#break)
- [abort](#abort)
- [file](#file)

Expand Down Expand Up @@ -782,10 +783,49 @@ The input string should contain selector of the element to check.
}
```

## break
Type: `String`

Interrupts executing commands in a loop and advances to the next command on the level of the interrupted loop.

```js
{
url: 'https://google.com',
wait: '#lst-ib'
},
{
repeat: 10,
do: [
{
click: '#lst-ib'
},
{
if: {
isFocused: '#lst-ib'
},
then: {
break: 'input is in focus'
}
}
]
}
```

## abort
Type: `String`

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.
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.

```js
{
url: 'https://google.com',
wait: '#lst-ib',
file: 'google'
},
{
abort: 'after the page loads'
}
```

## file
Type: `String`
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ One of the [instructions] has to be present in every command, otherwise its exec
* [isNotSelected](INSTRUCTIONS.md#isnotselected)
* [isNotVisible](INSTRUCTIONS.md#isnotvisible)
* [isNotVisibleWithinViewport](INSTRUCTIONS.md#isnotvisiblewithinviewport)
* [break](INSTRUCTIONS.md#break)
* [abort](INSTRUCTIONS.md#abort)
* [file](INSTRUCTIONS.md#file)

Expand Down Expand Up @@ -609,7 +610,7 @@ your code using Grunt.
## Release History
* 2019-07-20 [v3.0.0] Report unrecognised instructions as errors
* 2019-07-21 [v3.0.0] Report unrecognised instructions as errors, introduce new instructions (focus, while-do, do-until, repeat-do, break)
* 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
* 2018-11-26 [v2.0.0] Use headless Chrome instead of PhantomJS by default, introduce conditional if-then-else instructions
* 2018-05-14 [v1.3.0] Allow saving snapshots to sub-directories, file numbering per-directory, add `scroll` instruction
Expand Down
43 changes: 33 additions & 10 deletions tasks/html-dom-snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const instructionKeys = [
'isEnabled', 'isExisting', 'isFocused', 'isSelected', 'isVisible',
'isVisibleWithinViewport', 'isNotEnabled', 'isNotExisting',
'isNotFocused', 'isNotSelected', 'isNotVisible',
'isNotVisibleWithinViewport', 'abort'
'isNotVisibleWithinViewport', 'break', 'abort'
]
const instructions = instructionKeys.map(instruction =>
require('./instructions/' + instruction))
Expand Down Expand Up @@ -242,10 +242,12 @@ module.exports = grunt => {

function performConditionalCommand (ifCommands, command) {
grunt.verbose.writeln('Testing a condition.')
const promise = new Promise(resolve => {
const promise = new Promise((resolve, reject) => {
performCommands(ifCommands)
.then(() => resolve(performConditionalBranch(command.then, true)))
.catch(() => resolve(performConditionalBranch(command.else, false)))
.then(() => performConditionalBranch(command.then, true)
.then(resolve, reject))
.catch(() => performConditionalBranch(command.else, false)
.then(resolve, reject))
})
promise.finally(() => grunt.verbose.writeln('The conditional command ended.'))
return promise
Expand All @@ -269,8 +271,15 @@ module.exports = grunt => {
performCommands(whileCommands)
.then(() => {
performLoopBody(command.do, 'Continuing with')
.then(() => resolve(runWhile()))
.catch(error => reject(error))
.then(() => runWhile()
.then(resolve, reject))
.catch(error => {
if (error.break) {
resolve()
} else {
reject(error)
}
})
})
.catch(() => resolve())
})
Expand All @@ -291,9 +300,16 @@ module.exports = grunt => {
grunt.verbose.writeln('Testing a condition after loop.')
performCommands(untilCommands)
.then(() => resolve())
.catch(() => resolve(runUntil()))
.catch(() => runUntil()
.then(resolve, reject))
})
.catch(error => {
if (error.break) {
resolve()
} else {
reject(error)
}
})
.catch(error => reject(error))
})
}

Expand All @@ -309,8 +325,15 @@ module.exports = grunt => {
updatePromise(reject)
if (counter++ < totalCount) {
performLoopBody(command.do, 'Repeating ' + counter + '/' + totalCount)
.then(() => resolve(runRepeat(totalCount)))
.catch(error => reject(error))
.then(() => runRepeat(totalCount)
.then(resolve, reject))
.catch(error => {
if (error.break) {
resolve()
} else {
reject(error)
}
})
} else {
resolve()
}
Expand Down
4 changes: 3 additions & 1 deletion tasks/instructions/abort.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ module.exports = {
},

perform: function (grunt, target, client, command) {
throw new Error('Aborted: "' + command.abort +
const reason = command.abort
grunt.verbose.writeln('Aborting: "' + reason + '".')
throw new Error('Aborted: "' + reason +
'" in the target "' + target + '".\n' +
JSON.stringify(command))
}
Expand Down
15 changes: 15 additions & 0 deletions tasks/instructions/break.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict'

module.exports = {
detect: function (command) {
return !!command.break
},

perform: function (grunt, target, client, command) {
const reason = command.break
grunt.verbose.writeln('Breaking the loop: "' + reason + '".')
var error = new Error('Break the loop')
error.break = reason
throw error
}
}

0 comments on commit e334603

Please sign in to comment.