From 1a57a61138fea744345e048137bb24f327419d32 Mon Sep 17 00:00:00 2001 From: Eric Newport Date: Fri, 18 Oct 2024 18:29:10 -0400 Subject: [PATCH] Tests refactor and more cheerio polyfill work - Fixed client-side tests to test Teddy in the browser properly. - Refactored tests to improve maintainability. - Did further work on `cheerioPolyfill.js`. It's more than half finished, but it isn't fully done yet. - Updated various dependencies. --- CHANGELOG.md | 5 +- cheerioPolyfill.js | 25 +- package-lock.json | 90 +++---- package.json | 6 +- teddy.js | 43 +++- test/loaders/loadTests.js | 32 +++ test/loaders/loaderUtils.js | 56 ----- test/loaders/mocha.js | 62 ++--- test/loaders/playwright.js | 163 ++++++++----- test/{models => }/model.js | 0 test/testUtils.js | 13 - test/tests.js | 474 ++++++++++++++++-------------------- webpack.config.js | 30 ++- 13 files changed, 503 insertions(+), 496 deletions(-) create mode 100644 test/loaders/loadTests.js delete mode 100644 test/loaders/loaderUtils.js rename test/{models => }/model.js (100%) delete mode 100644 test/testUtils.js diff --git a/CHANGELOG.md b/CHANGELOG.md index d97cd28..bbc149b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ ## Next version -- Put your changes here... +- Fixed client-side tests to test Teddy in the browser properly. +- Refactored tests to improve maintainability. +- Did further work on `cheerioPolyfill.js`. It's more than half finished, but it isn't fully done yet. +- Updated various dependencies. ## 0.6.13 diff --git a/cheerioPolyfill.js b/cheerioPolyfill.js index 9bc90ee..0fbe9ee 100644 --- a/cheerioPolyfill.js +++ b/cheerioPolyfill.js @@ -1,11 +1,4 @@ // extend HTMLElement prototype to include cheerio properties -Object.defineProperty(window.HTMLElement.prototype, 'attribs', { - get: function () { - if (this.__attribs === undefined) this.__attribs = this.attributes - return this.__attribs - } -}) - Object.defineProperty(window.HTMLElement.prototype, 'name', { get: function () { if (this.__name === undefined) this.__name = this.nodeName.toLowerCase() @@ -21,6 +14,7 @@ Object.defineProperty(window.HTMLElement.prototype, 'parent', { }) // TODO: write more HTMLElement property extensions to polyfill cheerio: this will require reading teddy.js line by line to see what properties from cheerio each method uses and adapt them like above one property at a time +// TODO: nextSibling, children? // create a native DOMParser const parser = new window.DOMParser() @@ -29,6 +23,7 @@ const parser = new window.DOMParser() export function load (html) { console.log('Loading cheerio polyfill... TODO: This is unfinished! Please use teddy.mjs or teddy.cjs via a bundle for now.') const doc = parser.parseFromString(html, 'text/html') + console.log('doc:', doc.body.innerHTML) // return a querySelector function with function chains // e.g. dom('include') or dom(el) from teddy @@ -36,7 +31,7 @@ export function load (html) { // if query is a string, we need to create a dom object from the string: an object with elements in it, e.g. a list of include tag objects if (typeof query === 'string') { const els = doc.querySelectorAll(query) - console.log(els) + console.log('cheerio polyfill: dom(query)', els) return els // return the object collection } @@ -46,33 +41,46 @@ export function load (html) { // e.g. dom(el).children() from teddy children: function () { + console.log('cheerio polyfill: children()', el.children) return el.children }, // e.g. dom(arg).html() from teddy html: function () { + console.log('cheerio polyfill: html()', el.innerHTML) return el.innerHTML }, // e.g. dom(el).attr('teddy_deferred_dynamic_include', 'true') from teddy attr: function (attr, val) { + console.log('cheerio polyfill: attr()', attr, val) return el.setAttribute(attr, val) }, // dom(el).removeAttr(attr) from teddy removeAttr: function (attr) { + console.log('cheerio polyfill: removeAttr()', attr) return el.removeAttribute(attr) }, // e.g. dom(el).replaceWith(localDom.html()) from teddy replaceWith: function (html) { + // can either be a string or an array of elements + console.log('replaceWith doc:', doc.body.innerHTML) + if (typeof html === 'object') { + let newHtml = '' + for (const el of html) newHtml += el.outerHTML + html = newHtml + } const temp = document.createElement('div') temp.innerHTML = html el.replaceWith(...temp.children) + console.log('replaceWith doc:', doc.body.innerHTML) }, // e.g. dom(el).remove() from teddy remove: function () { + console.log('cheerio polyfill: remove()', el) return el.remove() } } @@ -80,6 +88,7 @@ export function load (html) { // e.g. dom.html() from teddy $.html = function () { + console.log('cheerio polyfill: dom.html()', doc.body.innerHTML) return doc.body.innerHTML } diff --git a/package-lock.json b/package-lock.json index aa2b5df..fdef3f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,11 +12,11 @@ "cheerio": "1.0.0" }, "devDependencies": { - "@playwright/test": "1.48.0", + "@playwright/test": "1.48.1", "c8": "10.1.2", "codecov": "3.8.3", "cross-env": "7.0.3", - "eslint": "9.12.0", + "eslint": "9.13.0", "eslint-plugin-html": "8.1.2", "eslint-plugin-mocha": "10.5.0", "mocha": "10.7.3", @@ -104,9 +104,9 @@ } }, "node_modules/@eslint/core": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz", - "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", + "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -158,9 +158,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz", - "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz", + "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==", "dev": true, "license": "MIT", "engines": { @@ -178,9 +178,9 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", - "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.1.tgz", + "integrity": "sha512-HFZ4Mp26nbWk9d/BpvP0YNL6W4UoZF0VFcTw/aPPA8RpOxeFQgK+ClABGgAUXs9Y/RGX/l1vOmrqz1MQt9MNuw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -493,13 +493,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.0.tgz", - "integrity": "sha512-W5lhqPUVPqhtc/ySvZI5Q8X2ztBOUgZ8LbAFy0JQgrXZs2xaILrUcNO3rQjwbLPfGK13+rZsDa1FpG+tqYkT5w==", + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.1.tgz", + "integrity": "sha512-s9RtWoxkOLmRJdw3oFvhFbs9OJS0BzrLUc8Hf6l2UdCNd1rqeEyD4BhCJkvzeEoD1FsK4mirsWwGerhVmYKtZg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.48.0" + "playwright": "1.48.1" }, "bin": { "playwright": "cli.js" @@ -554,9 +554,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", - "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "version": "22.7.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.6.tgz", + "integrity": "sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw==", "dev": true, "license": "MIT", "dependencies": { @@ -793,9 +793,9 @@ "license": "Apache-2.0" }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", + "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", "dev": true, "license": "MIT", "bin": { @@ -1294,9 +1294,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001668", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001668.tgz", - "integrity": "sha512-nWLrdxqCdblixUO+27JtGJJE/txpJlyUy5YN1u53wLZkP0emYCo5zgS6QYft7VUYR42LGgi/S5hdLZTrnyIddw==", + "version": "1.0.30001669", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", + "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", "dev": true, "funding": [ { @@ -1796,9 +1796,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.38", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.38.tgz", - "integrity": "sha512-VbeVexmZ1IFh+5EfrYz1I0HTzHVIlJa112UEWhciPyeOcKJGeTv6N8WnG4wsQB81DGCaVEGhpSb6o6a8WYFXXg==", + "version": "1.5.41", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.41.tgz", + "integrity": "sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ==", "dev": true, "license": "ISC" }, @@ -2068,18 +2068,18 @@ } }, "node_modules/eslint": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz", - "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==", + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.13.0.tgz", + "integrity": "sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.11.0", "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.6.0", + "@eslint/core": "^0.7.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.12.0", + "@eslint/js": "9.13.0", "@eslint/plugin-kit": "^0.2.0", "@humanfs/node": "^0.16.5", "@humanwhocodes/module-importer": "^1.0.1", @@ -4641,9 +4641,9 @@ } }, "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, @@ -4820,13 +4820,13 @@ } }, "node_modules/playwright": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.0.tgz", - "integrity": "sha512-qPqFaMEHuY/ug8o0uteYJSRfMGFikhUysk8ZvAtfKmUK3kc/6oNl/y3EczF8OFGYIi/Ex2HspMfzYArk6+XQSA==", + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.1.tgz", + "integrity": "sha512-j8CiHW/V6HxmbntOfyB4+T/uk08tBy6ph0MpBXwuoofkSnLmlfdYNNkFTYD6ofzzlSqLA1fwH4vwvVFvJgLN0w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.48.0" + "playwright-core": "1.48.1" }, "bin": { "playwright": "cli.js" @@ -4839,9 +4839,9 @@ } }, "node_modules/playwright-core": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.0.tgz", - "integrity": "sha512-RBvzjM9rdpP7UUFrQzRwR8L/xR4HyC1QXMzGYTbf1vjw25/ya9NRAVnXi/0fvFopjebvyPzsmoK58xxeEOaVvA==", + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.1.tgz", + "integrity": "sha512-Yw/t4VAFX/bBr1OzwCuOMZkY1Cnb4z/doAFSwf4huqAGWmf9eMNjmK7NiOljCdLmxeRYcGPPmcDgU0zOlzP0YA==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5998,9 +5998,9 @@ } }, "node_modules/terser": { - "version": "5.34.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.34.1.tgz", - "integrity": "sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA==", + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", "dev": true, "license": "BSD-2-Clause", "dependencies": { diff --git a/package.json b/package.json index 74288ce..82730ed 100644 --- a/package.json +++ b/package.json @@ -30,11 +30,11 @@ "cheerio": "1.0.0" }, "devDependencies": { - "@playwright/test": "1.48.0", + "@playwright/test": "1.48.1", "c8": "10.1.2", "codecov": "3.8.3", "cross-env": "7.0.3", - "eslint": "9.12.0", + "eslint": "9.13.0", "eslint-plugin-html": "8.1.2", "eslint-plugin-mocha": "10.5.0", "mocha": "10.7.3", @@ -63,7 +63,7 @@ "build": "webpack", "coverage": "npm run coverage-server && npm run coverage-client", "coverage-server": "npm run build && cross-env NODE_ENV=cover c8 mocha --timeout 60000 test/loaders/mocha.js", - "coverage-client": "npm run build && cross-env NODE_ENV=cover c8 playwright test", + "coverage-client": "npm run build && cross-env NODE_ENV=cover c8 --include=dist/teddy.js playwright test", "lint": "standard && eslint ./test && standard --plugin html *.html", "lint-fix": "standard --fix && eslint ./test && standard --plugin html *.html --fix", "test": "npm run test-server && npm run test-client", diff --git a/teddy.js b/teddy.js index d7ae774..bd5ae1c 100644 --- a/teddy.js +++ b/teddy.js @@ -5,6 +5,7 @@ import path from 'path' // node path module import { load as cheerioLoad } from 'cheerio/slim' // dom parser const cheerioOptions = { xml: { xmlMode: false, lowerCaseAttributeNames: false, decodeEntities: false } } +const browser = !fs || !fs.readFileSync // true if we are executing in the browser context const params = {} // teddy parameters setDefaultParams() // set params to the defaults const templates = {} // loaded templates are stored as object collections, e.g. { "myTemplate.html": "

