diff --git a/goml-script.md b/goml-script.md index 62d5efb8..fcb42355 100644 --- a/goml-script.md +++ b/goml-script.md @@ -66,11 +66,16 @@ store-value: (effect, ":hover") set-text: ("element" + |variable|, "something " + 2 + " something else") ``` -Rules of concatenation are simple: if any of the element is a string, then it'll concatenate as a string. Examples: +Operations are handled from the left to the right. Operations between parens are performed first: ```ignore -1 + 2 + "a" // gives string "12a" -1 + 2 // gives number 3 +1 + 2 + "a" + (4 * 3) +// first the parens +1 + 2 + "a" + 12 +// then from left to right +3 + "a" + 12 +"3a" + 12 +"3a12" ``` This is just a sub-part of expressions which allow more things. diff --git a/src/ast.js b/src/ast.js index e43ea8a2..b4801d52 100644 --- a/src/ast.js +++ b/src/ast.js @@ -35,15 +35,14 @@ function replaceVariable(elem, variables, functionArgs, forceVariableAsString, e if (associatedValue instanceof Element) { // Nothing to be done in here. return associatedValue; - } else if (['number', 'string', 'boolean'].includes(typeof associatedValue)) { - if (typeof associatedValue === 'boolean') { - return new IdentElement( - associatedValue.toString(), startPos, endPos, lineNumber); - } else if (typeof associatedValue === 'number' || - // eslint-disable-next-line no-extra-parens - (!forceVariableAsString && matchInteger(associatedValue) === true)) { - return new NumberElement(associatedValue, startPos, endPos, lineNumber); - } + } else if (typeof associatedValue === 'boolean') { + return new IdentElement( + associatedValue.toString(), startPos, endPos, lineNumber); + } else if (typeof associatedValue === 'number' || + // eslint-disable-next-line no-extra-parens + (!forceVariableAsString && matchInteger(associatedValue) === true)) { + return new NumberElement(associatedValue, startPos, endPos, lineNumber); + } else if (typeof associatedValue === 'string') { return new StringElement( associatedValue, startPos, diff --git a/src/commands/navigation.js b/src/commands/navigation.js index 310db71e..d3ca5434 100644 --- a/src/commands/navigation.js +++ b/src/commands/navigation.js @@ -1,6 +1,5 @@ // Commands changing the current location or reloading the page. -const { cleanString } = require('../parser.js'); const { hasError } = require('../utils.js'); const { validator } = require('../validator.js'); @@ -22,7 +21,8 @@ function parseGoTo(parser) { return ret; } - const path = ret.value.value.trim(); + const path = ret.value.getStringValue(); + const code = ret.value.displayInCode(); let goto_arg; const permissions = 'await arg.browser.overridePermissions(page.url(), arg.permissions);'; @@ -32,11 +32,11 @@ function parseGoTo(parser) { || path.startsWith('www.') === true || path.startsWith('file://') === true ) { - goto_arg = `"${cleanString(path)}"`; + goto_arg = code; } else if (path.startsWith('.')) { - goto_arg = `page.url().split("/").slice(0, -1).join("/") + "/${cleanString(path)}"`; + goto_arg = `page.url().split("/").slice(0, -1).join("/") + "/" + ${code}`; } else if (path.startsWith('/')) { - goto_arg = `page.url().split("/").slice(0, -1).join("/") + "${cleanString(path)}"`; + goto_arg = `page.url().split("/").slice(0, -1).join("/") + ${code}`; } else { return {'error': `a relative path or a full URL was expected, found \`${path}\``}; } diff --git a/src/parser.js b/src/parser.js index 03509b6b..3e79714d 100644 --- a/src/parser.js +++ b/src/parser.js @@ -21,7 +21,7 @@ function isLetter(c) { function matchInteger(s) { if (typeof s === 'number' || s instanceof Number) { return true; - } else if (typeof s === 'string' || s instanceof String) { + } else if ((typeof s === 'string' || s instanceof String) && s.length !== 0) { for (let i = s.length - 1; i >= 0; --i) { if (!isNumber(s.charAt(i))) { return false; @@ -158,39 +158,6 @@ function isArrayElementCompatible(expected, elem) { return expected.kind === elem.kind; } -// Used to concatenate all elements into a string, like `1 + "a" + 12` -> "1a12". -function concatExprAsString(elems) { - let out = ''; - for (const elem of elems) { - if (elem.kind === 'operator') { - continue; - } else if (['number', 'string', 'boolean'].includes(elem.kind)) { - out += elem.value; - } else { - out += concatExprAsString(elem.value); - } - } - return out; -} - -function concatExprAsObjectPath(elems) { - let s = ''; - const parts = []; - - for (const elem of elems) { - if (elem.kind === 'operator') { - continue; - } else if (elem.kind !== 'object-path') { - s += concatExprAsString([elem]); - } else { - elem.value[0].value = s + elem.value[0].value; - parts.push(...elem.value); - s = ''; - } - } - return parts; -} - // This function is used when generating an expression interpreted as a boolean. function concatExprAsExpr(elems) { const out = []; @@ -261,24 +228,19 @@ function canBeCompared(kind1, kind2) { } function convertAsString(elem) { - if (elem.value.some(v => v.kind === 'object-path')) { - return new ObjectPathElement( - concatExprAsObjectPath(elem.value), - elem.startPos, - elem.endPos, - elem.fullText, - elem.line, - elem.error, - ); - } - return new StringElement( - concatExprAsString(elem.value), - elem.startPos, - elem.endPos, - elem.fullText, - elem.line, - elem.error, - ); + const pos = elem.value.findIndex(v => v.kind === 'object-path'); + elem.kind = 'string'; + if (pos !== -1) { + // We remove the object-path from the expression. + const objPath = elem.value.pop(); + // We remove the first item of the object path and push it at the end of the expression. + elem.value.push(...objPath.value.splice(0, 1)); + // We put the expression as the first element of the object path. + objPath.value.splice(0, 0, elem); + // All done! + return objPath; + } + return elem; } function convertExprAs(elem, convertAs) { @@ -363,7 +325,8 @@ class Element { } isRecursive() { - // Only Tuple and JSON elements are "recursive" (meaning they can contain sub-levels). + // Expression, Array, Tuple and JSON elements are "recursive" (meaning they can contain + // sub-levels). return false; } @@ -433,6 +396,18 @@ class ExpressionElement extends Element { super('expression', value, startPos, endPos, fullText, line, error); } + isRecursive() { + return true; + } + + displayInCode() { + return this.value.map(v => v.displayInCode()).join(''); + } + + getStringValue() { + return this.value.map(v => v.getStringValue()).join(''); + } + clone() { const elems = this.value.map(elem => elem.clone()); return new this.constructor( @@ -537,8 +512,8 @@ class ObjectPathElement extends Element { super('object-path', value, startPos, endPos, fullText, line, error); } - getStringValue(trim, clean = true) { - const content = this.value.map(v => `"${v.getStringValue(clean)}"`).join(','); + getStringValue() { + const content = this.value.map(v => `${v.displayInCode()}`).join(','); return `[${content}]`; } diff --git a/tests/api-output/parseGoTo/basic-4.toml b/tests/api-output/parseGoTo/basic-4.toml index 67182263..86db6a1a 100644 --- a/tests/api-output/parseGoTo/basic-4.toml +++ b/tests/api-output/parseGoTo/basic-4.toml @@ -1,5 +1,5 @@ instructions = [ - """const url = page.url().split(\"/\").slice(0, -1).join(\"/\") + \"/./a\"; + """const url = page.url().split(\"/\").slice(0, -1).join(\"/\") + \"/\" + \"./a\"; try { await page.goto(url); } catch(exc) { diff --git a/tests/api-output/parseGoTo/var-1.toml b/tests/api-output/parseGoTo/var-1.toml index 0ccc3787..644ccc8c 100644 --- a/tests/api-output/parseGoTo/var-1.toml +++ b/tests/api-output/parseGoTo/var-1.toml @@ -1,5 +1,5 @@ instructions = [ - """const url = \"file://foo/a\"; + """const url = \"file://\"+\"foo\"+\"/a\"; try { await page.goto(url); } catch(exc) { diff --git a/tests/api-output/parseGoTo/var-3.toml b/tests/api-output/parseGoTo/var-3.toml index 0f49154f..812108ea 100644 --- a/tests/api-output/parseGoTo/var-3.toml +++ b/tests/api-output/parseGoTo/var-3.toml @@ -1,5 +1,5 @@ instructions = [ - """const url = \"http://foo/tadam/fa\"; + """const url = \"http://foo/\"+\"tadam/\"+\"fa\"; try { await page.goto(url); } catch(exc) { diff --git a/tests/api-output/parseGoTo/var-4.toml b/tests/api-output/parseGoTo/var-4.toml index 0f49154f..52f4ea03 100644 --- a/tests/api-output/parseGoTo/var-4.toml +++ b/tests/api-output/parseGoTo/var-4.toml @@ -1,5 +1,5 @@ instructions = [ - """const url = \"http://foo/tadam/fa\"; + """const url = \"http://foo/\"+\"tadam\"+\"/fa\"; try { await page.goto(url); } catch(exc) { diff --git a/tests/ui/assert-expr.goml b/tests/ui/assert-expr.goml index f1217c5f..0ad16e69 100644 --- a/tests/ui/assert-expr.goml +++ b/tests/ui/assert-expr.goml @@ -18,6 +18,8 @@ assert: ["1", "2"] != ["1", "2"] store-value: (var, (1 + 2) * 4 + 1) assert: |var| == 13 assert: |var| != 12 && 1 < 2 +assert: 1 + 2 + "a" == "3a" +assert: 1 + 2 + "a" + (4 * 3) == "3a12" // Should fail. assert: |var| != 13 diff --git a/tests/ui/assert-expr.output b/tests/ui/assert-expr.output index 2aef8a03..0cb79f94 100644 --- a/tests/ui/assert-expr.output +++ b/tests/ui/assert-expr.output @@ -2,12 +2,12 @@ assert-expr... FAILED [ERROR] `tests/ui/assert-expr.goml` line 15: Condition `!compareArrayLike(["1", "2"], ["1", "2"])` was evaluated as false: for command `assert: ["1", "2"] != ["1", "2"]` -[ERROR] `tests/ui/assert-expr.goml` line 23: Condition `13 != 13` was evaluated as false: for command `assert: |var| != 13` -[ERROR] `tests/ui/assert-expr.goml` line 24: assert didn't fail: for command `assert-false: |var| == 13` -[ERROR] `tests/ui/assert-expr.goml` line 25: Condition `"a" == 13` was evaluated as false: for command `assert: |var2| == |var|` -[ERROR] `tests/ui/assert-expr.goml` line 26: Condition `compareJson({"b": 3}, {"a": 2})` was evaluated as false: for command `assert: {"b": 3} == |var3|` -[ERROR] `tests/ui/assert-expr.goml` line 27: Condition `compareArrayLike([1, "a"], [2, 3])` was evaluated as false: for command `assert: (1, "a") == (2, 3)` -[ERROR] `tests/ui/assert-expr.goml` line 28: Condition `compareArrayLike([1, 2], ["a", "b"])` was evaluated as false: for command `assert: [1, 2] == ["a", "b"]` +[ERROR] `tests/ui/assert-expr.goml` line 25: Condition `13 != 13` was evaluated as false: for command `assert: |var| != 13` +[ERROR] `tests/ui/assert-expr.goml` line 26: assert didn't fail: for command `assert-false: |var| == 13` +[ERROR] `tests/ui/assert-expr.goml` line 27: Condition `"a" == 13` was evaluated as false: for command `assert: |var2| == |var|` +[ERROR] `tests/ui/assert-expr.goml` line 28: Condition `compareJson({"b": 3}, {"a": 2})` was evaluated as false: for command `assert: {"b": 3} == |var3|` +[ERROR] `tests/ui/assert-expr.goml` line 29: Condition `compareArrayLike([1, "a"], [2, 3])` was evaluated as false: for command `assert: (1, "a") == (2, 3)` +[ERROR] `tests/ui/assert-expr.goml` line 30: Condition `compareArrayLike([1, 2], ["a", "b"])` was evaluated as false: for command `assert: [1, 2] == ["a", "b"]` <= doc-ui tests done: 0 succeeded, 1 failed \ No newline at end of file diff --git a/tests/ui/debug.output b/tests/ui/debug.output index 031da51d..ba6ac900 100644 --- a/tests/ui/debug.output +++ b/tests/ui/debug.output @@ -4,7 +4,7 @@ debug... [DEBUG] Done! [DEBUG] EXECUTING (line 2) "arg.screenshotComparison = false;" [DEBUG] Done! -[DEBUG] EXECUTING (line 3) "const url = "file://$CURRENT_DIR/tests/html_files/elements.html"; +[DEBUG] EXECUTING (line 3) "const url = "file://"+"$CURRENT_DIR"+"/"+"tests/html_files"+"/elements.html"; try { await page.goto(url); } catch(exc) { diff --git a/tests/ui/debug2.output b/tests/ui/debug2.output index ccc13ca9..20346955 100644 --- a/tests/ui/debug2.output +++ b/tests/ui/debug2.output @@ -4,7 +4,7 @@ debug2... [DEBUG] Done! [DEBUG] EXECUTING (line 2) "arg.screenshotComparison = false;" [DEBUG] Done! -[DEBUG] EXECUTING (line 3) "const url = "file://$CURRENT_DIR/tests/html_files/elements.html"; +[DEBUG] EXECUTING (line 3) "const url = "file://"+"$CURRENT_DIR"+"/"+"tests/html_files"+"/elements.html"; try { await page.goto(url); } catch(exc) { diff --git a/tools/doc.js b/tools/doc.js index c88f9394..78f06173 100644 --- a/tools/doc.js +++ b/tools/doc.js @@ -3,7 +3,7 @@ const path = require('path'); const { ORDERS } = require('../src/commands.js'); const docFile = path.join(__dirname, '../goml-script.md'); -const {Assert, print} = require('./utils.js'); +const {Assert, plural, print} = require('./utils.js'); function compareCommands(x, commands) { print(`Checking ${commands.length} commands from documentation (\ @@ -80,7 +80,11 @@ function checkDoc(x = new Assert()) { if (x.getTotalRanTests() === 0) { x.addError('No commands found in doc...'); } + const errors = x.getTotalErrors(); + print(''); + print(`<= Ending ${x.getTotalRanTests()} ${plural('test', x.getTotalRanTests())} with ` + + `${x.getTotalErrors()} ${plural('error', errors)}`); x.endTestSuite(false); return errors; } diff --git a/tools/parser.js b/tools/parser.js index 6075f0a8..56347021 100644 --- a/tools/parser.js +++ b/tools/parser.js @@ -477,7 +477,7 @@ function checkTuple(x) { x.assert(p.elems[0].getRaw().length, 3); x.assert(p.elems[0].getRaw()[0].error, null); x.assert(p.elems[0].getRaw()[0].kind, 'string'); - x.assert(p.elems[0].getRaw()[0].value, '.result-a .a'); + x.assert(p.elems[0].getRaw()[0].displayInCode(), '".result-"+"a"+" ."+"a"'); x.assert(p.elems[0].getRaw()[1].error, null); x.assert(p.elems[0].getRaw()[1].kind, 'json'); x.assert(p.elems[0].getRaw()[1].getRaw().length, 1); @@ -507,7 +507,7 @@ function checkTuple(x) { x.assert(p.elems[0].getRaw()[0].value, '1'); x.assert(p.elems[0].getRaw()[1].error, null); x.assert(p.elems[0].getRaw()[1].kind, 'string'); - x.assert(p.elems[0].getRaw()[1].value, '.result-a'); + x.assert(p.elems[0].getRaw()[1].displayInCode(), '".result-"+"a"'); x.assert(p.elems[0].getRaw()[2].error, null); x.assert(p.elems[0].getRaw()[2].kind, 'json'); x.assert(p.elems[0].getRaw()[2].getRaw().length, 1); @@ -1579,7 +1579,8 @@ assert-css: (".item-left sup", {"color": |color|})`); x.assert(p.elems[0].getRaw()[0].key.getErrorText(), '"x"'); x.assert(p.elems[0].getRaw()[0].value.kind, 'string'); x.assert(p.elems[0].getRaw()[0].value.getErrorText(), '2 + |y|'); - x.assert(p.elems[0].getRaw()[0].value.getRaw(), '2a'); + x.assert(p.elems[0].getRaw()[0].value.getRaw().length, 3); + x.assert(p.elems[0].getRaw()[0].value.displayInCode(), '2+"a"'); p = new Parser('{"x" {"y": 1}}'); @@ -1936,7 +1937,7 @@ function checkExpr(x) { x.assert(p.elems.length, 1); x.assert(p.elems[0].kind, 'string'); x.assert(p.elems[0].error, null); - x.assert(p.elems[0].getRaw(), 'ab'); + x.assert(p.elems[0].displayInCode(), '"a"+"b"'); x.assert(p.elems[0].getErrorText(), '"a" + "b" '); p = inferredValues('"a" + "b"'); @@ -1944,7 +1945,7 @@ function checkExpr(x) { x.assert(p.elems.length, 1); x.assert(p.elems[0].kind, 'string'); x.assert(p.elems[0].error, null); - x.assert(p.elems[0].getRaw(), 'ab'); + x.assert(p.elems[0].displayInCode(), '"a"+"b"'); x.assert(p.elems[0].getErrorText(), '"a" + "b"'); p = inferredValues('"a" + 1 '); @@ -1952,7 +1953,7 @@ function checkExpr(x) { x.assert(p.elems.length, 1); x.assert(p.elems[0].kind, 'string'); x.assert(p.elems[0].error, null); - x.assert(p.elems[0].getRaw(), 'a1'); + x.assert(p.elems[0].displayInCode(), '"a"+1'); x.assert(p.elems[0].getErrorText(), '"a" + 1 '); p = inferredValues('1 + "a" '); @@ -1960,7 +1961,7 @@ function checkExpr(x) { x.assert(p.elems.length, 1); x.assert(p.elems[0].kind, 'string'); x.assert(p.elems[0].error, null); - x.assert(p.elems[0].getRaw(), '1a'); + x.assert(p.elems[0].displayInCode(), '1+"a"'); x.assert(p.elems[0].getErrorText(), '1 + "a" '); p = inferredValues('1 + "a" + 4 + "bcd"'); @@ -1968,7 +1969,7 @@ function checkExpr(x) { x.assert(p.elems.length, 1); x.assert(p.elems[0].kind, 'string'); x.assert(p.elems[0].error, null); - x.assert(p.elems[0].getRaw(), '1a4bcd'); + x.assert(p.elems[0].displayInCode(), '1+"a"+4+"bcd"'); x.assert(p.elems[0].getErrorText(), '1 + "a" + 4 + "bcd"'); process.env['variable'] = 'hello'; @@ -1977,7 +1978,7 @@ function checkExpr(x) { x.assert(p.elems.length, 1); x.assert(p.elems[0].kind, 'string'); x.assert(p.elems[0].error, null); - x.assert(p.elems[0].getRaw(), 'hello2'); + x.assert(p.elems[0].displayInCode(), '"hello"+2'); x.assert(p.elems[0].getErrorText(), '|variable| + 2'); process.env['variable'] = '1'; @@ -1995,7 +1996,7 @@ function checkExpr(x) { x.assert(p.elems.length, 1); x.assert(p.elems[0].kind, 'string'); x.assert(p.elems[0].error, null); - x.assert(p.elems[0].getRaw(), '12'); + x.assert(p.elems[0].displayInCode(), '1+""+2'); x.assert(p.elems[0].getErrorText(), '1 + "" + 2'); p = inferredValues('1 + 2 + "a"'); @@ -2003,7 +2004,7 @@ function checkExpr(x) { x.assert(p.elems.length, 1); x.assert(p.elems[0].kind, 'string'); x.assert(p.elems[0].error, null); - x.assert(p.elems[0].getRaw(), '12a'); + x.assert(p.elems[0].displayInCode(), '1+2+"a"'); x.assert(p.elems[0].getErrorText(), '1 + 2 + "a"'); p = inferredValues('"a" + 1 + 2'); @@ -2011,7 +2012,7 @@ function checkExpr(x) { x.assert(p.elems.length, 1); x.assert(p.elems[0].kind, 'string'); x.assert(p.elems[0].error, null); - x.assert(p.elems[0].getRaw(), 'a12'); + x.assert(p.elems[0].displayInCode(), '"a"+1+2'); x.assert(p.elems[0].getErrorText(), '"a" + 1 + 2'); p = inferredValues('"a" + 1 + \n2'); @@ -2019,7 +2020,7 @@ function checkExpr(x) { x.assert(p.elems.length, 1); x.assert(p.elems[0].kind, 'string'); x.assert(p.elems[0].error, null); - x.assert(p.elems[0].getRaw(), 'a12'); + x.assert(p.elems[0].displayInCode(), '"a"+1+2'); x.assert(p.elems[0].getErrorText(), '"a" + 1 + \n2'); p = inferredValues('"a" + 1 + // comment?\n2'); @@ -2027,7 +2028,7 @@ function checkExpr(x) { x.assert(p.elems.length, 1); x.assert(p.elems[0].kind, 'string'); x.assert(p.elems[0].error, null); - x.assert(p.elems[0].getRaw(), 'a12'); + x.assert(p.elems[0].displayInCode(), '"a"+1+2'); x.assert(p.elems[0].getErrorText(), '"a" + 1 + // comment?\n2'); p = inferredValues('{"x" + 2: 1,}'); @@ -2038,7 +2039,7 @@ function checkExpr(x) { x.assert(p.elems[0].getErrorText(), '{"x" + 2: 1,}'); x.assert(p.elems[0].getRaw()[0].key.kind, 'string'); x.assert(p.elems[0].getRaw()[0].key.getErrorText(), '"x" + 2'); - x.assert(p.elems[0].getRaw()[0].key.getRaw(), 'x2'); + x.assert(p.elems[0].getRaw()[0].key.displayInCode(), '"x"+2'); x.assert(p.elems[0].getRaw()[0].value.kind, 'number'); x.assert(p.elems[0].getRaw()[0].value.getRaw(), '1'); @@ -2180,6 +2181,20 @@ function checkExpr(x) { x.assert(p.elems[0].error, null); x.assert(p.elems[0].getRaw(), '!compareArrayLike(["1", 1], ["a", 3, 2])'); x.assert(p.elems[0].getErrorText(), '("1", 1) != ("a", 3, 2)'); + + p = inferredValues('(1 * 3) + "a"'); + x.assert(p.errors, []); + x.assert(p.elems.length, 1); + x.assert(p.elems[0].kind, 'string'); + x.assert(p.elems[0].error, null); + x.assert(p.elems[0].displayInCode(), '(1 * 3)+"a"'); + + p = inferredValues('(|x| * 3) + "a"', {'x': 1}); + x.assert(p.errors, []); + x.assert(p.elems.length, 1); + x.assert(p.elems[0].kind, 'string'); + x.assert(p.elems[0].error, null); + x.assert(p.elems[0].displayInCode(), '(1 * 3)+"a"'); } function checkBlock(x) { @@ -2448,11 +2463,12 @@ function checkObjectPath(x) { x.assert(p.elems.length, 1); x.assert(p.elems[0].kind, 'object-path'); x.assert(p.elems[0].error, null); + x.assert(p.elems[0].getStringValue(), '["a","b"+"c","d"]'); x.assert(p.elems[0].value.length, 3); x.assert(p.elems[0].value[0].kind, 'string'); x.assert(p.elems[0].value[0].value, 'a'); x.assert(p.elems[0].value[1].kind, 'string'); - x.assert(p.elems[0].value[1].value, 'bc'); + x.assert(p.elems[0].value[1].displayInCode(), '"b"+"c"'); x.assert(p.elems[0].value[2].kind, 'string'); x.assert(p.elems[0].value[2].value, 'd'); @@ -2463,7 +2479,7 @@ function checkObjectPath(x) { x.assert(p.elems[0].error, null); x.assert(p.elems[0].value.length, 2); x.assert(p.elems[0].value[0].kind, 'string'); - x.assert(p.elems[0].value[0].value, '2c'); + x.assert(p.elems[0].value[0].displayInCode(), '2+"c"'); x.assert(p.elems[0].value[1].kind, 'string'); x.assert(p.elems[0].value[1].value, 'd'); @@ -2476,7 +2492,7 @@ function checkObjectPath(x) { x.assert(p.elems[0].value[0].kind, 'string'); x.assert(p.elems[0].value[0].value, 'a'); x.assert(p.elems[0].value[1].kind, 'string'); - x.assert(p.elems[0].value[1].value, 'b2c'); + x.assert(p.elems[0].value[1].displayInCode(), '"b"+2+"c"'); x.assert(p.elems[0].value[2].kind, 'string'); x.assert(p.elems[0].value[2].value, 'd'); @@ -2489,7 +2505,7 @@ function checkObjectPath(x) { x.assert(p.elems[0].value[0].kind, 'string'); x.assert(p.elems[0].value[0].value, 'a'); x.assert(p.elems[0].value[1].kind, 'string'); - x.assert(p.elems[0].value[1].value, 'bc'); + x.assert(p.elems[0].value[1].displayInCode(), '"b"+"c"'); p = inferredValues('"a"."b" + 2'); x.assert(p.errors, []); @@ -2500,7 +2516,7 @@ function checkObjectPath(x) { x.assert(p.elems[0].value[0].kind, 'string'); x.assert(p.elems[0].value[0].value, 'a'); x.assert(p.elems[0].value[1].kind, 'string'); - x.assert(p.elems[0].value[1].value, 'b2'); + x.assert(p.elems[0].value[1].displayInCode(), '"b"+2'); p = inferredValues('"a"."b" + "c" + 2'); x.assert(p.errors, []); @@ -2511,7 +2527,7 @@ function checkObjectPath(x) { x.assert(p.elems[0].value[0].kind, 'string'); x.assert(p.elems[0].value[0].value, 'a'); x.assert(p.elems[0].value[1].kind, 'string'); - x.assert(p.elems[0].value[1].value, 'bc2'); + x.assert(p.elems[0].value[1].displayInCode(), '"b"+"c"+2'); p = inferredValues('"a"."b" + |c| + 2', {'c': 'r'}); x.assert(p.errors, []); @@ -2522,7 +2538,7 @@ function checkObjectPath(x) { x.assert(p.elems[0].value[0].kind, 'string'); x.assert(p.elems[0].value[0].value, 'a'); x.assert(p.elems[0].value[1].kind, 'string'); - x.assert(p.elems[0].value[1].value, 'br2'); + x.assert(p.elems[0].value[1].displayInCode(), '"b"+"r"+2'); p = inferredValues('"a".|c|', {'c': 'r'}); x.assert(p.errors, []); diff --git a/tools/ui.js b/tools/ui.js index 395d61fa..2fa2341b 100644 --- a/tools/ui.js +++ b/tools/ui.js @@ -133,11 +133,11 @@ async function checkUi(x) { checkImageFileForTest( x, 'tests/ui/screenshot-on-failure-failure.png', 'screenshot-on-failure.goml'); + const errors = x.getTotalErrors(); print(''); print(`<= Ending ${x.getTotalRanTests()} ${plural('test', x.getTotalRanTests())} with ` + - `${x.getTotalErrors()} ${plural('error', x.getTotalErrors())}`); + `${x.getTotalErrors()} ${plural('error', errors)}`); - const errors = x.getTotalErrors(); x.endTestSuite(false); return errors; }