Skip to content

Commit

Permalink
Merge pull request #354 from GuillaumeGomez/variables
Browse files Browse the repository at this point in the history
Add `assert-variable`, `assert-variable-false`, `store-property` and `store-value` commands
  • Loading branch information
GuillaumeGomez authored Sep 22, 2022
2 parents e5cab4b + b655677 commit 4b5d7ae
Show file tree
Hide file tree
Showing 8 changed files with 427 additions and 2 deletions.
53 changes: 53 additions & 0 deletions goml-script.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ text: ("#an-element", |A_VARIABLE|)

In here, it'll set "#an-element" element's text to "12".

If you want to set a variable from inside a script, use one of the `store-*` commands. Important to be noted: the created variables only override the variables set with `--variable` in the current script and don't change environment variables.

A small note: the variable `CURRENT_DIR` is always available (and contains the directory where the script has been started) and **cannot** be override! It is also guaranteed to never end with `/` or `\\`.

## Command list
Expand All @@ -73,6 +75,8 @@ Here's the command list:
* [`assert-property-false`](#assert-property-false)
* [`assert-text`](#assert-text)
* [`assert-text-false`](#assert-text-false)
* [`assert-variable`](#assert-variable)
* [`assert-variable-false`](#assert-variable-false)
* [`assert-window-property`](#assert-window-property)
* [`assert-window-property-false`](#assert-window-property-false)
* [`attribute`](#attribute)
Expand Down Expand Up @@ -114,6 +118,8 @@ Here's the command list:
* [`scroll-to`](#scroll-to)
* [`show-text`](#show-text)
* [`size`](#size)
* [`store-property`](#store-property)
* [`store-value`](#store-value)
* [`text`](#text)
* [`timeout`](#timeout)
* [`wait-for`](#wait-for)
Expand Down Expand Up @@ -493,6 +499,30 @@ Please note that if you want to compare DOM elements, you should take a look at

Another thing to be noted: if you don't care wether the selector exists or not either, take a look at the [`fail`](#fail) command too.

#### assert-variable

**assert-variable** commands checks that the value of the given variable is the one provided. Examples:

```
assert-variable: (variable_name, "hello")
assert-variable: (variable_name, 12)
assert-variable: (variable_name, 12.1)
```

For more information about variables, read the [variables section](#variables).

#### assert-variable-false

**assert-variable-false** commands checks that the value of the given variable is not the one provided. Examples:

```
assert-variable-false: (variable_name, "hello")
assert-variable-false: (variable_name, 12)
assert-variable-false: (variable_name, 12.1)
```

For more information about variables, read the [variables section](#variables).

#### assert-window-property

**assert-window-property** command checks the properties' value of the `window` object of a webpage have the provided value. Examples:
Expand Down Expand Up @@ -1075,6 +1105,29 @@ show-text: true // text won't be invisible anymore
size: (700, 1000)
```

#### store-property

**store-property** command stores an element's property into a variable. Examples:

```
store-property: (variable_name, "#button", "clientHeight")
store-property: (variable_name, "#button", "scrollHeight")
```

For more information about variables, read the [variables section](#variables).

#### store-value

**store-value** command stores a value into a variable. The value can be a number of a string. Examples:

```
store-value: (variable_name, "hello")
store-value: (variable_name, 1)
store-value: (variable_name, 1.45)
```

For more information about variables, read the [variables section](#variables).

#### text

**text** command allows to update an element's text. Example:
Expand Down
9 changes: 9 additions & 0 deletions src/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const ORDERS = {
'assert-property-false': commands.parseAssertPropertyFalse,
'assert-text': commands.parseAssertText,
'assert-text-false': commands.parseAssertTextFalse,
'assert-variable': commands.parseAssertVariable,
'assert-variable-false': commands.parseAssertVariableFalse,
'assert-window-property': commands.parseAssertWindowProperty,
'assert-window-property-false': commands.parseAssertWindowPropertyFalse,
'attribute': commands.parseAttribute,
Expand Down Expand Up @@ -63,6 +65,8 @@ const ORDERS = {
'scroll-to': commands.parseScrollTo,
'show-text': commands.parseShowText,
'size': commands.parseSize,
'store-property': commands.parseStoreProperty,
'store-value': commands.parseStoreValue,
'text': commands.parseText,
'timeout': commands.parseTimeout,
'wait-for': commands.parseWaitFor,
Expand All @@ -86,6 +90,8 @@ const FATAL_ERROR_COMMANDS = [
'move-cursor-to',
'screenshot',
'scroll-to',
'store-property',
'store-value',
'text',
'wait-for',
'wait-for-attribute',
Expand All @@ -96,12 +102,15 @@ const FATAL_ERROR_COMMANDS = [

// Commands which do not run JS commands but change the behavior of the commands following.
const NO_INTERACTION_COMMANDS = [
'assert-variable',
'assert-variable-false',
'debug',
'emulate',
'fail',
'fail-on-js-error',
'javascript',
'screenshot-comparison',
'store-value',
'timeout',
];

Expand Down
5 changes: 5 additions & 0 deletions src/commands/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const emulation = require('./emulation.js');
const general = require('./general.js');
const input = require('./input.js');
const navigation = require('./navigation.js');
const store = require('./store.js');

module.exports = {
'parseAssert': assert.parseAssert,
Expand All @@ -28,6 +29,8 @@ module.exports = {
'parseAssertPropertyFalse': assert.parseAssertPropertyFalse,
'parseAssertText': assert.parseAssertText,
'parseAssertTextFalse': assert.parseAssertTextFalse,
'parseAssertVariable': assert.parseAssertVariable,
'parseAssertVariableFalse': assert.parseAssertVariableFalse,
'parseAssertWindowProperty': assert.parseAssertWindowProperty,
'parseAssertWindowPropertyFalse': assert.parseAssertWindowPropertyFalse,
'parseAttribute': dom_modifiers.parseAttribute,
Expand Down Expand Up @@ -69,6 +72,8 @@ module.exports = {
'parseScrollTo': input.parseScrollTo,
'parseShowText': context_setters.parseShowText,
'parseSize': emulation.parseSize,
'parseStoreProperty': store.parseStoreProperty,
'parseStoreValue': store.parseStoreValue,
'parseText': dom_modifiers.parseText,
'parseTimeout': context_setters.parseTimeout,
'parseWaitFor': general.parseWaitFor,
Expand Down
52 changes: 52 additions & 0 deletions src/commands/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -1228,6 +1228,56 @@ function parseAssertLocalStorageFalse(parser) {
return parseAssertLocalStorageInner(parser, true);
}

function parseAssertVariableInner(parser, operator) {
const elems = parser.elems;

if (elems.length === 0) {
return {'error': 'expected a tuple, found nothing'};
} else if (elems.length !== 1 || elems[0].kind !== 'tuple') {
return {'error': `expected a tuple, found \`${parser.getRawArgs()}\``};
}
const tuple = elems[0].getRaw();
if (tuple.length !== 2) {
let err = `expected 2 elements in the tuple, found ${tuple.length} element`;
if (tuple.length > 1) {
err += 's';
}
return {'error': err};
} else if (tuple[0].kind !== 'ident') {
return {
'error': 'expected first argument to be an ident, ' +
`found ${tuple[0].getArticleKind()} (\`${tuple[0].getText()}\`)`,
};
} else if (tuple[1].kind !== 'number' && tuple[1].kind !== 'string') {
return {
'error': `expected second argument to be a number or a string, found \
${tuple[1].getArticleKind()} (\`${tuple[1].getText()}\`)`,
};
}
return {
'instructions': [`\
if (arg.variables["${tuple[0].getText()}"] ${operator} ${tuple[1].getText()}) {
throw 'variable (of value \`' + arg.variables["${tuple[0].getText()}"] + '\` ${operator} \`' + \
${tuple[1].getText()} + '\`';
}`],
'wait': false,
};
}

// Possible inputs:
//
// * (ident, "string" | number)
function parseAssertVariable(parser) {
return parseAssertVariableInner(parser, '!=');
}

// Possible inputs:
//
// * (ident, "string" | number)
function parseAssertVariableFalse(parser) {
return parseAssertVariableInner(parser, '==');
}

module.exports = {
'parseAssert': parseAssert,
'parseAssertFalse': parseAssertFalse,
Expand All @@ -1247,6 +1297,8 @@ module.exports = {
'parseAssertPropertyFalse': parseAssertPropertyFalse,
'parseAssertText': parseAssertText,
'parseAssertTextFalse': parseAssertTextFalse,
'parseAssertVariable': parseAssertVariable,
'parseAssertVariableFalse': parseAssertVariableFalse,
'parseAssertWindowProperty': parseAssertWindowProperty,
'parseAssertWindowPropertyFalse': parseAssertWindowPropertyFalse,
};
106 changes: 106 additions & 0 deletions src/commands/store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// All `compare*` commands.

const { getAndSetElements } = require('./utils.js');

// Possible inputs:
//
// * (ident, "CSS selector" | "XPath", "property")
function parseStoreProperty(parser) {
const elems = parser.elems;

if (elems.length === 0) {
return {'error': 'expected a tuple, found nothing'};
} else if (elems.length !== 1 || elems[0].kind !== 'tuple') {
return {
'error': `expected a tuple, found \`${parser.getRawArgs()}\``,
};
}
const tuple = elems[0].getRaw();
if (tuple.length !== 3) {
let err = `expected 3 elements in the tuple, found ${tuple.length} element`;
if (tuple.length > 1) {
err += 's';
}
return {'error': err};
} else if (tuple[0].kind !== 'ident') {
return {
'error': `expected first argument to be an ident, found ${tuple[0].getArticleKind()} \
(\`${tuple[0].getText()}\`)`,
};
} else if (tuple[1].kind !== 'string') {
return {
'error': `expected second argument to be a string, found ${tuple[1].getArticleKind()} \
(\`${tuple[1].getText()}\`)`,
};
} else if (tuple[2].kind !== 'string') {
return {
'error': `expected third argument to be a CSS selector or an XPath, found \
${tuple[2].getArticleKind()} (\`${tuple[2].getText()}\`)`,
};
}

const selector = tuple[1].getSelector();
if (selector.error !== undefined) {
return selector;
}
const warnings = [];
const isPseudo = !selector.isXPath && selector.pseudo !== null;
if (isPseudo) {
warnings.push(`Pseudo-elements (\`${selector.pseudo}\`) don't have attributes so \
the check will be performed on the element itself`);
}

const varName = 'parseStoreProperty';
const code = `\
${getAndSetElements(selector, varName, false)}
const jsHandle = await ${varName}.evaluateHandle((e, p) => {
return String(e[p]);
}, ${tuple[2].getText()});
arg.variables["${tuple[0].getText()}"] = await jsHandle.jsonValue();`;

return {
'instructions': [code],
'wait': false,
'warnings': warnings.length !== 0 ? warnings : undefined,
};
}

// Possible inputs:
//
// * (ident, "string" | number)
function parseStoreValue(parser) {
const elems = parser.elems;

if (elems.length === 0) {
return {'error': 'expected a tuple, found nothing'};
} else if (elems.length !== 1 || elems[0].kind !== 'tuple') {
return {'error': `expected a tuple, found \`${parser.getRawArgs()}\``};
}
const tuple = elems[0].getRaw();
if (tuple.length !== 2) {
let err = `expected 2 elements in the tuple, found ${tuple.length} element`;
if (tuple.length > 1) {
err += 's';
}
return {'error': err};
} else if (tuple[0].kind !== 'ident') {
return {
'error': 'expected first argument to be an ident, ' +
`found ${tuple[0].getArticleKind()} (\`${tuple[0].getText()}\`)`,
};
} else if (tuple[1].kind !== 'number' && tuple[1].kind !== 'string') {
return {
'error': `expected second argument to be a number or a string, found \
${tuple[1].getArticleKind()} (\`${tuple[1].getText()}\`)`,
};
}
return {
'instructions': [`arg.variables["${tuple[0].getText()}"] = ${tuple[1].getText()};`],
'wait': false,
};
}

module.exports = {
'parseStoreProperty': parseStoreProperty,
'parseStoreValue': parseStoreValue,
};
Loading

0 comments on commit 4b5d7ae

Please sign in to comment.