some markup

"} @@ -24,7 +25,7 @@ function loadTemplate (template) { } const name = template let register = false - if (!templates[template] && template.indexOf('<') === -1 && fs !== undefined && fs.readFileSync !== undefined) { + if (!templates[template] && template.indexOf('<') === -1 && !browser) { // template is not found, it is not code, and we're in the node.js context register = true // append extension if not present @@ -95,6 +96,7 @@ function replaceCacheElements (dom, model) { const tags = dom('cache:not([defer])') if (tags.length > 0) { for (const el of tags) { + if (browser) el.attribs = getAttribs(el) const name = el.attribs.name if (name.includes('{')) continue const key = el.attribs.key || 'none' @@ -171,6 +173,7 @@ function parseIncludes (dom, model, dynamic) { } if (next) continue // get attributes + if (browser) el.attribs = getAttribs(el) const src = el.attribs.src if (!src) { if (params.verbosity > 1) console.warn('teddy encountered an include tag with no src attribute.') @@ -185,6 +188,7 @@ function parseIncludes (dom, model, dynamic) { const localModel = Object.assign({}, model) for (const arg of dom(el).children()) { if (arg.name === 'arg') { + if (browser) arg.attribs = getAttribs(arg) const argval = Object.keys(arg.attribs)[0] getOrSetObjectByDotNotation(localModel, argval, dom(arg).html()) } @@ -227,6 +231,7 @@ function parseConditionals (dom, model) { if (next) continue // get conditions let args = [] + if (browser) el.attribs = getAttribs(el) for (const attr in el.attribs) { const val = el.attribs[attr] if (val) args.push(`${attr}=${val}`) @@ -268,6 +273,7 @@ function parseConditionals (dom, model) { case 'elseif': // get conditions args = [] + if (browser) nextSibling.attribs = getAttribs(nextSibling) for (const attr in nextSibling.attribs) { const val = nextSibling.attribs[attr] if (val) args.push(`${attr}=${val}`) @@ -308,6 +314,7 @@ function parseConditionals (dom, model) { case 'elseunless': // get conditions args = [] + if (browser) nextSibling.attribs = getAttribs(nextSibling) for (const attr in nextSibling.attribs) { const val = nextSibling.attribs[attr] if (val) args.push(`${attr}=${val}`) @@ -460,6 +467,7 @@ function parseOneLineConditionals (dom, model) { for (const el of tags) { // skip parsing this if it uses variables as part of its conditions; it will get caught in the next pass after parseVars runs let defer = false + if (browser) el.attribs = getAttribs(el) for (const attr in el.attribs) { const val = el.attribs[attr] if (val.includes('{')) { @@ -490,6 +498,7 @@ function parseOneLineConditionals (dom, model) { let cond let ifTrue let ifFalse + if (browser) el.attribs = getAttribs(el) for (const attr in el.attribs) { const val = el.attribs[attr] if (attr.startsWith('if-')) { @@ -537,6 +546,7 @@ function parseLoops (dom, model) { let loopThrough let keyName let valName + if (browser) el.attribs = getAttribs(el) for (const attr in el.attribs) { if (attr === 'through') loopThrough = getOrSetObjectByDotNotation(model, el.attribs[attr]) else if (attr === 'key') keyName = el.attribs[attr] @@ -660,6 +670,7 @@ function defineNewCaches (dom, model) { const tags = dom('cache[defer]') if (tags.length > 0) { for (const el of tags) { + if (browser) el.attribs = getAttribs(el) const name = el.attribs.name const key = el.attribs.key || 'none' const maxAge = parseInt(el.attribs.maxAge) || 0 @@ -703,6 +714,7 @@ function cleanupStrayTeddyTags (dom) { if (el.name === 'include' || el.name === 'arg' || el.name === 'if' || el.name === 'unless' || el.name === 'elseif' || el.name === 'elseunless' || el.name === 'else' || el.name === 'loop' || el.name === 'cache') { dom(el).remove() } + if (browser) el.attribs = getAttribs(el) for (const attr in el.attribs) { if (attr === 'true' || attr === 'false' || attr === 'teddy_deferred_one_line_conditional' || attr.startsWith('if-')) { dom(el).removeAttr(attr) @@ -804,9 +816,36 @@ function getOrSetObjectByDotNotation (obj, dotNotation, value) { return obj[dotNotation[0]] } else if (dotNotation.length === 0) return obj else if (dotNotation.length === 1) { - if (obj) return obj[dotNotation[0]] + if (obj) { + if (browser) return caseInsensitiveLookup(obj, dotNotation[0]) + else return obj[dotNotation[0]] + } return false } else return getOrSetObjectByDotNotation(obj[dotNotation[0]], dotNotation.slice(1), value) + function caseInsensitiveLookup (obj, key) { + const lowerCaseKey = key.toLowerCase() + const normalizedObj = Object.keys(obj).reduce((acc, k) => { + acc[k.toLowerCase()] = obj[k] + return acc + }, {}) + return normalizedObj[lowerCaseKey] + } +} + +// #endregion + +// #region cheerio polyfills + +function getAttribs (element) { + const attributes = element.attributes + const attributesObject = {} + + for (let i = 0; i < attributes.length; i++) { + const attr = attributes[i] + attributesObject[attr.name] = attr.value + } + + return attributesObject } // #endregion diff --git a/test/loaders/loadTests.js b/test/loaders/loadTests.js new file mode 100644 index 0000000..0265df7 --- /dev/null +++ b/test/loaders/loadTests.js @@ -0,0 +1,32 @@ +// filters which tests to run based on the presence of "only" or "skip" +export function loadTests (testGroups) { + // handle when "only" has been added to some tests in a test group + if (testGroups.some(group => group.tests.some(test => test?.only))) { + testGroups = testGroups.filter(group => group.tests.some(test => test.only)) + } + + // handle when "skip" has been added to a test group itself + if (testGroups.some(group => group.skip)) { + testGroups = testGroups.filter(group => !group.skip) + } + + // handle when "only" has been added to a test group itself + if (testGroups.some(group => group.only)) { + testGroups = testGroups.filter(group => group.only) + } + + // examine the tests themselves for "only" and "skip" + for (const group of testGroups) { + // check for test skip + if (group.tests.some(test => test.skip)) { + group.tests = group.tests.filter(test => !test.skip) + } + + // check for test only + if (group.tests.some(test => test.only)) { + group.tests = group.tests.filter(test => test.only) + } + } + + return testGroups +} diff --git a/test/loaders/loaderUtils.js b/test/loaders/loaderUtils.js deleted file mode 100644 index 4330a24..0000000 --- a/test/loaders/loaderUtils.js +++ /dev/null @@ -1,56 +0,0 @@ -import path from 'path' -import fs from 'fs' - -export function sanitizeTests (conditions) { - // search condition tests for only's - if (conditions.some(condition => condition.tests.some(test => test?.only))) { - conditions = conditions.filter(condition => condition.tests.some(test => test.only)) - } - - // check for condition skip - if (conditions.some(condition => condition.skip)) { - conditions = conditions.filter(condition => !condition.skip) - } - - // check for condition only - if (conditions.some(condition => condition.only)) { - conditions = conditions.filter(condition => condition.only) - } - - // check condition tests - for (const condition of conditions) { - // check for test skip - if (condition.tests.some(test => test.skip)) { - condition.tests = condition.tests.filter(test => !test.skip) - } - - // check for test only - if (condition.tests.some(test => test.only)) { - condition.tests = condition.tests.filter(test => test.only) - } - } - - return conditions -} - -// pre-register teddy templates -export function registerTemplates (teddy, dir) { - const files = fs.readdirSync(dir) - - for (const file of files) { - const filePath = path.join(dir, file) - const fileStat = fs.statSync(filePath) - - if (fileStat.isDirectory()) { - // run again until file is found - registerTemplates(teddy, filePath) - } else { - // remove unneeded path and filetype - const path = filePath.replaceAll('\\', '/').replace('test/templates/', '').replace('.html', '') - - // set teddy template with file contents - const content = fs.readFileSync(filePath, 'utf-8') - teddy.setTemplate(path, content.replace(/\n/g, '')) - } - } -} diff --git a/test/loaders/mocha.js b/test/loaders/mocha.js index 58adecb..df275fa 100644 --- a/test/loaders/mocha.js +++ b/test/loaders/mocha.js @@ -1,54 +1,36 @@ /* eslint-env mocha */ import assert from 'assert' -import makeModel from '../models/model.js' -import testConditions from '../tests.js' -import { ignoreSpaces } from '../testUtils.js' -import { sanitizeTests } from './loaderUtils.js' import teddy from '../../teddy.js' +import { loadTests } from './loadTests.js' +import makeModel from '../model.js' +import testGroups from '../tests.js' -const conditions = sanitizeTests(testConditions) -for (const tc of conditions) { - describe(tc.describe, () => { +const testsToRun = loadTests(testGroups) +for (const testGroup of testsToRun) { + describe(testGroup.describe, () => { let model before(() => { teddy.setTemplateRoot('test/templates') model = makeModel() - if (process.env.NODE_ENV === 'test') { - teddy.setVerbosity(0) - } + if (process.env.NODE_ENV === 'test') teddy.setVerbosity(0) }) - for (const t of tc.tests) { - if (t.skip) continue - // callback function used on custom and asynchronous tests - const cb = (result, expected = true) => { - if (typeof expected === 'string') { - expected = ignoreSpaces(expected) - } - assert.equal(ignoreSpaces(result), expected) - } - - // test asynchronous code - if (t?.type === 'async') { - it(t.message, async () => await t.test(teddy, t.template, model, cb)) - continue - } - - // test code that is handled within that test (with use of a callback) - if (t?.type === 'custom') { - it(t.message, () => t.test(teddy, t.template, model, cb)) - continue - } - - // assert result of the test code - it(t.message, () => { - if (typeof t.expected === 'string') { - t.expected = ignoreSpaces(t.expected) - } - const result = ignoreSpaces(t.test(teddy, t.template, model)) - assert.equal(result, t.expected) - }) + for (const test of testGroup.tests) { + if (test.skip) continue + if (test.runMocha) test.run = test.runMocha + if (!test.run) continue + else it(test.message, async () => await test.run(teddy, test.template, model, teddyAssert, test.expected)) } }) } + +function teddyAssert (result, expected = true) { + if (typeof expected === 'string') expected = ignoreSpaces(expected) + assert.equal(ignoreSpaces(result), expected) +} + +function ignoreSpaces (str) { + if (typeof str !== 'string') return str + return str.replace(/\s/g, '') +} diff --git a/test/loaders/playwright.js b/test/loaders/playwright.js index 21f2608..6082ef3 100644 --- a/test/loaders/playwright.js +++ b/test/loaders/playwright.js @@ -1,65 +1,104 @@ -import { test, expect } from '@playwright/test' -import makeModel from '../models/model.js' -import testConditions from '../tests.js' -import { ignoreSpaces } from '../testUtils.js' -import { sanitizeTests, registerTemplates } from './loaderUtils.js' -import teddy from '../../teddy.js' - -// TODO: refactor this loader to import teddy from within the page's DOM so we can import the version of teddy without cheerio - -const conditions = sanitizeTests(testConditions) - -for (const tc of conditions) { - test.describe(tc.describe, () => { - // let coverageObj - let model - - test.beforeAll(() => { - // this ensures that teddy is not using the fs module to retrieve templates - teddy.setTemplateRoot('test/noTemplatesHere') - registerTemplates(teddy, 'test/templates') - model = makeModel() - }) - - for (const t of tc.tests) { - test(t.message, async ({ page }) => { - // callback function used on custom and asynchronous tests - const cb = (result, expected = true) => { - if (typeof expected === 'string') { - expected = ignoreSpaces(expected) - } - expect(ignoreSpaces(result)).toBe(expected) - } - - if (t.playwright) { - const params = { teddy, model, template: t.template } - await t.playwright(params, page, expect) - } else if (t?.type === 'async') { // test asynchronous code - if (!t.expected) { - await t.test(teddy, t.template, model, cb) - } else if (typeof t.expected === 'string') { - const content = await t.test(teddy, t.template, model, cb) - await page.setContent('
') - await page.evaluate((html) => { - document.getElementById('content').textContent = html - }, content) - expect(ignoreSpaces(await page.evaluate(() => document.getElementById('content').textContent))).toEqual(ignoreSpaces(t.expected)) - } else if (typeof t.expected === 'boolean') { - expect(t.test(teddy, t.template, model, cb)).toBe(t.expected) - } - } else if (t?.type === 'custom') { // test code that is handled within that test (with use of a callback) - t.test(teddy, t.template, model, cb) - } else if (typeof t.expected === 'string') { // test code that needs to be appended to the playwright page - const content = t.test(teddy, t.template, model) - await page.setContent('
') - await page.evaluate((html) => { - document.getElementById('content').textContent = html - }, content) - expect(ignoreSpaces(await page.evaluate(() => document.getElementById('content').textContent))).toStrictEqual(ignoreSpaces(t.expected)) - } else if (typeof t.expected === 'boolean') { // test code that is resolved in the test without a callback - expect(t.test(teddy, t.template, model)).toBe(t.expected) - } - }) +import path from 'path' +import fs from 'fs' +import { fileURLToPath } from 'url' +import { test as playwrightTest } from '@playwright/test' +import { loadTests } from './loadTests.js' +import makeModel from '../model.js' +import testGroups from '../tests.js' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) +const teddyPath = path.resolve(__dirname, '../../dist/teddy.js') +const testsToRun = loadTests(testGroups) + +// pre-register teddy templates +function registerTemplates (dir) { + const templates = [] + + function readDir (directory) { + const files = fs.readdirSync(directory) + + for (const file of files) { + const filePath = path.join(directory, file) + const fileStat = fs.statSync(filePath) + + if (fileStat.isDirectory()) { + readDir(filePath) + } else if (filePath.includes('.html')) { + const relativePath = path.relative(dir, filePath).replace(/\\/g, '/') + const content = fs.readFileSync(filePath, 'utf-8').replace(/\n/g, '') + templates.push({ + path: relativePath, + content + }) + } + } + } + + readDir(dir) + return templates +} +const templates = registerTemplates('test/templates') + +for (const testGroup of testsToRun) { + playwrightTest.describe(testGroup.describe, () => { + for (const test of testGroup.tests) { + if (test.skip) continue + if (test.runPlaywright) test.run = test.runPlaywright + if (!test.run) continue + else { + playwrightTest(test.message, async ({ page }) => { + // to debug, uncomment this: + // page.on('console', (msg) => console.log(msg)) + // for deeper debugging: export DEBUG=pw:browser + + const model = makeModel() + + // set an initial DOM + await page.setContent(` + + + + + + Teddy Playwright Tests + + + + `) + await page.addScriptTag({ path: teddyPath }) // add teddy script tag to the browser page + test.run = test.run?.toString() || '' // can't pass functions to page.evaluate, so we need to stringify the test.run function + + await page.evaluate(async (params) => { + const { test, templates, model } = params + + // load templates into browser context + for (const template of templates) window.teddy.setTemplate(template.path, template.content) + window.teddy.setTemplateRoot('test/templates') + + console.log(window.teddy) + + // fix the Set test by remaking the Set + model.set = new Set(['a', 'b', 'c']) + + // convert test.run method back from string to an actual excutable function + test.run = eval(test.run) // eslint-disable-line + await test.run(window.teddy, test.template, model, teddyAssert, test.expected) + + function teddyAssert (result, expected = true) { + if (typeof expected === 'string') expected = ignoreSpaces(expected) + if (ignoreSpaces(result) !== expected) { + throw new Error(`Assertion failed: expected ${expected}, got ${ignoreSpaces(result)}`) + } + } + + function ignoreSpaces (str) { + if (typeof str !== 'string') return str + return str.replace(/\s/g, '') + } + }, { test, templates, model }) + }) + } } }) } diff --git a/test/models/model.js b/test/model.js similarity index 100% rename from test/models/model.js rename to test/model.js diff --git a/test/testUtils.js b/test/testUtils.js deleted file mode 100644 index 97bb8a9..0000000 --- a/test/testUtils.js +++ /dev/null @@ -1,13 +0,0 @@ -export function ignoreSpaces (str) { - if (typeof str !== 'string') { - return str - } - - return str.replace(/\s/g, '') -} - -export function timeout (ms) { - return new Promise(resolve => setTimeout(resolve, ms)) -} - -export default { ignoreSpaces, timeout } diff --git a/test/tests.js b/test/tests.js index 0038a20..1273283 100644 --- a/test/tests.js +++ b/test/tests.js @@ -1,26 +1,10 @@ -import { timeout } from './testUtils.js' import { execSync } from 'child_process' import fs from 'fs' -/* - WRITING TESTS - - These tests are shared across all loaders (found in test/loaders). - - If the test is more complex than rendering a template, the `test` method has a 4th parameter (`assert`) that allows you to utilize the respective loaders equality checker. You will also need to add a `type` parameter to the test object (`async` or `custom`). - - Using the `assert` param should result in comparisons (assert(a, b), assert(a, !b)) - - PLAYWRIGHT TESTS - - If a playwright test requires more than the simple assertion option offered above, you can create a separate method (`playwright: (params, page, expect) => {}`) that allows you to write more complex client-side tests. `params` is an object containing the expect params in the `test` method, and `page` and `expect` are playwright-specific methods. - - SKIP/ONLY - - To skip test suites or individual tests, add `skip: true` to the suite/test object - - To test an individual suite or test, add `only: true` to the suite/test object -*/ +// these tests are shared by both mocha and playwright +// to skip test groups or individual tests, add `skip: true` to the group or test object +// to test an individual group or test, add `only: true` to the group or test object +// to run a test only in mocha or only in playwright, use `runMocha` or `runPlaywright` instead of `run` export default [ { @@ -29,411 +13,391 @@ export default [ { message: 'should evaluate as true (conditionals/if.html)', template: 'conditionals/if', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'something\' is present

' }, { message: 'should evaluate as false and trigger condition (conditionals/ifElse.html)', template: 'conditionals/ifElse', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'doesntexist\' is not present

' }, { message: 'should evaluate as true (conditionals/ifValue.html)', template: 'conditionals/ifValue', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'something\' is set to \'Some content\'

' }, { message: 'should evaluate as false (conditionals/ifEmptyArray.html)', template: 'conditionals/ifEmptyArray', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'emptyArray\' is considered falsey

' }, { message: 'should evaluate as false and trigger condition (conditionals/ifElseValue.html)', template: 'conditionals/ifElseValue', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'something\' is not set to \'no\'

' }, { message: 'should evaluate as true (conditionals/unless.html)', template: 'conditionals/unless', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'doesntexist\' is not present

' }, { message: 'should evaluate as false and trigger condition (conditionals/unlessElse.html)', template: 'conditionals/unlessElse', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'something\' is present

' }, { message: 'should evaluate nested tag in the if (conditionals/unlessNestedIf.html)', template: 'conditionals/unlessNestedIf', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'doesntexist\' is not present

The variable \'anotherdoesntexist\' is not present

' }, { message: 'should evaluate nested tag in the else (conditionals/unlessNestedElse.html)', template: 'conditionals/unlessNestedElse', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'doesntexist\' is present

The variable \'anotherdoesntexist\' is not present

' }, { message: 'should evaluate as false and trigger condition with comment in between (conditionals/unlessWithComment.html)', template: 'conditionals/unlessWithComment', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'something\' is present

' }, { message: 'should evaluate nested tag in the if with a comment in between (conditionals/unlessNestedIfWithComment.html)', template: 'conditionals/unlessNestedIfWithComment', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'doesntexist\' is not present

The variable \'something\' is present

' }, { message: 'should evaluate as true (conditionals/unlessNull.html)', template: 'conditionals/unlessNull', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'nullVar\' is falsey

' }, { message: 'should evaluate as false and trigger condition (conditionals/unlessValue.html)', template: 'conditionals/unlessValue', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'something\' is set to \'Some content\'

' }, { message: 'should evaluate as false and trigger condition (conditionals/unlessElseValue.html)', template: 'conditionals/unlessElseValue', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'something\' is not set to \'no\'

' }, { message: 'should evaluate as false (conditionals/unlessAndOr.html)', template: 'conditionals/unlessAndOr', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

should render

' }, { message: 'should evaluate entire conditional and correctly show HTML comments (conditionals/commentConditional.html)', template: 'conditionals/commentConditional', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'something\' is present

' }, { message: 'should evaluate as false and as true (conditionals/ifElseIf.html)', template: 'conditionals/ifElseIf', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'somethingElse\' is present

' }, { message: 'should evaluate as false and as true (conditionals/unlessElseUnless.html)', template: 'conditionals/unlessElseUnless', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'doesntexist\' is not present

' }, { message: 'should eval as false and as true (conditionals/ifElseUnless.html)', template: 'conditionals/ifElseUnless', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'something\' is not set to \'maybe\'

' }, { message: 'should eval as false and as true (conditionals/unlessElseIf.html)', template: 'conditionals/unlessElseIf', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'somethingElse\' is present

' }, { message: 'should evaluate as false (conditionals/and.html)', template: 'conditionals/and', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

and: false

' }, { message: 'should evaluate `and` correctly when not using explicit values (conditionals/andImplicit.html)', template: 'conditionals/andImplicit', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

should render

and: false

and: false

and: false

' }, { message: 'should evaluate `and` correctly using explicit values (conditionals/andExplicit.html)', template: 'conditionals/andExplicit', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

should render

should render

should render

and: false

and: false

and: false

and: false

and: false

' }, { message: 'should evaluate `and` truth table (conditionals/andTruthTable.html)', template: 'conditionals/andTruthTable', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

and: true true

' }, { message: 'should evaluate `or` truth table correctly (conditionals/orTruthTable.html)', template: 'conditionals/orTruthTable', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

or: true true

or: true false

or: true false

or: false true

or: false false

or: false true

or: true false

or: true true

or: false false

or: false false

or: false false

' }, { message: 'should evaluate as true (conditionals/orSameVar.html)', template: 'conditionals/orSameVar', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

or: true

' }, { message: 'should evaluate as false (conditionals/xor.html)', template: 'conditionals/xor', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

xor: false

' }, { message: 'should evaluate xor correctly when not using explicit values (conditionals/xorImplicit.html)', template: 'conditionals/xorImplicit', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

xor: false

should render

should render

' }, { message: 'should evaluate xor correctly using explicit values (conditionals/xorExplicit.html)', template: 'conditionals/xorExplicit', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

xor: false

xor: false

xor: false

should render

should render

' }, { message: 'should evaluate as true (conditionals/andOr.html)', template: 'conditionals/andOr', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

and + or: true

' }, { message: 'should evaluate as false and as true (conditionals/not.html)', template: 'conditionals/not', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

not: false

not: true

' }, { message: 'should evaluate one line if "if-something" as true (conditionals/oneLine.html)', template: 'conditionals/oneLine', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

One line if.

' }, { message: 'should evaluate one line if "if-somethingFalse" as false (conditionals/oneLineIfBooleanValue.html)', template: 'conditionals/oneLineIfBooleanValue', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

' }, { message: 'should evaluate one line ifs in loops examining the object member\'s value correctly (conditionals/oneLineInLoop.html)', template: 'conditionals/oneLineInLoop', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

guy

girl

landscape

guy

girl

landscape

' }, { message: 'should evaluate one line if "if-something" as true when attributes are split across multiple lines (conditionals/oneLineNewLine.html)', template: 'conditionals/oneLineNewLine', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

One line if.

' }, { message: 'should evaluate one line if "if-something" as true in self-closing element (conditionals/oneLineSelfClosing.html)', template: 'conditionals/oneLineSelfClosing', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '' }, { message: 'should evaluate one line if "if-something" as true when result includes slash (/) characters (conditionals/oneLineWithSlash.html)', template: 'conditionals/oneLineWithSlash', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: 'One line if.' }, { message: 'should evaluate one line if "if-something" as true with no false condition supplied (conditionals/oneLineTrueOnly.html)', template: 'conditionals/oneLineTrueOnly', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

One line if.

' }, { message: 'should evaluate one line if "if-something" as false even with no false condition supplied (conditionals/oneLineNoFalse.html)', template: 'conditionals/oneLineNoFalse', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

{content.subTitle}

' }, { message: 'should evaluate one line if "if-something=\'Some content\'" as true (conditionals/oneLineValue.html)', template: 'conditionals/oneLineValue', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

One line if.

' }, { message: 'should evaluate one line if "if-something.something={something}" as false and remove attributes (conditionals/oneLineValueVars.html)', template: 'conditionals/oneLineValueVars', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '' }, { message: 'should evaluate ' }, { message: 'should evaluate ' }, { message: 'should evaluate one line if "if-something=\'Some content\'" as true and still add the id attribute regardless of the if statement outcome (conditionals/oneLineValueWithAdditionalAttributesNotImpactedByIf.html)', template: 'conditionals/oneLineValueWithAdditionalAttributesNotImpactedByIf', - playwright: async (params, page, expect) => { - await page.setContent('' + params.teddy.render(params.template, params.model) + '') - const firstSelected = await page.getByRole('option').first() - const secondSelected = await page.getByRole('option').nth(1) - - await expect(firstSelected).toHaveAttribute('selected', '') - await expect(secondSelected).toHaveAttribute('selected', '') - }, - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

One line if.

One line if.

One line if.

' }, { message: 'should evaluate one line if "if-something=\'\'" as false (conditionals/oneLineEmpty.html)', template: 'conditionals/oneLineEmpty', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

One line if.

' }, { message: 'should reduce multiple one line if statements down to only the first one (conditionals/oneLineMulti.html)', template: 'conditionals/oneLineMulti', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

One line if.

' }, { message: 'should evaluate one line if "if-something" with a dynamic value (conditionals/oneLineDynamicVariable.html)', template: 'conditionals/oneLineDynamicVariable', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Some content

' }, { message: 'should evaluate as true and the nested as false, triggering the nested condition (conditionals/nestedConditional.html)', template: 'conditionals/nestedConditional', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'something\' and \'somethingElse\' are both present

' }, { message: 'should render nothing if condition isn\'t met (conditionals/ifNotPresent.html)', template: 'conditionals/ifNotPresent', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '
' }, { message: 'should evaluate one line if as false and apply no class (conditionals/oneLineFalse.html)', template: 'conditionals/oneLineFalse', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

' }, { message: 'should evaluate one line if as false and apply a class (conditionals/oneLineOnlyFalse.html)', template: 'conditionals/oneLineOnlyFalse', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

' }, { message: 'should evaluate if statement that contains an element with a regex pattern (conditionals/ifEscapeRegex.html)', template: 'conditionals/ifEscapeRegex', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '' }, { message: 'should evaluate if statement that queries the same variable more than once (conditionals/duplicateVarInline.html)', template: 'conditionals/duplicateVarInline', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

True

' }, { message: 'should evaluate if statement with multiple instances of the same operator inline (conditionals/duplicateOperatorInline.html)', template: 'conditionals/duplicateOperatorInline', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

True

' }, { message: 'should evaluate containing regex pattern as false and trigger condition (conditionals/ifElseRegex.html)', template: 'conditionals/ifElseRegex', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

False

' }, { message: 'should evaluate if statement where elseif condition is a three character named object (conditionals/ifNestedProperties.html)', template: 'conditionals/ifNestedProperties', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Should render

' }, { message: 'should evaluate one line if "if-something" as true with quote types reversed (conditionals/oneLineReverseQuotes.html)', template: 'conditionals/oneLineReverseQuotes', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

One line if.

' }, { message: 'should evaluate one line if "if-something" as true with quote types reversed and a variable result (conditionals/oneLineReverseQuotesVar.html)', template: 'conditionals/oneLineReverseQuotesVar', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

One line if.

' }, { message: 'should ignore \'if-\' when not part of an if statement (conditionals/ifOutsideIf.html)', template: 'conditionals/ifOutsideIf', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

gif-something-jpg-png

' }, { message: 'should ignore \'if-\' when not part of an if statement with a variable present (conditionals/varIfOutsideIf.html)', template: 'conditionals/varIfOutsideIf', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

gif-Some content-jpg-png

' }, { message: 'should ignore \'if-\' when not part of an if statement when combined with a normal if statement (conditionals/nestedIfOutsideIf.html)', template: 'conditionals/nestedIfOutsideIf', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

gif-jpg-png If that should not be parsed, How art thou?

' }, { message: 'should ignore \'if-\' when not part of an if statement when combined with a one line if statement (conditionals/oneLineIfOutsideIf.html)', template: 'conditionals/oneLineIfOutsideIf', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

gif-jpg-png hello

' }, { message: 'should ignore \'if-\' when not part of an if statement when \'if-\' is part of an attribute\'s value (conditionals/oneLineIfInsideAttribute.html)', template: 'conditionals/oneLineIfInsideAttribute', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

hello

hello

hello

' }, { message: 'should ignore \'if-\' when not part of an if statement when combined with a one line if statement, reversed (conditionals/oneLineIfOutsideIfReverse.html)', template: 'conditionals/oneLineIfOutsideIfReverse', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

gif-jpg-png

' }, { message: 'should evaluate 5000 one line ifs in under 10000ms (conditionals/oneLinePerformance.html)', template: 'conditionals/oneLinePerformance', - test: (teddy, template, model) => { + run: async (teddy, template, model, assert, expected) => { const start = new Date().getTime() teddy.render(template, model) const end = new Date().getTime() @@ -446,43 +410,43 @@ export default [ { message: 'should evaluate as false and trigger condition containing very few characters (conditionals/ifElseLowChars.html)', template: 'conditionals/ifElseLowChars', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

B

' }, { message: 'should evaluate as false and trigger condition with preceding HTML comment (conditionals/ifCommentElse.html)', template: 'conditionals/ifCommentElse', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'doesntexist\' is not present

' }, { message: 'should evaluate as false and trigger condition with multiple preceding HTML comments (conditionals/ifMultipleCommentsElse.html)', template: 'conditionals/ifMultipleCommentsElse', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'doesntexist\' is not present

' }, { message: 'should evaluate as false and trigger condition with embedded HTML comments in conditional statements (conditionals/ifCommentsEmbedded.html)', template: 'conditionals/ifCommentsEmbedded', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

The variable \'doesntexist\' is not present

' }, { message: 'should evaluate the condition as true and not render the other conditions (conditionals/ifWithSiblingIfWithNestedIfElse.html)', template: 'conditionals/ifWithSiblingIfWithNestedIfElse', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Should render.

' }, { message: 'should print the letters behind both statements nested in the (conditionals/ifLoopDoubleIf.html)', template: 'conditionals/ifLoopDoubleIf', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

a

b

a

b

a

b

' }, { message: 'should correctly print the JSON string as unmodified text (conditionals/ifJSONStringPrintJSONString.html)', template: 'conditionals/ifJSONStringPrintJSONString', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '
{"content":{"appTitle":"Some App","pageTitle":"{content.appTitle}"},"currentYear":1858,"mainDomain":"localhost:43711","NODE_ENV":"development"}
' } ] @@ -493,136 +457,121 @@ export default [ { message: 'should a template (includes/include.html)', template: 'includes/include', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Some content

' }, { message: 'should all templates (includes/includeMultipleTemplates.html)', template: 'includes/includeMultipleTemplates', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

test test

test test

test test

' }, { message: 'should a template whose name is populated by a {variable} (includes/dynamicInclude.html)', template: 'includes/dynamicInclude', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Some content

' }, { message: 'should populate in the child template; the class should render (includes/includeArgCheckedByOneLineIfWrapper.html)', template: 'includes/includeArgCheckedByOneLineIfWrapper', - playwright: async (params, page, expect) => { - // temporarily set template root so teddy can find included templates - params.teddy.setTemplateRoot('test/templates') - - await page.setContent('' + params.teddy.render(params.template, params.model) + '') - - await expect(page.locator('html')).toContainText('Is it populated? populated') - - params.teddy.setTemplateRoot('test/noTemplatesHere') - }, - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Is it populated? populated

' }, { message: 'should a template with arguments (includes/includeWithArguments.html)', template: 'includes/includeWithArguments', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

override

' }, { message: 'should a template with a nested include (includes/nestedInclude.html)', template: 'includes/nestedInclude', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Some content

' }, { message: 'should a template with a nested include passing a text argument (includes/nestedIncludeWithArg.html)', template: 'includes/nestedIncludeWithArg', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

nested

' }, { message: 'should a template with loop arguments (includes/nestedLoop.html)', template: 'includes/nestedLoop', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

a

b

c

' }, { message: 'should ignore and skip rendering orphaned argument (includes/orphanedArgument.html)', template: 'includes/orphanedArgument', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '
' }, { message: 'should a template that contains loops and variables with an argument (includes/includeLoopsAndVars.html)', template: 'includes/includeLoopsAndVars', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

a

b

c

world

guy

' }, { message: 'should a template that contains numerical {variables} (includes/numericVarInArg.html)', template: 'includes/numericVarInArg', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

STRING!

' }, { message: 'should a template with numeric arguments (includes/numericArgument.html)', template: 'includes/numericArgument', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Hello!

' }, { message: 'should escape the contents of a script when included in a template (includes/inlineScriptTag.html)', template: 'includes/inlineScriptTag', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Hello!

' }, { message: 'should evaluate {variable} outside of include as original model value (includes/argRedefineModelVar.html)', template: 'includes/argRedefineModelVar', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Some content

' }, { message: 'should prevent recursion abuse (includes/argVariableWithinArg.html)', template: 'includes/argVariableWithinArg', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Some content

' }, { message: 'should a template and render pageContent inside of (includes/includeIfContent.html)', template: 'includes/includeIfContent', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

hello

' }, { message: 'should a template and render pageContent contents and correctly parse , , and tags (includes/includeComplexContent.html)', template: 'includes/includeComplexContent', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '
other_prop_one
other_prop_two
' }, { message: 'should a template and escape regex pattern in argument (includes/includeEscapeRegex.html)', template: 'includes/includeEscapeRegex', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '' }, { message: 'should ignore includes with invalid markup (includes/invalidIncludeMarkup.html)', template: 'includes/invalidIncludeMarkup', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Some content

' }, { message: 'should escape from infinite loop of includes via setMaxPasses (includes/includeInfiniteLoop.html)', template: 'includes/includeInfiniteLoop', - playwright: async (params, page, expect) => { - await page.setContent('' + params.teddy.render(params.template, params.model) + '') - - await expect(page.locator('html')).toContainText('{infinity2}') - }, - test: (teddy, template, model) => { + run: async (teddy, template, model, assert, expected) => { teddy.setVerbosity(3) teddy.setMaxPasses(100) @@ -637,19 +586,19 @@ export default [ { message: 'should evaluate a nested reverse quotes oneliner with an arg passed to it (includes/nestedOneliner.html)', template: 'includes/nestedOneliner', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

One line if.

' }, { message: 'should populate in the child template (includes/includeArgCheckedByOneLineIfWrapper.html)', template: 'includes/includeArgCheckedByOneLineIfWrapper', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Is it populated? populated

' }, { message: 'should a template with a one-line if statement that renders correctly (includes/includeOneLineOnlyFalse.html)', template: 'includes/includeOneLineOnlyFalse', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

' } ] @@ -660,128 +609,121 @@ export default [ { message: 'should loop through {letters} correctly (looping/loopVal.html)', template: 'looping/loopVal', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

a

b

c

' }, { message: 'should loop through {set} correctly (looping/loopValSet.html)', template: 'looping/loopValSet', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

a

b

c

' }, { message: 'should loop through {names} correctly (looping/loopKeyVal.html)', template: 'looping/loopKeyVal', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

jack

guy

jill

girl

hill

landscape

' }, { message: 'should loop through {arrays} correctly (looping/loopArrayOfArrays.html)', template: 'looping/loopArrayOfArrays', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

0

a

b

c

1

d

e

f

2

g

h

i

' }, { message: 'should loop through {objects} correctly (looping/loopArrayOfObjects.html)', template: 'looping/loopArrayOfObjects', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

0

1

2

3

1

4

5

6

2

7

8

9

' }, { message: 'should loop through a {nested.object} correctly (looping/nestedObjectLoop.html)', template: 'looping/nestedObjectLoop', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

a: 4

b: 5

c: 6

' }, { message: 'should parse loop through nested object correctly (looping/nestedObjectLoopLookup.html)', template: 'looping/nestedObjectLoopLookup', - playwright: async (params, page, expect) => { - await page.setContent('' + params.teddy.render(params.template, params.model) + '') - - await expect(page.locator('input').first()).toHaveAttribute('checked', '') - await expect(page.locator('input').nth(1)).not.toHaveAttribute('checked', '') - await expect(page.locator('input').nth(2)).toHaveAttribute('checked', '') - }, - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

1

2

3

' }, { message: 'should parse nested loops correctly (looping/nestedLoopsObjectWithArrayOfObjects.html)', template: 'looping/nestedLoopsObjectWithArrayOfObjects', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

value1

value2

value3

value4

' }, { message: 'should render {variables} via second loop (looping/varNameViaVarInLoop.html)', template: 'looping/varNameViaVarInLoop', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

guy

girl

landscape

' }, { message: 'should render {variables} defined as {varname.{othervar}} under slightly different conditions (looping/varNameViaVarInLoopWithIndependentVars.html)', template: 'looping/varNameViaVarInLoopWithIndependentVars', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

guy

girl

landscape

' }, { message: 'should render {variable.{otherVar}} in loop that repeats twice doubled (looping/varNameViaVarInLoopWithIndependentVarsDoubled.html)', template: 'looping/varNameViaVarInLoopWithIndependentVarsDoubled', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

guy

girl

landscape

guy

girl

landscape

' }, { message: 'should render {variable.{otherVar}} in nested loop variant 1 (looping/varNameViaVarInLoopWithIndependentVarsViaArray.html)', template: 'looping/varNameViaVarInLoopWithIndependentVarsViaArray', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

guy

girl

landscape

' }, { message: 'should render {variable.{otherVar}} in nested loop variant 2 (looping/varNameViaVarInLoopWithIndependentVarsViaArrayTwice.html)', template: 'looping/varNameViaVarInLoopWithIndependentVarsViaArrayTwice', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

guy

girl

landscape

man

woman

scenary

' }, { message: 'should not render the loop (looping/commentedLoopInLoop.html)', template: 'looping/commentedLoopInLoop', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

' }, { message: 'should parse nested loops correctly (looping/nestedLoops.html)', template: 'looping/nestedLoops', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

1

  • 0: one
  • 1: two
  • 2: three

2

  • 0: four
  • 1: five
  • 2: six

3

  • 0: seven
  • 1: eight
  • 2: nine
' }, { message: 'should parse complex nested nested loops correctly (looping/nestedNestedLoops.html)', template: 'looping/nestedNestedLoops', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

1

  • 1
    • 0: one
    • 1: two
    • 2: three
  • 2
    • 0: four
    • 1: five
    • 2: six
  • 3
    • 0: seven
    • 1: eight
    • 2: nine

2

  • 1
    • 0: one
    • 1: two
    • 2: three
  • 2
    • 0: four
    • 1: five
    • 2: six
  • 3
    • 0: seven
    • 1: eight
    • 2: nine

3

  • 1
    • 0: one
    • 1: two
    • 2: three
  • 2
    • 0: four
    • 1: five
    • 2: six
  • 3
    • 0: seven
    • 1: eight
    • 2: nine
' }, { message: 'should loop through nested arrays correctly (looping/nestedArrays.html)', template: 'looping/nestedArrays', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

one

two

three

four

five

six

seven

eight

nine

' }, { message: 'should loop through nested objects correctly (looping/nestedObjects.html)', template: 'looping/nestedObjects', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Thing With Name 1

Thing With Name 1: Subthing With Name 1

Thing With Name 1: Subthing With Name 2

Thing With Name 1: Subthing With Name 3

Thing With Name 2

Thing With Name 2: Subthing With Name 4

Thing With Name 2: Subthing With Name 5

Thing With Name 2: Subthing With Name 6

Thing With Name 3

Thing With Name 3: Subthing With Name 7

Thing With Name 3: Subthing With Name 8

Thing With Name 3: Subthing With Name 9

' }, { message: 'should loop through a quad-nested structure correctly (looping/quadNested.html)', template: 'looping/quadNested', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '' }, { message: 'should loop through an array of 5000 elements caching the first pass with a element so the second pass is faster (looping/largeDataSet.html)', template: 'looping/largeDataSet', - test: (teddy, template, model) => { + run: async (teddy, template, model, assert, expected) => { const start = new Date().getTime() teddy.render(template, model) const end = new Date().getTime() @@ -800,84 +742,79 @@ export default [ { message: 'should ignore loop with invalid through attribute (looping/undefinedObjectLoop.html)', template: 'looping/undefinedObjectLoop', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '
' }, { message: 'should ignore loop with no contents (looping/emptyMarkupLoop.html)', template: 'looping/emptyMarkupLoop', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '
' }, { message: 'should loop without nested markup (looping/noMarkupLoop.html)', template: 'looping/noMarkupLoop', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '
abc
' }, { message: 'should loop through {letters} correctly with numeric val (looping/numericalVal.html)', template: 'looping/numericalVal', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

a

b

c

' }, { message: 'should loop through {letters} correctly with camelCase val (looping/camelCaseLoopVal.html)', template: 'looping/camelCaseLoopVal', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

a

b

c

' }, { message: 'should loop through {letters} keys correctly with no val attribute (looping/loopNoVal.html)', template: 'looping/loopNoVal', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

0

1

2

' }, { message: 'should ignore loops with missing attributes (looping/loopInvalidAttributes.html)', template: 'looping/loopInvalidAttributes', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '
' }, { message: 'should ignore undefined members of objects and arrays (looping/loopUndefinedMember.html)', template: 'looping/loopUndefinedMember', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

a

{letter}

c

{item.a}

{item.b}

{item.c}

4

5

6

7

8

9

' }, { message: 'should loop through {letters} correctly and evaluate other teddy tags (looping/loopIncludesIfUnless.html)', template: 'looping/loopIncludesIfUnless', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

a

Some content

Hello

b

Some content

Hello

c

Some content

Hello

' }, { message: 'should render deeply nested vars with teddy code (looping/nestedObjectWithTeddyContent.html)', template: 'looping/nestedObjectWithTeddyContent', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

1

Something Exists

2

Something Exists

' }, { message: 'should render deeply nested vars with teddy code and respect noparse flag (looping/nestedObjectWithTeddyContentNoParse.html)', template: 'looping/nestedObjectWithTeddyContentNoParse', - playwright: async (params, page, expect) => { - await page.setContent('' + params.teddy.render(params.template, params.model) + '') - - await expect(page.locator('html')).toContainText('1 Something Exists 2 Something Exists') - }, - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

1

Something Exists

2

Something Exists

' }, { message: 'should not crash if attempting to set a val that matches the name of something else in the model (looping/loopValNameCollision.html)', template: 'looping/loopValNameCollision', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

2

5

8

' }, { message: 'should print an empty string for array member set to an empty string (looping/loopValEmptyString.html)', template: 'looping/loopValEmptyString', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

one

two

three

' } ] @@ -888,7 +825,7 @@ export default [ { message: 'should compile a template and return a function which when given data will render HTML', template: '

{hello}

', - test: (teddy, template, _model) => { + run: async (teddy, template, model, assert, expected) => { const templateFunction = teddy.compile(template) return templateFunction({ hello: 'world' }) }, @@ -897,31 +834,31 @@ export default [ { message: 'should not escape HTML entities present in {variables} which are properly {flagged|p|s} (misc/barPandSTest.html)', template: 'misc/barPandSTest', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

double bars

{something}' }, { message: 'should not escape HTML entities present in {variables} which are properly {flagged|s|p} (misc/barSandPTest.html)', template: 'misc/barSandPTest', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

double bars

{something}' }, { message: 'should render multiple {variables} (misc/multipleVariables.html)', template: 'misc/multipleVariables', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Some content

More content
' }, { message: 'should render {variables} (misc/variable.html)', template: 'misc/variable', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Some content

' }, { message: 'should render {variables} as blank when x is true (misc/undefinedVar.html)', template: 'misc/undefinedVar', - test: (teddy, template, model) => { + run: async (teddy, template, model, assert, expected) => { teddy.setEmptyVarBehavior('hide') const result = teddy.render(template, model) teddy.setEmptyVarBehavior('display') @@ -932,68 +869,67 @@ export default [ { message: 'should render template literal ${variables} (misc/variableTemplateLiteral.html)', // eslint-disable-line template: 'misc/variableTemplateLiteral', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Some content

' }, { message: 'should render nested {variables} (misc/nestedVars.html)', template: 'misc/nestedVars', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Variable with a variable inside: And another: Some content

' }, { message: 'should not render nested {variables|p} (misc/nestedVarsParseFlag.html)', template: 'misc/nestedVarsParseFlag', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Variable with a variable inside: {subVar}

' }, { message: 'should properly escape HTML entities present in {variables} (misc/varEscaping.html)', template: 'misc/varEscaping', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

<span>raw html</span>

' }, { message: 'should not escape HTML entities present in {variables} which are properly {flagged|s} (misc/varNoEscaping.html)', template: 'misc/varNoEscaping', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '
raw html
' }, { message: 'should not parse any code in tags (misc/varNoParsing.html)', template: 'misc/varNoParsing', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

{escapeTest}

' }, { message: 'should remove {! server side comments !} (misc/serverSideComments.html)', template: 'misc/serverSideComments', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

test test

' }, { message: 'should remove {! server side comments !} in an inline template', template: 'misc/serverSideComments', - test: (teddy, template, model) => teddy.render('{! comments !}

Should remove {! the !} comments.

', model), + run: async (teddy, template, model, assert, expected) => teddy.render('{! comments !}

Should remove {! the !} comments.

', model), expected: '

Should remove comments.

' }, { message: 'should remove {! {! nested !} server side comments !} (misc/serverSideCommentsNested.html)', template: 'misc/serverSideCommentsNested', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

Any comments?

' }, { message: 'should not break when referencing objects that don\'t exist (misc/objectDoesNotExist.html)', template: 'misc/objectDoesNotExist', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

{doesntExist.someKey}

' }, { message: 'should render plain HTML with no teddy tags with no changes (misc/plainHTML.html)', template: 'misc/plainHTML', - type: 'custom', - test: (teddy, template, model, assert) => { + run: async (teddy, template, model, assert, expected) => { const teddyTemplate = teddy.render(template, model) assert(teddyTemplate, 'Plain HTML

This template contains no teddy tags. Just HTML.

') @@ -1003,32 +939,35 @@ export default [ { message: 'should render {variables} within style element (misc/styleVariables.html)', template: 'misc/styleVariables', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '' }, { message: 'should access property of {variable} object with {variable} (misc/variableObjectProperty.html)', template: 'misc/variableObjectProperty', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

guy

' }, { message: 'should escape curly braces from regex pattern (misc/regexEscaping.html)', template: 'misc/regexEscaping', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '' }, { message: 'should render emojis correctly (misc/emojis.html)', template: 'misc/emojis', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

🎉🥳🎈🎊

' }, { message: 'should cache the contents of the cache element but not anything outside of it (misc/cacheElement.html)', template: 'misc/cacheElement', - type: 'async', - test: async (teddy, template, _model, assert) => { + run: async (teddy, template, model, assert, expected) => { + function timeout (ms) { + return new Promise(resolve => setTimeout(resolve, ms)) + } + // these will be cached const render1 = teddy.render(template, { user: 'Joe', city: 'NY', value: 30 }) assert(render1, '

Dynamic: Welcome Joe!

Cached: High temperature today in NY is 30.

') @@ -1083,8 +1022,11 @@ export default [ { message: 'should cache the contents of the cache element but not anything outside of it (misc/cacheElementMaxAge.html)', template: 'misc/cacheElementMaxAge', - type: 'async', - test: async (teddy, template, _model, assert) => { + run: async (teddy, template, model, assert, expected) => { + function timeout (ms) { + return new Promise(resolve => setTimeout(resolve, ms)) + } + // these will be cached const render1 = teddy.render(template, { user: 'Joe', city: 'NY', value: 30 }) assert(render1, '

Dynamic: Welcome Joe!

Cached: High temperature today in NY is 30.

') @@ -1107,8 +1049,11 @@ export default [ { message: 'should render cache element correctly with dynamic attributes (misc/cacheElementDynamicAttrs.html)', template: 'misc/cacheElementDynamicAttrs', - type: 'async', - test: async (teddy, template, model, assert) => { + run: async (teddy, template, model, assert, expected) => { + function timeout (ms) { + return new Promise(resolve => setTimeout(resolve, ms)) + } + teddy.clearCache('weather') // these will be cached @@ -1165,8 +1110,11 @@ export default [ { message: 'should render cache element correctly with dynamic attributes (misc/cacheElementDynamicAttrsNested.html)', template: 'misc/cacheElementDynamicAttrsNested', - type: 'async', - test: async (teddy, template, model, assert) => { + run: async (teddy, template, model, assert, expected) => { + function timeout (ms) { + return new Promise(resolve => setTimeout(resolve, ms)) + } + teddy.clearCache('weather') // these will be cached @@ -1223,8 +1171,11 @@ export default [ { message: 'should render template, then render cached template, then render the template again when the cache expires (misc/cacheWholeTemplate.html)', template: 'misc/cacheWholeTemplate', - type: 'async', - test: async (teddy, template, model, assert) => { + run: async (teddy, template, model, assert, expected) => { + function timeout (ms) { + return new Promise(resolve => setTimeout(resolve, ms)) + } + teddy.setCache({ template, key: null, @@ -1256,8 +1207,7 @@ export default [ { message: 'should render template, then render cached template, then render the template again when the cache is explicitly cleared (misc/cacheWholeTemplate.html)', template: 'misc/cacheWholeTemplate', - type: 'async', - test: async (teddy, template, model, assert) => { + run: async (teddy, template, model, assert, expected) => { teddy.setCache({ template, key: null, @@ -1292,8 +1242,11 @@ export default [ { message: 'should render template, then render cached template, then render the template again when the cache expires via keyed values (misc/cacheWholeTemplate.html)', template: 'misc/cacheWholeTemplate', - type: 'async', - test: async (teddy, template, model, assert) => { + run: async (teddy, template, model, assert, expected) => { + function timeout (ms) { + return new Promise(resolve => setTimeout(resolve, ms)) + } + const modelNY = Object.assign({ city: 'NY' }, model) const modelSF = Object.assign({ city: 'SF' }, model) teddy.setCache({ @@ -1333,8 +1286,7 @@ export default [ { message: 'should render template, then render cached template, then render the template again when the cache expires via keyed values when the cache is explicitly cleared (misc/cacheWholeTemplate.html)', template: 'misc/cacheWholeTemplate', - type: 'async', - test: async (teddy, template, model, assert) => { + run: async (teddy, template, model, assert, expected) => { const modelNY = Object.assign({ city: 'NY' }, model) const modelSF = Object.assign({ city: 'SF' }, model) teddy.setCache({ @@ -1377,8 +1329,11 @@ export default [ { message: 'should render template, then render cached template, then render the template again when the cache expires via keyed values with nesting (misc/cacheWholeTemplate.html)', template: 'misc/cacheWholeTemplate', - type: 'async', - test: async (teddy, template, model, assert) => { + run: async (teddy, template, model, assert, expected) => { + function timeout (ms) { + return new Promise(resolve => setTimeout(resolve, ms)) + } + const modelNY = Object.assign({ city: { acronym: 'NY' } }, model) const modelSF = Object.assign({ city: { acronym: 'SF' } }, model) teddy.setCache({ @@ -1418,8 +1373,7 @@ export default [ { message: 'should render template, then render cached template, then render the template again when the cache expires via keyed values with nesting when the cache is explicitly cleared (misc/cacheWholeTemplate.html)', template: 'misc/cacheWholeTemplate', - type: 'async', - test: async (teddy, template, model, assert) => { + run: async (teddy, template, model, assert, expected) => { const modelNY = Object.assign({ city: { acronym: 'NY' } }, model) const modelSF = Object.assign({ city: { acronym: 'SF' } }, model) teddy.setCache({ @@ -1462,8 +1416,11 @@ export default [ { message: 'should drop caches which have expired due to maximum being reached (misc/cacheWholeTemplate.html)', template: 'misc/cacheWholeTemplate', - type: 'async', - test: async (teddy, template, model, assert) => { + run: async (teddy, template, model, assert, expected) => { + function timeout (ms) { + return new Promise(resolve => setTimeout(resolve, ms)) + } + const modelNY = Object.assign({ city: { acronym: 'NY' } }, model) const modelSF = Object.assign({ city: { acronym: 'SF' } }, model) const modelLA = Object.assign({ city: { acronym: 'LA' } }, model) @@ -1508,26 +1465,25 @@ export default [ { message: 'should avoid rendering templates that are not strings', template: 5, - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '' }, { message: 'should render a template with missing or invalid model (misc/emptyModelMarkup.html)', template: 'misc/emptyModelMarkup', - test: (teddy, template, _model) => teddy.render(template, 1), + run: async (teddy, template, model, assert, expected) => teddy.render(template, 1), expected: '

Hello

' }, { message: 'should not render {variables} that don\'t exist in the model (misc/varNotInModel.html)', template: 'misc/varNotInModel', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '{noExist}' }, { message: 'should set each verbosity level', template: '', - type: 'custom', - test: (teddy, _template, _model, assert) => { + run: async (teddy, template, model, assert, expected) => { let verbosity = '' teddy.setVerbosity() verbosity += teddy.params.verbosity + ', ' @@ -1561,13 +1517,13 @@ export default [ { message: 'should render undefined variables as text (misc/undefinedVar.html)', template: 'misc/undefinedVar', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

{undefinedVar}

{definedParent.undefinedMember}

' }, { message: 'should prevent infinitely referencing variables (misc/varRefVar.html)', template: 'misc/varRefVar', - test: (teddy, template, model) => { + run: async (teddy, template, model, assert, expected) => { teddy.setVerbosity(0) return teddy.render(template, model) }, @@ -1576,43 +1532,43 @@ export default [ { message: 'should render empty strings as is for variables that are empty strings (misc/emptyStringVariable.html)', template: 'misc/emptyStringVariable', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

' }, { message: 'should render template with extraneous whitespace properly (misc/extraneousWhitespace.html)', template: 'misc/extraneousWhitespace', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

a

Something exists

b

Something exists

c

Something exists

' }, { message: 'should render {variables} that resolve to true or false boolean literals as strings (misc/printBooleanLiteral.html)', template: 'misc/printBooleanLiteral', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

true

{somethingFalse}

' }, { message: 'should render {zero} as 0 (misc/zero.html)', template: 'misc/zero', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

0

' }, { message: 'should not render Teddy code in server-side comments in loops (misc/serverSideCommentsWithTeddyCode.html)', template: 'misc/serverSideCommentsWithTeddyCode', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

test

test

test

test

test

test

' }, { message: 'should parse embedded script tag correctly (misc/scriptWithEmptyObject.html)', template: 'misc/scriptWithEmptyObject', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '' }, { message: 'should parse a script tag with a JSON string correctly (misc/scriptWithJson.html)', template: 'misc/scriptWithJson', - test: (teddy, template, model) => { + run: async (teddy, template, model, assert, expected) => { teddy.setVerbosity(0) return teddy.render(template, model) }, @@ -1621,19 +1577,19 @@ export default [ { message: 'should render special characters correctly when piped through a teddy noparse flagged variable (misc/specialChars.html)', template: 'misc/specialChars', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

special .$&@. chars

' }, { message: 'should render empty strings as is for |p or |s variables that are empty strings (misc/emptyStringVariableFlags.html)', template: 'misc/emptyStringVariableFlags', - test: (teddy, template, model) => teddy.render(template, model), + run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), expected: '

' } // ,{ // message: '', // template: '', - // test: (teddy, template, model) => teddy.render(template, model), + // run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), // expected: '' // } ] @@ -1644,8 +1600,7 @@ export default [ tests: [ { message: 'should be able require teddy.cjs', - type: 'custom', - test: async (_params, _page, _model, assert) => { + runMocha: async (teddy, template, model, assert, expected) => { if (fs.existsSync('test/client.cjs')) fs.rmSync('test/client.cjs') fs.writeFileSync('test/client.cjs', 'const teddy = require("../dist/teddy.cjs")\nconsole.log(teddy)') @@ -1659,8 +1614,7 @@ export default [ }, { message: 'should be able to import teddy.mjs', - type: 'custom', - test: (_params, _page, _model, assert) => { + runMocha: async (teddy, template, model, assert, expected) => { if (fs.existsSync('test/client.js')) fs.rmSync('test/client.js') fs.writeFileSync('test/client.js', 'import teddy from "../dist/teddy.mjs"\nconsole.log(teddy)') diff --git a/webpack.config.js b/webpack.config.js index 76350e7..47b5a20 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -139,10 +139,13 @@ export default [ fallback: { fs: false, path: false - }, + } + /* + TODO: uncomment this when cheerioPolyfill is done alias: { 'cheerio/slim': path.resolve(__dirname, 'cheerioPolyfill.js') } + */ } }, @@ -185,10 +188,13 @@ export default [ fallback: { fs: false, path: false - }, + } + /* + TODO: uncomment this when cheerioPolyfill is done alias: { 'cheerio/slim': path.resolve(__dirname, 'cheerioPolyfill.js') } + */ } }, @@ -231,10 +237,13 @@ export default [ fallback: { fs: false, path: false - }, + } + /* + TODO: uncomment this when cheerioPolyfill is done alias: { 'cheerio/slim': path.resolve(__dirname, 'cheerioPolyfill.js') } + */ } }, @@ -280,10 +289,13 @@ export default [ fallback: { fs: false, path: false - }, + } + /* + TODO: uncomment this when cheerioPolyfill is done alias: { 'cheerio/slim': path.resolve(__dirname, 'cheerioPolyfill.js') } + */ } }, @@ -326,10 +338,13 @@ export default [ fallback: { fs: false, path: false - }, + } + /* + TODO: uncomment this when cheerioPolyfill is done alias: { 'cheerio/slim': path.resolve(__dirname, 'cheerioPolyfill.js') } + */ } }, @@ -372,10 +387,13 @@ export default [ fallback: { fs: false, path: false - }, + } + /* + TODO: uncomment this when cheerioPolyfill is done alias: { 'cheerio/slim': path.resolve(__dirname, 'cheerioPolyfill.js') } + */ } }