diff --git a/goml-script.md b/goml-script.md index 0e84ad693..04bc0ee4b 100644 --- a/goml-script.md +++ b/goml-script.md @@ -239,6 +239,7 @@ Here's the command list: * [`wait-for-position`](#wait-for-position) * [`wait-for-position-false`](#wait-for-position-false) * [`wait-for-property`](#wait-for-property) + * [`wait-for-property-false`](#wait-for-property-false) * [`wait-for-text`](#wait-for-text) * [`wait-for-size`](#wait-for-size) * [`wait-for-window-property`](#wait-for-window-property) @@ -2173,7 +2174,7 @@ wait-for-property: ("//*[@id='element']", {"scrollTop": 10, "name": "hello"}) wait-for-property: ("#element", {"key"."sub-key": "value"}) ``` -If you want to check that a property doesn't exist, you can use `null`: +If you want to wait for a property to be removed, you can use `null`: ``` // Checking that "property-name" doesn't exist. @@ -2200,6 +2201,55 @@ wait-for-property: ( ) ``` +If you want to wait for any of the properties to not be the provided ones, take a look at [`wait-for-property-false`](#wait-for-property-false). + +#### wait-for-property-false + +**wait-for-property-false** command waits for any of the given element(s) to not have the expected values for the given properties. It'll wait up to 30 seconds by default before failing (can be changed with the [`timeout`](#timeout) command). + +Examples: + +``` +wait-for-property-false: ("#element", {"scrollTop": 10}) +wait-for-property-false: ("#element", {"scrollTop": 10, "name": "hello"}) + +// Same with an XPath: +wait-for-property-false: ("//*[@id='element']", {"scrollTop": 10}) +wait-for-property-false: ("//*[@id='element']", {"scrollTop": 10, "name": "hello"}) + +// You can also use object-paths: +wait-for-property-false: ("#element", {"key"."sub-key": "value"}) +``` + +If you want to wait for a property to be created, you can use `null`: + +``` +// Checking that "property-name" doesn't exist. +wait-for-property-false: ("#id > .class", {"property-name": null}) +``` + +You can use more specific checks as well by using one of the following identifiers: "ALL", "CONTAINS", "ENDS_WITH", "STARTS_WITH" or "NEAR". + +``` +wait-for-property-false: ( + "#id", + {"className": "where", "title": "a title"}, + STARTS_WITH, +) +``` + +You can even combine the checks: + +``` +wait-for-property-false: ( + "#id", + {"className": "where", "title": "a title"}, + [STARTS_WITH, ENDS_WITH, ALL], +) +``` + +If you want to wait for all properties to have the expected values, take a look at [`wait-for-property`](#wait-for-property). + #### wait-for-size **wait-for-size** command wait for the given element(s) that either the "width" or the "height" (or both) have the expected value. Examples: diff --git a/src/commands.js b/src/commands.js index e20a6a1bc..30b9e3b8a 100644 --- a/src/commands.js +++ b/src/commands.js @@ -110,6 +110,7 @@ const ORDERS = { 'wait-for-position': commands.parseWaitForPosition, 'wait-for-position-false': commands.parseWaitForPositionFalse, 'wait-for-property': commands.parseWaitForProperty, + 'wait-for-property-false': commands.parseWaitForPropertyFalse, 'wait-for-size': commands.parseWaitForSize, 'wait-for-text': commands.parseWaitForText, 'wait-for-window-property': commands.parseWaitForWindowProperty, @@ -158,6 +159,7 @@ const FATAL_ERROR_COMMANDS = [ 'wait-for-count', 'wait-for-count-false', 'wait-for-property', + 'wait-for-property-false', 'wait-for-text', 'write', 'write-into', diff --git a/src/commands/all.js b/src/commands/all.js index 161776d08..30539711f 100644 --- a/src/commands/all.js +++ b/src/commands/all.js @@ -118,6 +118,7 @@ module.exports = { 'parseWaitForPosition': wait.parseWaitForPosition, 'parseWaitForPositionFalse': wait.parseWaitForPositionFalse, 'parseWaitForProperty': wait.parseWaitForProperty, + 'parseWaitForPropertyFalse': wait.parseWaitForPropertyFalse, 'parseWaitForSize': wait.parseWaitForSize, 'parseWaitForText': wait.parseWaitForText, 'parseWaitForWindowProperty': wait.parseWaitForWindowProperty, diff --git a/src/commands/wait.js b/src/commands/wait.js index 24b7213e7..8731a9f3b 100644 --- a/src/commands/wait.js +++ b/src/commands/wait.js @@ -788,6 +788,17 @@ ${indentString(incr, 1)} // // * ("selector", {"property name": "expected property value"}) function parseWaitForProperty(parser) { + return parseWaitForPropertyInner(parser, false); +} + +// Possible inputs: +// +// * ("selector", {"property name": "expected property value"}) +function parseWaitForPropertyFalse(parser) { + return parseWaitForPropertyInner(parser, true); +} + +function parseWaitForPropertyInner(parser, waitFalse) { const identifiers = ['ALL', 'CONTAINS', 'ENDS_WITH', 'NEAR', 'STARTS_WITH']; const ret = validator(parser, { kind: 'tuple', @@ -895,10 +906,17 @@ the check will be performed on the element itself`); warnings.push(`Special checks (${k.join(', ')}) will be ignored for \`null\``); } + let comp = '==='; + let errorMessage = '"The following properties still don\'t match: [" + props + "]"'; + if (waitFalse) { + comp = '!=='; + errorMessage = '"All properties still match"'; + } + const [init, looper] = waitForElement(selector, varName, {checkAll: enabledChecks.has('ALL')}); const incr = incrWait(`\ const props = nonMatchingProps.join(", "); -throw new Error("The following properties still don't match: [" + props + "]");`); +throw new Error(${errorMessage});`); const instructions = `\ async function checkPropForElem(elem) { @@ -940,7 +958,7 @@ ${init} while (true) { ${indentString(looper, 1)} ${indentString(checker, 1)} - if (nonMatchingProps.length === 0) { + if (nonMatchingProps.length ${comp} 0) { break; } ${indentString(incr, 1)} @@ -1283,6 +1301,7 @@ module.exports = { 'parseWaitForPosition': parseWaitForPosition, 'parseWaitForPositionFalse': parseWaitForPositionFalse, 'parseWaitForProperty': parseWaitForProperty, + 'parseWaitForPropertyFalse': parseWaitForPropertyFalse, 'parseWaitForText': parseWaitForText, 'parseWaitForWindowProperty': parseWaitForWindowProperty, 'parseWaitForWindowPropertyFalse': parseWaitForWindowPropertyFalse, diff --git a/tests/api-output/parseWaitForPropertyFalse/basic-1.toml b/tests/api-output/parseWaitForPropertyFalse/basic-1.toml new file mode 100644 index 000000000..594f38f80 --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/basic-1.toml @@ -0,0 +1,88 @@ +instructions = [ + """async function checkPropForElem(elem) { + return await elem.evaluate(e => { + function checkObjectPaths(object, path, callback, notFoundCallback) { + const found = []; + + for (const subPath of path) { + found.push(subPath); + if (object === undefined || object === null) { + notFoundCallback(found); + return; + } + object = object[subPath]; + } + callback(object); + } + + const nonMatchingProps = []; + const parseWaitForPropDict = []; + const nullProps = []; + for (const prop of nullProps) { + checkObjectPaths(e, prop, val => { + if (val !== undefined && val !== null) { + const p = prop.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Expected property `\" + p + \"` to not exist, found: `\" + val + \"`\"); + return; + } + }, _notFound => { + }); + } + for (const [parseWaitForPropKey, parseWaitForPropValue] of parseWaitForPropDict) { + checkObjectPaths(e, parseWaitForPropKey, val => { + if (val === undefined) { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + return; + } + if (val !== parseWaitForPropValue) { + nonMatchingProps.push(\"expected `\" + parseWaitForPropValue + \"` for property `\" + parseWaitForPropKey + \"`, found `\" + val + \"`\"); + } + }, _notFound => { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + }); + } + return nonMatchingProps; + }); +} + +const timeLimit = page.getDefaultTimeout(); +const timeAdd = 50; +let allTime = 0; +let parseWaitForProp = null; +while (true) { + while (true) { + parseWaitForProp = await page.$$(\"a\"); + if (parseWaitForProp.length !== 0) { + parseWaitForProp = parseWaitForProp[0]; + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + throw new Error(\"The CSS selector \\\"a\\\" was not found\"); + } + } + const nonMatchingProps = await checkPropForElem(parseWaitForProp); + if (nonMatchingProps.length !== 0) { + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + const props = nonMatchingProps.join(\", \"); + throw new Error(\"All properties still match\"); + } +}""", +] +wait = false +warnings = [ +] +checkResult = true diff --git a/tests/api-output/parseWaitForPropertyFalse/basic-2.toml b/tests/api-output/parseWaitForPropertyFalse/basic-2.toml new file mode 100644 index 000000000..91446ac0c --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/basic-2.toml @@ -0,0 +1,88 @@ +instructions = [ + """async function checkPropForElem(elem) { + return await elem.evaluate(e => { + function checkObjectPaths(object, path, callback, notFoundCallback) { + const found = []; + + for (const subPath of path) { + found.push(subPath); + if (object === undefined || object === null) { + notFoundCallback(found); + return; + } + object = object[subPath]; + } + callback(object); + } + + const nonMatchingProps = []; + const parseWaitForPropDict = [[[\"x\"],\"1\"]]; + const nullProps = []; + for (const prop of nullProps) { + checkObjectPaths(e, prop, val => { + if (val !== undefined && val !== null) { + const p = prop.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Expected property `\" + p + \"` to not exist, found: `\" + val + \"`\"); + return; + } + }, _notFound => { + }); + } + for (const [parseWaitForPropKey, parseWaitForPropValue] of parseWaitForPropDict) { + checkObjectPaths(e, parseWaitForPropKey, val => { + if (val === undefined) { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + return; + } + if (val !== parseWaitForPropValue) { + nonMatchingProps.push(\"expected `\" + parseWaitForPropValue + \"` for property `\" + parseWaitForPropKey + \"`, found `\" + val + \"`\"); + } + }, _notFound => { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + }); + } + return nonMatchingProps; + }); +} + +const timeLimit = page.getDefaultTimeout(); +const timeAdd = 50; +let allTime = 0; +let parseWaitForProp = null; +while (true) { + while (true) { + parseWaitForProp = await page.$$(\"a\"); + if (parseWaitForProp.length !== 0) { + parseWaitForProp = parseWaitForProp[0]; + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + throw new Error(\"The CSS selector \\\"a\\\" was not found\"); + } + } + const nonMatchingProps = await checkPropForElem(parseWaitForProp); + if (nonMatchingProps.length !== 0) { + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + const props = nonMatchingProps.join(\", \"); + throw new Error(\"All properties still match\"); + } +}""", +] +wait = false +warnings = [ +] +checkResult = true diff --git a/tests/api-output/parseWaitForPropertyFalse/basic-3.toml b/tests/api-output/parseWaitForPropertyFalse/basic-3.toml new file mode 100644 index 000000000..19411089f --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/basic-3.toml @@ -0,0 +1,88 @@ +instructions = [ + """async function checkPropForElem(elem) { + return await elem.evaluate(e => { + function checkObjectPaths(object, path, callback, notFoundCallback) { + const found = []; + + for (const subPath of path) { + found.push(subPath); + if (object === undefined || object === null) { + notFoundCallback(found); + return; + } + object = object[subPath]; + } + callback(object); + } + + const nonMatchingProps = []; + const parseWaitForPropDict = [[[\"x\"],\"1\"],[[\"y\"],\"2\"]]; + const nullProps = []; + for (const prop of nullProps) { + checkObjectPaths(e, prop, val => { + if (val !== undefined && val !== null) { + const p = prop.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Expected property `\" + p + \"` to not exist, found: `\" + val + \"`\"); + return; + } + }, _notFound => { + }); + } + for (const [parseWaitForPropKey, parseWaitForPropValue] of parseWaitForPropDict) { + checkObjectPaths(e, parseWaitForPropKey, val => { + if (val === undefined) { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + return; + } + if (val !== parseWaitForPropValue) { + nonMatchingProps.push(\"expected `\" + parseWaitForPropValue + \"` for property `\" + parseWaitForPropKey + \"`, found `\" + val + \"`\"); + } + }, _notFound => { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + }); + } + return nonMatchingProps; + }); +} + +const timeLimit = page.getDefaultTimeout(); +const timeAdd = 50; +let allTime = 0; +let parseWaitForProp = null; +while (true) { + while (true) { + parseWaitForProp = await page.$$(\"a\"); + if (parseWaitForProp.length !== 0) { + parseWaitForProp = parseWaitForProp[0]; + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + throw new Error(\"The CSS selector \\\"a\\\" was not found\"); + } + } + const nonMatchingProps = await checkPropForElem(parseWaitForProp); + if (nonMatchingProps.length !== 0) { + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + const props = nonMatchingProps.join(\", \"); + throw new Error(\"All properties still match\"); + } +}""", +] +wait = false +warnings = [ +] +checkResult = true diff --git a/tests/api-output/parseWaitForPropertyFalse/color-1.toml b/tests/api-output/parseWaitForPropertyFalse/color-1.toml new file mode 100644 index 000000000..1e58a8c62 --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/color-1.toml @@ -0,0 +1,88 @@ +instructions = [ + """async function checkPropForElem(elem) { + return await elem.evaluate(e => { + function checkObjectPaths(object, path, callback, notFoundCallback) { + const found = []; + + for (const subPath of path) { + found.push(subPath); + if (object === undefined || object === null) { + notFoundCallback(found); + return; + } + object = object[subPath]; + } + callback(object); + } + + const nonMatchingProps = []; + const parseWaitForPropDict = [[[\"color\"],\"blue\"]]; + const nullProps = []; + for (const prop of nullProps) { + checkObjectPaths(e, prop, val => { + if (val !== undefined && val !== null) { + const p = prop.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Expected property `\" + p + \"` to not exist, found: `\" + val + \"`\"); + return; + } + }, _notFound => { + }); + } + for (const [parseWaitForPropKey, parseWaitForPropValue] of parseWaitForPropDict) { + checkObjectPaths(e, parseWaitForPropKey, val => { + if (val === undefined) { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + return; + } + if (val !== parseWaitForPropValue) { + nonMatchingProps.push(\"expected `\" + parseWaitForPropValue + \"` for property `\" + parseWaitForPropKey + \"`, found `\" + val + \"`\"); + } + }, _notFound => { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + }); + } + return nonMatchingProps; + }); +} + +const timeLimit = page.getDefaultTimeout(); +const timeAdd = 50; +let allTime = 0; +let parseWaitForProp = null; +while (true) { + while (true) { + parseWaitForProp = await page.$$(\"a\"); + if (parseWaitForProp.length !== 0) { + parseWaitForProp = parseWaitForProp[0]; + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + throw new Error(\"The CSS selector \\\"a\\\" was not found\"); + } + } + const nonMatchingProps = await checkPropForElem(parseWaitForProp); + if (nonMatchingProps.length !== 0) { + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + const props = nonMatchingProps.join(\", \"); + throw new Error(\"All properties still match\"); + } +}""", +] +wait = false +warnings = [ +] +checkResult = true diff --git a/tests/api-output/parseWaitForPropertyFalse/err-1.toml b/tests/api-output/parseWaitForPropertyFalse/err-1.toml new file mode 100644 index 000000000..7ebf18c8f --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/err-1.toml @@ -0,0 +1 @@ +error = """expected a tuple, found nothing""" diff --git a/tests/api-output/parseWaitForPropertyFalse/err-2.toml b/tests/api-output/parseWaitForPropertyFalse/err-2.toml new file mode 100644 index 000000000..e5b8f7752 --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/err-2.toml @@ -0,0 +1 @@ +error = """expected a tuple, found `hello` (an ident)""" diff --git a/tests/api-output/parseWaitForPropertyFalse/err-3.toml b/tests/api-output/parseWaitForPropertyFalse/err-3.toml new file mode 100644 index 000000000..ee91ecfef --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/err-3.toml @@ -0,0 +1 @@ +error = """expected a selector, found `1` (a number) (first element of the tuple)""" diff --git a/tests/api-output/parseWaitForPropertyFalse/err-4.toml b/tests/api-output/parseWaitForPropertyFalse/err-4.toml new file mode 100644 index 000000000..ee91ecfef --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/err-4.toml @@ -0,0 +1 @@ +error = """expected a selector, found `1` (a number) (first element of the tuple)""" diff --git a/tests/api-output/parseWaitForPropertyFalse/err-5.toml b/tests/api-output/parseWaitForPropertyFalse/err-5.toml new file mode 100644 index 000000000..41922c8ad --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/err-5.toml @@ -0,0 +1 @@ +error = """expected a JSON dict, found `2` (a number) (second element of the tuple)""" diff --git a/tests/api-output/parseWaitForPropertyFalse/err-6.toml b/tests/api-output/parseWaitForPropertyFalse/err-6.toml new file mode 100644 index 000000000..417bfa3c0 --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/err-6.toml @@ -0,0 +1 @@ +error = """type \"json\" (`{\"a\": 2}`) is not allowed as value in this JSON dict, allowed types are: [`ident`, `number`, `string`] (second element of the tuple)""" diff --git a/tests/api-output/parseWaitForPropertyFalse/err-7.toml b/tests/api-output/parseWaitForPropertyFalse/err-7.toml new file mode 100644 index 000000000..ae42dac3e --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/err-7.toml @@ -0,0 +1 @@ +error = """unexpected ident `a` (third element of the tuple). Allowed idents are: [`ALL`, `CONTAINS`, `ENDS_WITH`, `NEAR`, `STARTS_WITH`]""" diff --git a/tests/api-output/parseWaitForPropertyFalse/extra-1.toml b/tests/api-output/parseWaitForPropertyFalse/extra-1.toml new file mode 100644 index 000000000..097f6de03 --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/extra-1.toml @@ -0,0 +1,94 @@ +instructions = [ + """async function checkPropForElem(elem) { + return await elem.evaluate(e => { + function checkObjectPaths(object, path, callback, notFoundCallback) { + const found = []; + + for (const subPath of path) { + found.push(subPath); + if (object === undefined || object === null) { + notFoundCallback(found); + return; + } + object = object[subPath]; + } + callback(object); + } + + const nonMatchingProps = []; + const parseWaitForPropDict = [[[\"x\"],\"1\"]]; + const nullProps = []; + for (const prop of nullProps) { + checkObjectPaths(e, prop, val => { + if (val !== undefined && val !== null) { + const p = prop.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Expected property `\" + p + \"` to not exist, found: `\" + val + \"`\"); + return; + } + }, _notFound => { + }); + } + for (const [parseWaitForPropKey, parseWaitForPropValue] of parseWaitForPropDict) { + checkObjectPaths(e, parseWaitForPropKey, val => { + if (val === undefined) { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + return; + } + if (val !== parseWaitForPropValue) { + nonMatchingProps.push(\"expected `\" + parseWaitForPropValue + \"` for property `\" + parseWaitForPropKey + \"`, found `\" + val + \"`\"); + } + }, _notFound => { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + }); + } + return nonMatchingProps; + }); +} + +const timeLimit = page.getDefaultTimeout(); +const timeAdd = 50; +let allTime = 0; +let parseWaitForProp = null; +while (true) { + while (true) { + parseWaitForProp = await page.$$(\"a\"); + if (parseWaitForProp.length !== 0) { + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + throw new Error(\"The CSS selector \\\"a\\\" was not found\"); + } + } + let nonMatchingProps = []; + for (const elem of parseWaitForProp) { + const ret = await checkPropForElem(elem); + if (ret.length !== 0) { + nonMatchingProps = ret; + break; + } + } + if (nonMatchingProps.length !== 0) { + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + const props = nonMatchingProps.join(\", \"); + throw new Error(\"All properties still match\"); + } +}""", +] +wait = false +warnings = [ +] +checkResult = true diff --git a/tests/api-output/parseWaitForPropertyFalse/extra-2.toml b/tests/api-output/parseWaitForPropertyFalse/extra-2.toml new file mode 100644 index 000000000..67c964756 --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/extra-2.toml @@ -0,0 +1,88 @@ +instructions = [ + """async function checkPropForElem(elem) { + return await elem.evaluate(e => { + function checkObjectPaths(object, path, callback, notFoundCallback) { + const found = []; + + for (const subPath of path) { + found.push(subPath); + if (object === undefined || object === null) { + notFoundCallback(found); + return; + } + object = object[subPath]; + } + callback(object); + } + + const nonMatchingProps = []; + const parseWaitForPropDict = [[[\"x\"],\"1\"]]; + const nullProps = []; + for (const prop of nullProps) { + checkObjectPaths(e, prop, val => { + if (val !== undefined && val !== null) { + const p = prop.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Expected property `\" + p + \"` to not exist, found: `\" + val + \"`\"); + return; + } + }, _notFound => { + }); + } + for (const [parseWaitForPropKey, parseWaitForPropValue] of parseWaitForPropDict) { + checkObjectPaths(e, parseWaitForPropKey, val => { + if (val === undefined) { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + return; + } + if (!val.includes(parseWaitForPropValue)) { + nonMatchingProps.push(\"property `\" + parseWaitForPropKey + \"` (`\" + val + \"`) doesn't contain `\" + parseWaitForPropValue + \"` (for CONTAINS check)\"); + } + }, _notFound => { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + }); + } + return nonMatchingProps; + }); +} + +const timeLimit = page.getDefaultTimeout(); +const timeAdd = 50; +let allTime = 0; +let parseWaitForProp = null; +while (true) { + while (true) { + parseWaitForProp = await page.$$(\"a\"); + if (parseWaitForProp.length !== 0) { + parseWaitForProp = parseWaitForProp[0]; + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + throw new Error(\"The CSS selector \\\"a\\\" was not found\"); + } + } + const nonMatchingProps = await checkPropForElem(parseWaitForProp); + if (nonMatchingProps.length !== 0) { + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + const props = nonMatchingProps.join(\", \"); + throw new Error(\"All properties still match\"); + } +}""", +] +wait = false +warnings = [ +] +checkResult = true diff --git a/tests/api-output/parseWaitForPropertyFalse/extra-3.toml b/tests/api-output/parseWaitForPropertyFalse/extra-3.toml new file mode 100644 index 000000000..bfcb081e4 --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/extra-3.toml @@ -0,0 +1,94 @@ +instructions = [ + """async function checkPropForElem(elem) { + return await elem.evaluate(e => { + function checkObjectPaths(object, path, callback, notFoundCallback) { + const found = []; + + for (const subPath of path) { + found.push(subPath); + if (object === undefined || object === null) { + notFoundCallback(found); + return; + } + object = object[subPath]; + } + callback(object); + } + + const nonMatchingProps = []; + const parseWaitForPropDict = [[[\"x\"],\"1\"]]; + const nullProps = []; + for (const prop of nullProps) { + checkObjectPaths(e, prop, val => { + if (val !== undefined && val !== null) { + const p = prop.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Expected property `\" + p + \"` to not exist, found: `\" + val + \"`\"); + return; + } + }, _notFound => { + }); + } + for (const [parseWaitForPropKey, parseWaitForPropValue] of parseWaitForPropDict) { + checkObjectPaths(e, parseWaitForPropKey, val => { + if (val === undefined) { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + return; + } + if (!val.includes(parseWaitForPropValue)) { + nonMatchingProps.push(\"property `\" + parseWaitForPropKey + \"` (`\" + val + \"`) doesn't contain `\" + parseWaitForPropValue + \"` (for CONTAINS check)\"); + } + }, _notFound => { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + }); + } + return nonMatchingProps; + }); +} + +const timeLimit = page.getDefaultTimeout(); +const timeAdd = 50; +let allTime = 0; +let parseWaitForProp = null; +while (true) { + while (true) { + parseWaitForProp = await page.$$(\"a\"); + if (parseWaitForProp.length !== 0) { + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + throw new Error(\"The CSS selector \\\"a\\\" was not found\"); + } + } + let nonMatchingProps = []; + for (const elem of parseWaitForProp) { + const ret = await checkPropForElem(elem); + if (ret.length !== 0) { + nonMatchingProps = ret; + break; + } + } + if (nonMatchingProps.length !== 0) { + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + const props = nonMatchingProps.join(\", \"); + throw new Error(\"All properties still match\"); + } +}""", +] +wait = false +warnings = [ +] +checkResult = true diff --git a/tests/api-output/parseWaitForPropertyFalse/object-path-1.toml b/tests/api-output/parseWaitForPropertyFalse/object-path-1.toml new file mode 100644 index 000000000..706ff08d7 --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/object-path-1.toml @@ -0,0 +1,88 @@ +instructions = [ + """async function checkPropForElem(elem) { + return await elem.evaluate(e => { + function checkObjectPaths(object, path, callback, notFoundCallback) { + const found = []; + + for (const subPath of path) { + found.push(subPath); + if (object === undefined || object === null) { + notFoundCallback(found); + return; + } + object = object[subPath]; + } + callback(object); + } + + const nonMatchingProps = []; + const parseWaitForPropDict = [[[\"x\",\"y\"],\"1\"]]; + const nullProps = []; + for (const prop of nullProps) { + checkObjectPaths(e, prop, val => { + if (val !== undefined && val !== null) { + const p = prop.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Expected property `\" + p + \"` to not exist, found: `\" + val + \"`\"); + return; + } + }, _notFound => { + }); + } + for (const [parseWaitForPropKey, parseWaitForPropValue] of parseWaitForPropDict) { + checkObjectPaths(e, parseWaitForPropKey, val => { + if (val === undefined) { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + return; + } + if (val !== parseWaitForPropValue) { + nonMatchingProps.push(\"expected `\" + parseWaitForPropValue + \"` for property `\" + parseWaitForPropKey + \"`, found `\" + val + \"`\"); + } + }, _notFound => { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + }); + } + return nonMatchingProps; + }); +} + +const timeLimit = page.getDefaultTimeout(); +const timeAdd = 50; +let allTime = 0; +let parseWaitForProp = null; +while (true) { + while (true) { + parseWaitForProp = await page.$$(\"a\"); + if (parseWaitForProp.length !== 0) { + parseWaitForProp = parseWaitForProp[0]; + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + throw new Error(\"The CSS selector \\\"a\\\" was not found\"); + } + } + const nonMatchingProps = await checkPropForElem(parseWaitForProp); + if (nonMatchingProps.length !== 0) { + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + const props = nonMatchingProps.join(\", \"); + throw new Error(\"All properties still match\"); + } +}""", +] +wait = false +warnings = [ +] +checkResult = true diff --git a/tests/api-output/parseWaitForPropertyFalse/object-path-2.toml b/tests/api-output/parseWaitForPropertyFalse/object-path-2.toml new file mode 100644 index 000000000..95e6a466f --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/object-path-2.toml @@ -0,0 +1,88 @@ +instructions = [ + """async function checkPropForElem(elem) { + return await elem.evaluate(e => { + function checkObjectPaths(object, path, callback, notFoundCallback) { + const found = []; + + for (const subPath of path) { + found.push(subPath); + if (object === undefined || object === null) { + notFoundCallback(found); + return; + } + object = object[subPath]; + } + callback(object); + } + + const nonMatchingProps = []; + const parseWaitForPropDict = [[[\"x\",\"y\"],\"1\"],[[\"z\"],\"3\"]]; + const nullProps = []; + for (const prop of nullProps) { + checkObjectPaths(e, prop, val => { + if (val !== undefined && val !== null) { + const p = prop.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Expected property `\" + p + \"` to not exist, found: `\" + val + \"`\"); + return; + } + }, _notFound => { + }); + } + for (const [parseWaitForPropKey, parseWaitForPropValue] of parseWaitForPropDict) { + checkObjectPaths(e, parseWaitForPropKey, val => { + if (val === undefined) { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + return; + } + if (val !== parseWaitForPropValue) { + nonMatchingProps.push(\"expected `\" + parseWaitForPropValue + \"` for property `\" + parseWaitForPropKey + \"`, found `\" + val + \"`\"); + } + }, _notFound => { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + }); + } + return nonMatchingProps; + }); +} + +const timeLimit = page.getDefaultTimeout(); +const timeAdd = 50; +let allTime = 0; +let parseWaitForProp = null; +while (true) { + while (true) { + parseWaitForProp = await page.$$(\"a\"); + if (parseWaitForProp.length !== 0) { + parseWaitForProp = parseWaitForProp[0]; + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + throw new Error(\"The CSS selector \\\"a\\\" was not found\"); + } + } + const nonMatchingProps = await checkPropForElem(parseWaitForProp); + if (nonMatchingProps.length !== 0) { + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + const props = nonMatchingProps.join(\", \"); + throw new Error(\"All properties still match\"); + } +}""", +] +wait = false +warnings = [ +] +checkResult = true diff --git a/tests/api-output/parseWaitForPropertyFalse/pseudo-1.toml b/tests/api-output/parseWaitForPropertyFalse/pseudo-1.toml new file mode 100644 index 000000000..63ad597b2 --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/pseudo-1.toml @@ -0,0 +1,89 @@ +instructions = [ + """async function checkPropForElem(elem) { + return await elem.evaluate(e => { + function checkObjectPaths(object, path, callback, notFoundCallback) { + const found = []; + + for (const subPath of path) { + found.push(subPath); + if (object === undefined || object === null) { + notFoundCallback(found); + return; + } + object = object[subPath]; + } + callback(object); + } + + const nonMatchingProps = []; + const parseWaitForPropDict = [[[\"x\"],\"1\"],[[\"y\"],\"2\"]]; + const nullProps = []; + for (const prop of nullProps) { + checkObjectPaths(e, prop, val => { + if (val !== undefined && val !== null) { + const p = prop.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Expected property `\" + p + \"` to not exist, found: `\" + val + \"`\"); + return; + } + }, _notFound => { + }); + } + for (const [parseWaitForPropKey, parseWaitForPropValue] of parseWaitForPropDict) { + checkObjectPaths(e, parseWaitForPropKey, val => { + if (val === undefined) { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + return; + } + if (val !== parseWaitForPropValue) { + nonMatchingProps.push(\"expected `\" + parseWaitForPropValue + \"` for property `\" + parseWaitForPropKey + \"`, found `\" + val + \"`\"); + } + }, _notFound => { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + }); + } + return nonMatchingProps; + }); +} + +const timeLimit = page.getDefaultTimeout(); +const timeAdd = 50; +let allTime = 0; +let parseWaitForProp = null; +while (true) { + while (true) { + parseWaitForProp = await page.$$(\"a\"); + if (parseWaitForProp.length !== 0) { + parseWaitForProp = parseWaitForProp[0]; + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + throw new Error(\"The CSS selector \\\"a\\\" was not found\"); + } + } + const nonMatchingProps = await checkPropForElem(parseWaitForProp); + if (nonMatchingProps.length !== 0) { + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + const props = nonMatchingProps.join(\", \"); + throw new Error(\"All properties still match\"); + } +}""", +] +wait = false +warnings = [ + """Pseudo-elements (`::after`) don't have properties so the check will be performed on the element itself""", +] +checkResult = true diff --git a/tests/api-output/parseWaitForPropertyFalse/xpath-1.toml b/tests/api-output/parseWaitForPropertyFalse/xpath-1.toml new file mode 100644 index 000000000..4c2caf665 --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/xpath-1.toml @@ -0,0 +1 @@ +error = """XPath must start with `//` (first element of the tuple)""" diff --git a/tests/api-output/parseWaitForPropertyFalse/xpath-2.toml b/tests/api-output/parseWaitForPropertyFalse/xpath-2.toml new file mode 100644 index 000000000..80a1855bc --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/xpath-2.toml @@ -0,0 +1,88 @@ +instructions = [ + """async function checkPropForElem(elem) { + return await elem.evaluate(e => { + function checkObjectPaths(object, path, callback, notFoundCallback) { + const found = []; + + for (const subPath of path) { + found.push(subPath); + if (object === undefined || object === null) { + notFoundCallback(found); + return; + } + object = object[subPath]; + } + callback(object); + } + + const nonMatchingProps = []; + const parseWaitForPropDict = []; + const nullProps = []; + for (const prop of nullProps) { + checkObjectPaths(e, prop, val => { + if (val !== undefined && val !== null) { + const p = prop.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Expected property `\" + p + \"` to not exist, found: `\" + val + \"`\"); + return; + } + }, _notFound => { + }); + } + for (const [parseWaitForPropKey, parseWaitForPropValue] of parseWaitForPropDict) { + checkObjectPaths(e, parseWaitForPropKey, val => { + if (val === undefined) { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + return; + } + if (val !== parseWaitForPropValue) { + nonMatchingProps.push(\"expected `\" + parseWaitForPropValue + \"` for property `\" + parseWaitForPropKey + \"`, found `\" + val + \"`\"); + } + }, _notFound => { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + }); + } + return nonMatchingProps; + }); +} + +const timeLimit = page.getDefaultTimeout(); +const timeAdd = 50; +let allTime = 0; +let parseWaitForProp = null; +while (true) { + while (true) { + parseWaitForProp = await page.$$(\"::-p-xpath(//a)\"); + if (parseWaitForProp.length !== 0) { + parseWaitForProp = parseWaitForProp[0]; + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + throw new Error(\"The XPath \\\"//a\\\" was not found\"); + } + } + const nonMatchingProps = await checkPropForElem(parseWaitForProp); + if (nonMatchingProps.length !== 0) { + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + const props = nonMatchingProps.join(\", \"); + throw new Error(\"All properties still match\"); + } +}""", +] +wait = false +warnings = [ +] +checkResult = true diff --git a/tests/api-output/parseWaitForPropertyFalse/xpath-3.toml b/tests/api-output/parseWaitForPropertyFalse/xpath-3.toml new file mode 100644 index 000000000..a16e835e1 --- /dev/null +++ b/tests/api-output/parseWaitForPropertyFalse/xpath-3.toml @@ -0,0 +1,88 @@ +instructions = [ + """async function checkPropForElem(elem) { + return await elem.evaluate(e => { + function checkObjectPaths(object, path, callback, notFoundCallback) { + const found = []; + + for (const subPath of path) { + found.push(subPath); + if (object === undefined || object === null) { + notFoundCallback(found); + return; + } + object = object[subPath]; + } + callback(object); + } + + const nonMatchingProps = []; + const parseWaitForPropDict = [[[\"x\"],\"1\"]]; + const nullProps = []; + for (const prop of nullProps) { + checkObjectPaths(e, prop, val => { + if (val !== undefined && val !== null) { + const p = prop.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Expected property `\" + p + \"` to not exist, found: `\" + val + \"`\"); + return; + } + }, _notFound => { + }); + } + for (const [parseWaitForPropKey, parseWaitForPropValue] of parseWaitForPropDict) { + checkObjectPaths(e, parseWaitForPropKey, val => { + if (val === undefined) { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + return; + } + if (val !== parseWaitForPropValue) { + nonMatchingProps.push(\"expected `\" + parseWaitForPropValue + \"` for property `\" + parseWaitForPropKey + \"`, found `\" + val + \"`\"); + } + }, _notFound => { + const p = parseWaitForPropKey.map(p => `\"${p}\"`).join('.'); + nonMatchingProps.push(\"Property `\" + p + \"` doesn't exist\"); + }); + } + return nonMatchingProps; + }); +} + +const timeLimit = page.getDefaultTimeout(); +const timeAdd = 50; +let allTime = 0; +let parseWaitForProp = null; +while (true) { + while (true) { + parseWaitForProp = await page.$$(\"::-p-xpath(//a)\"); + if (parseWaitForProp.length !== 0) { + parseWaitForProp = parseWaitForProp[0]; + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + throw new Error(\"The XPath \\\"//a\\\" was not found\"); + } + } + const nonMatchingProps = await checkPropForElem(parseWaitForProp); + if (nonMatchingProps.length !== 0) { + break; + } + await new Promise(r => setTimeout(r, timeAdd)); + if (timeLimit === 0) { + continue; + } + allTime += timeAdd; + if (allTime >= timeLimit) { + const props = nonMatchingProps.join(\", \"); + throw new Error(\"All properties still match\"); + } +}""", +] +wait = false +warnings = [ +] +checkResult = true diff --git a/tests/ui/wait-for-property-false.goml b/tests/ui/wait-for-property-false.goml new file mode 100644 index 000000000..12b9389c3 --- /dev/null +++ b/tests/ui/wait-for-property-false.goml @@ -0,0 +1,23 @@ +// This test ensures that the `wait-for-property-false` command is behaving like expected. +screenshot-comparison: false +go-to: "file://" + |CURRENT_DIR| + "/" + |DOC_PATH| + "/elements.html" +set-timeout: 400 +// Shouldn't wait here since it's already the case. +wait-for-property-false: ("#js-wait-prop", {"hehe": "haha"}) +click: "#js-wait-prop" +// Should wait for 250ms here. +wait-for-property-false: ("#js-wait-prop", {"someProp": null}) +click: "#js-create-elem" +// Should wait for 100ms here (the element is created first). +wait-for-property-false: ("#created-one", {"hehe": null}) + +// object-path +assert-property: ("#js-wait-prop2", {"toto"."z": null}) +click: "#js-wait-prop2" +// Should wait for 100ms here. +wait-for-property-false: ("#js-wait-prop2", {"toto"."z": null}) + +// This next one should fail. +wait-for-property-false: ("#js-wait-prop", {"hehe": "hoho"}) +// Check that the script won't run anything after the previous command failed. +assert-property: ("#js-wait-prop", {"data-a": "c"}) diff --git a/tests/ui/wait-for-property-false.output b/tests/ui/wait-for-property-false.output new file mode 100644 index 000000000..9b42c8a8c --- /dev/null +++ b/tests/ui/wait-for-property-false.output @@ -0,0 +1,7 @@ +=> Starting doc-ui tests... + +wait-for-property-false... FAILED +[ERROR] `tests/ui/wait-for-property-false.goml` line 21: Error: All properties still match: for command `wait-for-property-false: ("#js-wait-prop", {"hehe": "hoho"})` + + +<= doc-ui tests done: 0 succeeded, 1 failed \ No newline at end of file diff --git a/tests/ui/wait-for-property.goml b/tests/ui/wait-for-property.goml index fd766663b..c187117fa 100644 --- a/tests/ui/wait-for-property.goml +++ b/tests/ui/wait-for-property.goml @@ -10,6 +10,13 @@ wait-for-property: ("#js-wait-prop", {"someProp": "hello"}) click: "#js-create-elem" // Should wait for 100ms here (the element is created first). wait-for-property: ("#created-one", {"hehe": "hoho"}) + +// object-path +assert-property: ("#js-wait-prop2", {"toto"."z": null}) +click: "#js-wait-prop2" +// Should wait for 100ms here. +wait-for-property: ("#js-wait-prop2", {"toto"."z": 78}) + // This next one should fail. wait-for-property: ("#js-wait-prop", {"data-a": "c"}) // Check that the script won't run anything after the previous command failed. diff --git a/tests/ui/wait-for-property.output b/tests/ui/wait-for-property.output index 82423ee57..18fc28809 100644 --- a/tests/ui/wait-for-property.output +++ b/tests/ui/wait-for-property.output @@ -1,7 +1,7 @@ => Starting doc-ui tests... wait-for-property... FAILED -[ERROR] `tests/ui/wait-for-property.goml` line 14: Error: The following properties still don't match: [Property `"data-a"` doesn't exist]: for command `wait-for-property: ("#js-wait-prop", {"data-a": "c"})` +[ERROR] `tests/ui/wait-for-property.goml` line 18: Error: The following properties still don't match: [expected `78` for property `toto,z`, found `78`]: for command `wait-for-property: ("#js-wait-prop2", {"toto"."z": 78})` <= doc-ui tests done: 0 succeeded, 1 failed \ No newline at end of file diff --git a/tools/api.js b/tools/api.js index dbb86a238..108b37e73 100644 --- a/tools/api.js +++ b/tools/api.js @@ -2913,6 +2913,11 @@ const TO_CHECK = [ 'func': checkWaitForProperty, 'toCall': (x, e, name, o) => wrapper(parserFuncs.parseWaitForProperty, x, e, name, o), }, + { + 'name': 'wait-for-property-false', + 'func': checkWaitForProperty, + 'toCall': (x, e, name, o) => wrapper(parserFuncs.parseWaitForPropertyFalse, x, e, name, o), + }, { 'name': 'wait-for-size', 'func': checkAssertSize,