Skip to content

Commit

Permalink
Add NEAR check mode for assert-(variable|property|document-property|w…
Browse files Browse the repository at this point in the history
…indow-property)
  • Loading branch information
notriddle committed Jan 15, 2023
1 parent ea03675 commit f09fda3
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 28 deletions.
36 changes: 26 additions & 10 deletions goml-script.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ assert-attribute: ("#id > .class", {"attribute-name": "attribute-value"}, ALL)
assert-attribute: ("//*[@id='id']/*[@class='class']", {"key1": "value1", "key2": "value2"}, ALL)
```

You can use more specific checks as well by using one of the following identifiers: "ALL", "CONTAINS", "ENDS_WITH" or "STARTS_WITH".
You can use more specific checks as well by using one of the following identifiers: "ALL", "CONTAINS", "ENDS_WITH", "STARTS_WITH", or "NEAR".

```
assert-attribute: (
Expand Down Expand Up @@ -235,7 +235,7 @@ assert-attribute-false: ("#id > .class", {"attribute-name": "attribute-value"},
assert-attribute-false: ("//*[@id='id']/*[@class='class']", {"key1": "value1", "key2": "value2"}, ALL)
```

You can use more specific checks as well by using one of the following identifiers: "ALL", "CONTAINS", "ENDS_WITH" or "STARTS_WITH".
You can use more specific checks as well by using one of the following identifiers: "ALL", "CONTAINS", "ENDS_WITH", "STARTS_WITH", or "NEAR".

```
assert-attribute-false: (
Expand Down Expand Up @@ -321,7 +321,7 @@ assert-document-property: ({"URL": "https://some.where", "title": "a title"})
assert-document-property: {"URL": "https://some.where", "title": "a title"}
```

You can use more specific checks as well by using one of the following identifiers: "CONTAINS", "ENDS_WITH" or "STARTS_WITH".
You can use more specific checks as well by using one of the following identifiers: "CONTAINS", "ENDS_WITH", "STARTS_WITH", or "NEAR".

```
assert-document-property: ({"URL": "https://some.where", "title": "a title"}, STARTS_WITH)
Expand All @@ -343,7 +343,8 @@ assert-document-property-false: ({"URL": "https://some.where", "title": "a title
assert-document-property-false: {"URL": "https://some.where", "title": "a title"}
```

You can use more specific checks as well by using one of the following identifiers: "CONTAINS", "ENDS_WITH" or "STARTS_WITH".
You can use more specific checks as well by using one of the following identifiers: "CONTAINS", "ENDS_WITH",
"STARTS_WITH" or "NEAR".

```
assert-document-property-false: ({"URL": "https://some.where", "title": "a title"}, STARTS_WITH)
Expand Down Expand Up @@ -422,7 +423,7 @@ assert-property: ("#id > .class", { "offsetParent": "null" }, ALL)
assert-property: ("//*[@id='id']/*[@class='class']", { "offsetParent": "null", "clientTop": "10px" }, ALL)
```

You can use more specific checks as well by using one of the following identifiers: "ALL", "CONTAINS", "ENDS_WITH" or "STARTS_WITH".
You can use more specific checks as well by using one of the following identifiers: "ALL", "CONTAINS", "ENDS_WITH", "STARTS_WITH" or "NEAR".

```
assert-property: (
Expand Down Expand Up @@ -457,7 +458,7 @@ assert-property-false: ("#id > .class", { "offsetParent": "null" }, ALL)
assert-property-false: ("//*[@id='id']/*[@class='class']", { "offsetParent": "null", "clientTop": "10px" }, ALL)
```

You can use more specific checks as well by using one of the following identifiers: "ALL", "CONTAINS", "ENDS_WITH" or "STARTS_WITH".
You can use more specific checks as well by using one of the following identifiers: "ALL", "CONTAINS", "ENDS_WITH", "STARTS_WITH", or "NEAR".

```
assert-property-false: (
Expand Down Expand Up @@ -544,12 +545,27 @@ assert-variable: (variable_name, 12)
assert-variable: (variable_name, 12.1)
```

Apart from "CONTAINS", you can also use "ENDS_WITH" and "STARTS_WITH" and even combine them if you want. Example:
Apart from "CONTAINS", you can also use "ENDS_WITH", "STARTS_WITH" or "NEAR" and even combine them if you want. Example:

```
assert-variable: (variable_name, "hel", [CONTAINS, STARTS_WITH])
```

The `ENDS_WITH` and `STARTS_WITH` interpret the variable as a string, while `NEAR` interprets it as a number and asserts that the difference between the variable and the tested value is less than or equal to 1. This check is useful in cases where the browser rounds a potentially-fractional value to an integer, and may not always do it consistently from run to run:

```
// all of these assertions will pass
store-value: (variable_name, "hello")
assert-variable: (variable_name, "he", STARTS_WITH)
assert-variable: (variable_name, "o", ENDS_WITH)
store-value: (variable_name, 10)
assert-variable: (variable_name, 10, NEAR)
assert-variable: (variable_name, 9, NEAR)
assert-variable: (variable_name, 11, NEAR)
assert-variable-false: (variable_name, 8, NEAR)
assert-variable-false: (variable_name, 12, NEAR)
```

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

#### assert-variable-false
Expand All @@ -563,7 +579,7 @@ assert-variable-false: (variable_name, 12)
assert-variable-false: (variable_name, 12.1)
```

Apart from "CONTAINS", you can also use "ENDS_WITH" and "STARTS_WITH" and even combine them if you want. Example:
Apart from "CONTAINS", you can also use "ENDS_WITH", "STARTS_WITH" or "NEAR" and even combine them if you want. Example:

```
assert-variable-false: (variable_name, "hel", [CONTAINS, ENDS_WITH])
Expand All @@ -581,7 +597,7 @@ assert-window-property: ({"pageYOffset": "0", "location": "https://some.where"})
assert-window-property: {"pageYOffset": "0", "location": "https://some.where"}
```

You can use more specific checks as well by using one of the following identifiers: "CONTAINS", "ENDS_WITH" or "STARTS_WITH".
You can use more specific checks as well by using one of the following identifiers: "CONTAINS", "ENDS_WITH", "STARTS_WITH", or "NEAR".

```
assert-window-property: (
Expand Down Expand Up @@ -609,7 +625,7 @@ assert-window-property-false: ({"location": "https://some.where", "pageYOffset":
assert-window-property-false: {"location": "https://some.where", "pageYOffset": "10"}
```

You can use more specific checks as well by using one of the following identifiers: "CONTAINS", "ENDS_WITH" or "STARTS_WITH".
You can use more specific checks as well by using one of the following identifiers: "CONTAINS", "ENDS_WITH", "STARTS_WITH" or "NEAR".

```
assert-window-property-false: (
Expand Down
104 changes: 92 additions & 12 deletions src/commands/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ function parseAssertCssFalse(parser) {

function parseAssertObjPropertyInner(parser, assertFalse, objName) {
const elems = parser.elems;
const identifiers = ['CONTAINS', 'ENDS_WITH', 'STARTS_WITH'];
const identifiers = ['CONTAINS', 'ENDS_WITH', 'STARTS_WITH', 'NEAR'];

if (elems.length === 0) {
return {'error': 'expected a tuple or a JSON dict, found nothing'};
Expand Down Expand Up @@ -254,6 +254,27 @@ ENDS_WITH check)');
if (!String(${objName}[${varKey}]).endsWith(${varValue})) {
nonMatchingProps.push('Property \`' + ${varKey} + '\` (\`' + ${objName}[${varKey}] + '\
\`) does not end with \`' + ${varValue} + '\`');
}`);
}
}
if (enabled_checks['NEAR']) {
if (assertFalse) {
checks.push(`\
if (Number.isNaN(${objName}[${varKey}])) {
nonMatchingProps.push('Property \`' + ${varKey} + '\` (\`' + ${objName}[${varKey}] + '\
\`) is NaN');
} else if (Math.abs(${objName}[${varKey}] - ${varValue}) <= 1) {
nonMatchingProps.push('Property \`' + ${varKey} + '\` (\`' + ${objName}[${varKey}] + '\
\`) is within 1 of \`' + ${varValue} + '\`');
}`);
} else {
checks.push(`\
if (Number.isNaN(${objName}[${varKey}])) {
nonMatchingProps.push('Property \`' + ${varKey} + '\` (\`' + ${objName}[${varKey}] + '\
\`) is NaN');
} else if (Math.abs(${objName}[${varKey}] - ${varValue}) > 1) {
nonMatchingProps.push('Property \`' + ${varKey} + '\` (\`' + ${objName}[${varKey}] + '\
\`) is not within 1 of \`' + ${varValue} + '\`');
}`);
}
}
Expand Down Expand Up @@ -308,8 +329,8 @@ ${indentString(checks.join('\n'), 2)}
//
// * {"DOM property": "value"}
// * ({"DOM property": "value"})
// * ({"DOM property": "value"}, CONTAINS|ENDS_WITH|STARTS_WITH)
// * ({"DOM property": "value"}, [CONTAINS|ENDS_WITH|STARTS_WITH])
// * ({"DOM property": "value"}, CONTAINS|ENDS_WITH|STARTS_WITH|NEAR)
// * ({"DOM property": "value"}, [CONTAINS|ENDS_WITH|STARTS_WITH|NEAR])
function parseAssertDocumentProperty(parser) {
return parseAssertObjPropertyInner(parser, false, 'document');
}
Expand All @@ -318,8 +339,8 @@ function parseAssertDocumentProperty(parser) {
//
// * {"DOM property": "value"}
// * ({"DOM property": "value"})
// * ({"DOM property": "value"}, CONTAINS|ENDS_WITH|STARTS_WITH)
// * ({"DOM property": "value"}, [CONTAINS|ENDS_WITH|STARTS_WITH])
// * ({"DOM property": "value"}, CONTAINS|ENDS_WITH|STARTS_WITH|NEAR)
// * ({"DOM property": "value"}, [CONTAINS|ENDS_WITH|STARTS_WITH|NEAR])
function parseAssertDocumentPropertyFalse(parser) {
return parseAssertObjPropertyInner(parser, true, 'document');
}
Expand All @@ -328,8 +349,8 @@ function parseAssertDocumentPropertyFalse(parser) {
//
// * {"DOM property": "value"}
// * ({"DOM property": "value"})
// * ({"DOM property": "value"}, CONTAINS|ENDS_WITH|STARTS_WITH)
// * ({"DOM property": "value"}, [CONTAINS|ENDS_WITH|STARTS_WITH])
// * ({"DOM property": "value"}, CONTAINS|ENDS_WITH|STARTS_WITH|NEAR)
// * ({"DOM property": "value"}, [CONTAINS|ENDS_WITH|STARTS_WITH|NEAR])
function parseAssertWindowProperty(parser) {
return parseAssertObjPropertyInner(parser, false, 'window');
}
Expand All @@ -338,16 +359,16 @@ function parseAssertWindowProperty(parser) {
//
// * {"DOM property": "value"}
// * ({"DOM property": "value"})
// * ({"DOM property": "value"}, CONTAINS|ENDS_WITH|STARTS_WITH)
// * ({"DOM property": "value"}, [CONTAINS|ENDS_WITH|STARTS_WITH])
// * ({"DOM property": "value"}, CONTAINS|ENDS_WITH|STARTS_WITH|NEAR)
// * ({"DOM property": "value"}, [CONTAINS|ENDS_WITH|STARTS_WITH|NEAR])
function parseAssertWindowPropertyFalse(parser) {
return parseAssertObjPropertyInner(parser, true, 'window');
}

function parseAssertPropertyInner(parser, assertFalse) {
const err = 'Read the documentation to see the accepted inputs';
const elems = parser.elems;
const identifiers = ['ALL', 'CONTAINS', 'STARTS_WITH', 'ENDS_WITH'];
const identifiers = ['ALL', 'CONTAINS', 'STARTS_WITH', 'ENDS_WITH', 'NEAR'];
const warnings = [];
const enabled_checks = Object.create(null);

Expand Down Expand Up @@ -432,6 +453,27 @@ ENDS_WITH check)');
if (!String(e[${varKey}]).endsWith(${varValue})) {
nonMatchingProps.push('Property \`' + ${varKey} + '\` (\`' + e[${varKey}] + '\
\`) does not end with \`' + ${varValue} + '\`');
}`);
}
}
if (enabled_checks['NEAR']) {
if (assertFalse) {
checks.push(`\
if (Number.isNaN(e[${varKey}])) {
nonMatchingProps.push('Property \`' + ${varKey} + '\` (\`' + e[${varKey}] + '\
\`) is NaN');
} else if (Math.abs(e[${varKey}] - ${varValue}) <= 1) {
nonMatchingProps.push('Property \`' + ${varKey} + '\` (\`' + e[${varKey}] + '\
\`) is within 1 of \`' + ${varValue} + '\`');
}`);
} else {
checks.push(`\
if (Number.isNaN(e[${varKey}])) {
nonMatchingProps.push('Property \`' + ${varKey} + '\` (\`' + e[${varKey}] + '\
\`) is NaN');
} else if (Math.abs(e[${varKey}] - ${varValue}) > 1) {
nonMatchingProps.push('Property \`' + ${varKey} + '\` (\`' + e[${varKey}] + '\
\`) is not within 1 of \`' + ${varValue} + '\`');
}`);
}
}
Expand Down Expand Up @@ -544,7 +586,7 @@ function parseAssertPropertyFalse(parser) {
function parseAssertAttributeInner(parser, assertFalse) {
const err = 'Read the documentation to see the accepted inputs';
const elems = parser.elems;
const identifiers = ['ALL', 'CONTAINS', 'STARTS_WITH', 'ENDS_WITH'];
const identifiers = ['ALL', 'CONTAINS', 'STARTS_WITH', 'ENDS_WITH', 'NEAR'];
const warnings = [];
const enabled_checks = Object.create(null);

Expand Down Expand Up @@ -629,6 +671,27 @@ if (attr.endsWith(${varValue})) {
if (!attr.endsWith(${varValue})) {
nonMatchingAttrs.push("attribute \`" + ${varKey} + "\` (\`" + attr + "\`) doesn't end with \`"\
+ ${varValue} + "\`");
}`);
}
}
if (enabled_checks['NEAR']) {
if (assertFalse) {
checks.push(`\
if (Number.isNaN(attr)) {
nonMatchingProps.push('attribute \`' + ${varKey} + '\` (\`' + attr + '\
\`) is NaN');
} else if (Math.abs(attr] - ${varValue}) <= 1) {
nonMatchingProps.push('attribute \`' + ${varKey} + '\` (\`' + attr + '\
\`) is within 1 of \`' + ${varValue} '\`');
}`);
} else {
checks.push(`\
if (Number.isNaN(attr)) {
nonMatchingProps.push('Property \`' + ${varKey} + '\` (\`' + attr + '\
\`) is NaN');
} else if (Math.abs(attr - ${varValue}) > 1) {
nonMatchingProps.push('Property \`' + ${varKey} + '\` (\`' + attr + '\
\`) is not within 1 of \`' + ${varValue} '\`');
}`);
}
}
Expand Down Expand Up @@ -1264,7 +1327,7 @@ function parseAssertVariableInner(parser, assertFalse) {
${tuple[1].getArticleKind()} (\`${tuple[1].getErrorText()}\`)`,
};
} else if (tuple.length > 2) {
const identifiers = ['CONTAINS', 'STARTS_WITH', 'ENDS_WITH'];
const identifiers = ['CONTAINS', 'STARTS_WITH', 'ENDS_WITH', 'NEAR'];
const ret = fillEnabledChecks(tuple[2], identifiers, enabled_checks, warnings, 'third');
if (ret !== null) {
return ret;
Expand Down Expand Up @@ -1309,6 +1372,23 @@ if (value1.endsWith(value2)) {
checks.push(`\
if (!value1.endsWith(value2)) {
errors.push("\`" + value1 + "\` doesn't end with \`" + value2 + "\` (for ENDS_WITH check)");
}`);
}
}
if (enabled_checks['NEAR']) {
if (assertFalse) {
checks.push(`\
if (Number.isNaN(value1])) {
nonMatchingProps.push('\`' + value1 + '\` is NaN');
} else if (Math.abs(value1 - value2) <= 1) {
nonMatchingProps.push('\`' + value1 + '\` is within 1 of \`' + value2 '\`');
}`);
} else {
checks.push(`\
if (Number.isNaN(value1])) {
nonMatchingProps.push('\`' + value1 + '\` is NaN');
} else if (Math.abs(value1 - value2) > 1) {
nonMatchingProps.push('\`' + value1 + '\` is not within 1 of \`' + value2 '\`');
}`);
}
}
Expand Down
7 changes: 7 additions & 0 deletions tests/scripts/assert-document-property.goml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ assert-document-property-false: ({"title": "bsic"}, STARTS_WITH)
assert-document-property-false: ({"title": "bsic"}, CONTAINS)
assert-document-property-false: ({"title": "bsic"}, ENDS_WITH)
assert-document-property-false: ({"title": "bsic"}, [STARTS_WITH, CONTAINS])
assert-document-property: ({"nodeType": 9})
assert-document-property-false: ({"nodeType": 8})
assert-document-property: ({"nodeType": 9}, NEAR)
assert-document-property: ({"nodeType": 8}, NEAR)
assert-document-property-false: ({"nodeType": 7}, NEAR)
assert-document-property: ({"nodeType": 10}, NEAR)
assert-document-property-false: ({"nodeType": 11}, NEAR)
5 changes: 5 additions & 0 deletions tests/scripts/assert.goml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@ assert-count: ("div", 1)
assert-css: ("#button", {"padding": "5px"})
assert-attribute: ("#button", {"href": "./other_page.html"})
assert-property: ("#button", {"offsetParent": "null"})
assert-property: ("body", {"offsetTop": 0})
assert-property-false: ("body", {"offsetTop": 1})
assert-property: ("body", {"offsetTop": 0}, NEAR)
assert-property: ("body", {"offsetTop": 1}, NEAR)
assert-property-false: ("body", {"offsetTop": 2}, NEAR)
9 changes: 9 additions & 0 deletions tests/scripts/attribute.goml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,12 @@ assert-attribute: ("#yet-another-id", {"\"e": "'2"})
fail: false
attribute: ("#yet-another-id", "e", "'2")
assert-attribute: ("#yet-another-id", {"e": "'2"})
attribute: ("#yet-another-id", "e", "2")
assert-attribute: ("#yet-another-id", {"e": "2"})
assert-attribute-false: ("#yet-another-id", {"e": "3"})
assert-attribute: ("#yet-another-id", {"e": "2"}, NEAR)
assert-attribute: ("#yet-another-id", {"e": "3"}, NEAR)
assert-attribute: ("#yet-another-id", {"e": "1"}, NEAR)
fail: true
assert-attribute: ("#yet-another-id", {"e": "4"}, NEAR)
assert-attribute: ("#yet-another-id", {"e": "0"}, NEAR)
12 changes: 6 additions & 6 deletions tests/test-js/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,11 @@ function checkAssertAttributeInner(x, func, notFound, equal, contains, startsWit
});
x.assert(func('("a::after", {"a": 1}, all)'), {
'error': 'unknown identifier `all`. Available identifiers are: [`ALL`, `CONTAINS`, ' +
'`STARTS_WITH`, `ENDS_WITH`]',
'`STARTS_WITH`, `ENDS_WITH`, `NEAR`]',
});
x.assert(func('("a::after", {"a": 1}, ALLO)'), {
'error': 'unknown identifier `ALLO`. Available identifiers are: [`ALL`, `CONTAINS`, ' +
'`STARTS_WITH`, `ENDS_WITH`]',
'`STARTS_WITH`, `ENDS_WITH`, `NEAR`]',
});
x.assert(func('("a", {"b": "c", "b": "d"})'), {'error': 'attribute `b` is duplicated'});

Expand Down Expand Up @@ -667,7 +667,7 @@ ${equal(3)}
// Multiline
x.assert(func('("a::after", \n {"a": 1}, \n ALLO)'), {
'error': 'unknown identifier `ALLO`. Available identifiers are: [`ALL`, `CONTAINS`, ' +
'`STARTS_WITH`, `ENDS_WITH`]',
'`STARTS_WITH`, `ENDS_WITH`, `NEAR`]',
});
x.assert(func('("//a",\n \n{"b": "c"}, \n ALL)'), {
'instructions': [`\
Expand Down Expand Up @@ -878,7 +878,7 @@ function checkAssertObjPropertyInner(
x.assert(func('("a", "b" "c", ALL)'), {'error': 'expected `,` or `)`, found `"` after `"b"`'});
x.assert(func('({"a": "b"}, all)'), {
'error': 'unknown identifier `all`. Available identifiers are: [`CONTAINS`, `ENDS_WITH`, ' +
'`STARTS_WITH`]',
'`STARTS_WITH`, `NEAR`]',
});
x.assert(func('("a::after", {"a": 1}, ALLO)'), {
'error': 'expected a tuple of one or two elements, found 3 elements',
Expand Down Expand Up @@ -2186,11 +2186,11 @@ function checkAssertPropertyInner(x, func, exists, equal, startsWith, endsWith)
});
x.assert(func('("a::after", {"a": 1}, all)'), {
'error': 'unknown identifier `all`. Available identifiers are: [`ALL`, `CONTAINS`, ' +
'`STARTS_WITH`, `ENDS_WITH`]',
'`STARTS_WITH`, `ENDS_WITH`, `NEAR`]',
});
x.assert(func('("a::after", {"a": 1}, ALLO)'), {
'error': 'unknown identifier `ALLO`. Available identifiers are: [`ALL`, `CONTAINS`, ' +
'`STARTS_WITH`, `ENDS_WITH`]',
'`STARTS_WITH`, `ENDS_WITH`, `NEAR`]',
});
x.assert(func('("a", {"b": "c", "b": "d"})'), {'error': 'property `b` is duplicated'});
x.assert(func('("a", {"b": []})'), {
Expand Down

0 comments on commit f09fda3

Please sign in to comment.