diff --git a/CHANGELOG.md b/CHANGELOG.md index bbc149b..bcfee4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,13 @@ ## Next version +- Put your changes here... + +## 0.6.14 + +- Finsihed work on `cheerioPolyfill.js` which makes it possible for Teddy to execute in client-side contexts without using `cheerio`, allowing for a very small bundle size for client-side Teddy (17kb minified). - 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 0fbe9ee..dc0b469 100644 --- a/cheerioPolyfill.js +++ b/cheerioPolyfill.js @@ -1,29 +1,10 @@ -// extend HTMLElement prototype to include cheerio properties -Object.defineProperty(window.HTMLElement.prototype, 'name', { - get: function () { - if (this.__name === undefined) this.__name = this.nodeName.toLowerCase() - return this.__name - } -}) - -Object.defineProperty(window.HTMLElement.prototype, 'parent', { - get: function () { - if (this.__parent === undefined) this.__parent = this.parentNode - return this.__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() // stub out cheerio using native dom methods for frontend so we don't have to bundle cheerio on the frontend 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) + doc.body.innerHTML = doc.head.innerHTML + doc.body.innerHTML // return a querySelector function with function chains // e.g. dom('include') or dom(el) from teddy @@ -31,7 +12,6 @@ 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('cheerio polyfill: dom(query)', els) return els // return the object collection } @@ -41,46 +21,42 @@ export function load (html) { // e.g. dom(el).children() from teddy children: function () { - console.log('cheerio polyfill: children()', el.children) - return el.children + return el.childNodes }, // 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 + for (const el of html) { + if (el.nodeType === window.Node.COMMENT_NODE) newHtml += '' + else newHtml += el.outerHTML || el.textContent + } html = newHtml } const temp = document.createElement('div') temp.innerHTML = html - el.replaceWith(...temp.children) - console.log('replaceWith doc:', doc.body.innerHTML) + el.replaceWith(...temp.childNodes) }, // e.g. dom(el).remove() from teddy remove: function () { - console.log('cheerio polyfill: remove()', el) return el.remove() } } @@ -88,7 +64,6 @@ 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 fdef3f0..914e18d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "teddy", - "version": "0.6.13", + "version": "0.6.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "teddy", - "version": "0.6.13", + "version": "0.6.14", "license": "CC-BY-4.0", "dependencies": { "cheerio": "1.0.0" @@ -554,9 +554,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.7.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.6.tgz", - "integrity": "sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw==", + "version": "22.7.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.7.tgz", + "integrity": "sha512-SRxCrrg9CL/y54aiMCG3edPKdprgMVGDXjA3gB8UmmBW5TcXzRUYAh8EWzTnSJFAd1rgImPELza+A3bJ+qxz8Q==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 82730ed..d63d393 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "url": "https://github.com/rooseveltframework/teddy/graphs/contributors" } ], - "version": "0.6.13", + "version": "0.6.14", "files": [ "dist" ], diff --git a/teddy.js b/teddy.js index bd5ae1c..7861328 100644 --- a/teddy.js +++ b/teddy.js @@ -108,7 +108,7 @@ function replaceCacheElements (dom, model) { const now = Date.now() // if max age is not set, then there is no max age and the cache content is still valid // or if last accessed + max age > now then the cache is not stale and the cache is still valid - if (!cache.maxAge || cache.entries[keyVal].lastAccessed + cache.maxAge > now) { + if (!(cache.maxAge && !cache.maxage) || cache.entries[keyVal].lastAccessed + (cache.maxAge || cache.maxage) > now) { const cacheContent = cache.entries[keyVal].markup cache.entries[keyVal].lastAccessed = now dom(el).replaceWith(cacheContent) @@ -160,16 +160,16 @@ function parseIncludes (dom, model, dynamic) { // ensure this isn't the child of a no parse block let foundBody = false let next = false - let parent = el.parent + let parent = el.parent || el.parentNode while (!foundBody) { let parentName if (!parent) parentName = 'body' - else parentName = parent.name + else parentName = parent.name || parent.nodeName?.toLowerCase() if (parentName === 'noparse' || parentName === 'noteddy') { next = true break } else if (parentName === 'body') foundBody = true - else parent = parent.parent + else parent = parent.parent || parent.parentNode } if (next) continue // get attributes @@ -187,6 +187,7 @@ function parseIncludes (dom, model, dynamic) { const contents = templates[src] const localModel = Object.assign({}, model) for (const arg of dom(el).children()) { + if (browser) arg.name = arg.nodeName?.toLowerCase() if (arg.name === 'arg') { if (browser) arg.attribs = getAttribs(arg) const argval = Object.keys(arg.attribs)[0] @@ -217,16 +218,16 @@ function parseConditionals (dom, model) { // ensure this isn't the child of a loop or a no parse block let foundBody = false let next = false - let parent = el.parent + let parent = el.parent || el.parentNode while (!foundBody) { let parentName if (!parent) parentName = 'body' - else parentName = parent.name + else parentName = parent.name || parent.nodeName?.toLowerCase() if (parentName === 'loop' || parentName === 'noparse' || parentName === 'noteddy') { next = true break } else if (parentName === 'body') foundBody = true - else parent = parent.parent + else parent = parent.parent || parent.parentNode } if (next) continue // get conditions @@ -239,6 +240,7 @@ function parseConditionals (dom, model) { } // check if it's an if tag and not an unless tag let isIf = true + if (browser) el.name = el.nodeName?.toLowerCase() if (el.name === 'unless') isIf = false // evaluate conditional const condResult = evaluateConditional(args, model) @@ -247,6 +249,7 @@ function parseConditionals (dom, model) { let nextSibling = el.nextSibling const removeStack = [] while (nextSibling) { + if (browser) nextSibling.name = nextSibling.nodeName?.toLowerCase() switch (nextSibling.name) { case 'elseif': case 'elseunless': @@ -263,12 +266,13 @@ function parseConditionals (dom, model) { } } for (const element of removeStack) dom(element).replaceWith('') - dom(el).replaceWith(el.children) + dom(el).replaceWith(el.childNodes || el.children) parsedTags++ } else { // true block is false; find the next elseif, elseunless, or else tag to evaluate let nextSibling = el.nextSibling while (nextSibling) { + if (browser) nextSibling.name = nextSibling.nodeName?.toLowerCase() switch (nextSibling.name) { case 'elseif': // get conditions @@ -282,10 +286,11 @@ function parseConditionals (dom, model) { if (evaluateConditional(args, model)) { // render the true block and discard the elseif, elseunless, and else blocks const replaceSibling = nextSibling - dom(replaceSibling).replaceWith(replaceSibling.children) + dom(replaceSibling).replaceWith(replaceSibling.childNodes || replaceSibling.children) nextSibling = el.nextSibling const removeStack = [] while (nextSibling) { + if (browser) nextSibling.name = nextSibling.nodeName?.toLowerCase() switch (nextSibling.name) { case 'elseif': case 'elseunless': @@ -323,10 +328,11 @@ function parseConditionals (dom, model) { if (!evaluateConditional(args, model)) { // render the true block and discard the elseif, elseunless, and else blocks const replaceSibling = nextSibling - dom(replaceSibling).replaceWith(replaceSibling.children) + dom(replaceSibling).replaceWith(replaceSibling.childNodes || replaceSibling.children) nextSibling = el.nextSibling const removeStack = [] while (nextSibling) { + if (browser) nextSibling.name = nextSibling.nodeName?.toLowerCase() switch (nextSibling.name) { case 'elseif': case 'elseunless': @@ -354,7 +360,7 @@ function parseConditionals (dom, model) { break case 'else': // else is always true, so if we've gotten here, then there's nothing to evaluate and we've reached the end of the conditional blocks - dom(nextSibling).replaceWith(nextSibling.children) + dom(nextSibling).replaceWith(nextSibling.childNodes || nextSibling.children) nextSibling = false parsedTags++ break @@ -482,16 +488,16 @@ function parseOneLineConditionals (dom, model) { // ensure this isn't the child of a loop or a no parse block let foundBody = false let next = false - let parent = el.parent + let parent = el.parent || el.parentNode while (!foundBody) { let parentName if (!parent) parentName = 'body' - else parentName = parent.name + else parentName = parent.name || parent.nodeName?.toLowerCase() if (parentName === 'loop' || parentName === 'noparse' || parentName === 'noteddy') { next = true break } else if (parentName === 'body') foundBody = true - else parent = parent.parent + else parent = parent.parent || parent.parentNode } if (next) continue // get conditions @@ -673,8 +679,8 @@ function defineNewCaches (dom, model) { if (browser) el.attribs = getAttribs(el) const name = el.attribs.name const key = el.attribs.key || 'none' - const maxAge = parseInt(el.attribs.maxAge) || 0 - const maxCaches = parseInt(el.attribs.maxCaches) || 1000 + const maxAge = parseInt(el.attribs.maxAge || el.attribs.maxage) || 0 + const maxCaches = parseInt(el.attribs.maxCaches || el.attribs.maxcaches) || 1000 const timestamp = Date.now() const markup = dom(el).html() if (!caches[name]) { @@ -711,6 +717,7 @@ function cleanupStrayTeddyTags (dom) { const tags = dom('[teddy_deferred_one_line_conditional], include, arg, if, unless, elseif, elseunless, else, loop, cache') if (tags.length > 0) { for (const el of tags) { + if (browser) el.name = el.nodeName?.toLowerCase() 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() } @@ -832,10 +839,7 @@ function getOrSetObjectByDotNotation (obj, dotNotation, value) { } } -// #endregion - -// #region cheerio polyfills - +// cheerio polyfill function getAttribs (element) { const attributes = element.attributes const attributesObject = {} @@ -918,13 +922,13 @@ function setCache (params) { if (!templateCaches[params.template]) templateCaches[params.template] = {} if (params.key) { templateCaches[params.template][params.key] = { - maxAge: params.maxAge, - maxCaches: params.maxCaches || 1000, + maxAge: params.maxAge || params.maxage, + maxCaches: (params.maxCaches || params.maxcaches) || 1000, entries: {} } } else { templateCaches[params.template].none = { - maxAge: params.maxAge, + maxAge: params.maxAge || params.maxage, markup: null, created: null } @@ -981,11 +985,11 @@ function render (template, model, callback) { if (singletonCache) { // check if the timestamp exceeds max age if (!singletonCache.created) cacheKey = 'none' - else if (!singletonCache.maxAge) { + else if (!singletonCache.maxAge && singletonCache.maxage) { // if no max age is set, then this cache doesn't expire if (typeof callback === 'function') return callback(null, singletonCache.markup) else return singletonCache.markup - } else if (singletonCache.created + singletonCache.maxAge < Date.now()) cacheKey = 'none' // if yes re-render the template and cache it again + } else if (singletonCache.created + (singletonCache.maxAge || singletonCache.maxage) < Date.now()) cacheKey = 'none' // if yes re-render the template and cache it again else { // if no return the cached markup and skip the template render if (typeof callback === 'function') return callback(null, singletonCache.markup) @@ -1004,11 +1008,11 @@ function render (template, model, callback) { if (entryKey === cacheKeyModelVal) { // check if the timestamp exceeds max age const entry = templateCacheAtThisKey.entries[entryKey] - if (!templateCacheAtThisKey.maxAge) { + if (!templateCacheAtThisKey.maxAge && !templateCacheAtThisKey.maxage) { // if no max age is set, then this cache doesn't expire if (typeof callback === 'function') return callback(null, entry.markup) else return entry.markup - } else if (entry.created + templateCacheAtThisKey.maxAge < Date.now()) { + } else if (entry.created + (templateCacheAtThisKey.maxAge || templateCacheAtThisKey.maxage) < Date.now()) { // if yes re-render the template and cache it again cacheKey = key break diff --git a/test/loaders/mocha.js b/test/loaders/mocha.js index df275fa..bb8aa7b 100644 --- a/test/loaders/mocha.js +++ b/test/loaders/mocha.js @@ -13,7 +13,7 @@ for (const testGroup of testsToRun) { before(() => { teddy.setTemplateRoot('test/templates') model = makeModel() - if (process.env.NODE_ENV === 'test') teddy.setVerbosity(0) + if (process.env.NODE_ENV === 'test' || process.env.NODE_ENV === 'cover') teddy.setVerbosity(0) }) for (const test of testGroup.tests) { @@ -26,8 +26,16 @@ for (const testGroup of testsToRun) { } function teddyAssert (result, expected = true) { + result = ignoreSpaces(result) if (typeof expected === 'string') expected = ignoreSpaces(expected) - assert.equal(ignoreSpaces(result), expected) + if (Array.isArray(expected)) { + let match = false + for (let acceptable of expected) { + acceptable = ignoreSpaces(acceptable) + if (result === acceptable) match = true + } + assert.equal(match, true) + } else assert.equal(result, expected) } function ignoreSpaces (str) { diff --git a/test/loaders/playwright.js b/test/loaders/playwright.js index 6082ef3..3035f43 100644 --- a/test/loaders/playwright.js +++ b/test/loaders/playwright.js @@ -8,7 +8,6 @@ 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 @@ -40,65 +39,77 @@ function registerTemplates (dir) { } 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 runPlaywrightAgainstTeddyBundle (teddyPath) { + const fileName = teddyPath.split('/').pop() + for (const testGroup of testsToRun) { + playwrightTest.describe(`${testGroup.describe} (dist/${fileName})`, () => { + 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} (dist/${fileName})`, 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: test.bundle || 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') + + // 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) { + result = ignoreSpaces(result) + if (typeof expected === 'string') expected = ignoreSpaces(expected) + if (Array.isArray(expected)) { + let match = false + for (let acceptable of expected) { + acceptable = ignoreSpaces(acceptable) + if (result === acceptable) match = true + } + if (!match) throw new Error(`Assertion failed: expected ${expected}, got ${ignoreSpaces(result)}`) + } else if (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 }) - }) + function ignoreSpaces (str) { + if (typeof str !== 'string') return str + return str.replace(/\s/g, '') + } + }, { test, templates, model }) + }) + } } - } - }) + }) + } } + +runPlaywrightAgainstTeddyBundle(path.resolve(__dirname, '../../dist/teddy.js')) +// runPlaywrightAgainstTeddyBundle(path.resolve(__dirname, '../../dist/teddy.min.js')) // uncomment to test the minified bundle too diff --git a/test/templates/conditionals/commentConditional.html b/test/templates/conditionals/commentConditional.html index 60f615c..18ad24d 100644 --- a/test/templates/conditionals/commentConditional.html +++ b/test/templates/conditionals/commentConditional.html @@ -1,14 +1,17 @@ {! should evaluate entire conditional and correctly show HTML comments !} - -

The variable 'doesntexist' is not present

-
- - -

The variable 'something' is present

-
- - -

The variable 'doesntexist' is present

-
+ +
+ +

The variable 'doesntexist' is not present

+
+ + +

The variable 'something' is present

+
+ + +

The variable 'doesntexist' is present

+
+
diff --git a/test/templates/conditionals/conditionalValueVarsLooped.html b/test/templates/conditionals/conditionalValueVarsLooped.html index 34c99f4..57b0109 100644 --- a/test/templates/conditionals/conditionalValueVarsLooped.html +++ b/test/templates/conditionals/conditionalValueVarsLooped.html @@ -4,7 +4,7 @@ - + diff --git a/test/templates/conditionals/ifCommentElse.html b/test/templates/conditionals/ifCommentElse.html index d2182de..26412ba 100644 --- a/test/templates/conditionals/ifCommentElse.html +++ b/test/templates/conditionals/ifCommentElse.html @@ -1,11 +1,14 @@ {! should evaluate as false and trigger condition with preceding HTML comment !} - -

The variable 'doesntexist' is present

-
- - -

The variable 'doesntexist' is not present

-
+
+ +

The variable 'doesntexist' is present

+
+ + + +

The variable 'doesntexist' is not present

+
+
diff --git a/test/templates/conditionals/ifCommentsEmbedded.html b/test/templates/conditionals/ifCommentsEmbedded.html index e0fcaba..0a659d3 100644 --- a/test/templates/conditionals/ifCommentsEmbedded.html +++ b/test/templates/conditionals/ifCommentsEmbedded.html @@ -2,12 +2,14 @@ should evaluate as false and trigger condition with embedded HTML comments in conditional statements !} - -

The variable 'doesntexist' is present

-
+
+ +

The variable 'doesntexist' is present

+
- - - -

The variable 'doesntexist' is not present

-
+ + + +

The variable 'doesntexist' is not present

+
+
diff --git a/test/templates/conditionals/ifMultipleCommentsElse.html b/test/templates/conditionals/ifMultipleCommentsElse.html index 303f8a3..162f055 100644 --- a/test/templates/conditionals/ifMultipleCommentsElse.html +++ b/test/templates/conditionals/ifMultipleCommentsElse.html @@ -2,12 +2,14 @@ should evaluate as false and trigger condition with multiple preceding HTML comments !} - -

The variable 'doesntexist' is present

-
+
+ +

The variable 'doesntexist' is present

+
- - - -

The variable 'doesntexist' is not present

-
+ + + +

The variable 'doesntexist' is not present

+
+
diff --git a/test/templates/conditionals/oneLineValueVarsLooped.html b/test/templates/conditionals/oneLineValueVarsLooped.html index 22d4c4c..d54beeb 100644 --- a/test/templates/conditionals/oneLineValueVarsLooped.html +++ b/test/templates/conditionals/oneLineValueVarsLooped.html @@ -3,5 +3,5 @@ !} - + diff --git a/test/templates/conditionals/oneLineValueWithAdditionalAttributesNotImpactedByIf.html b/test/templates/conditionals/oneLineValueWithAdditionalAttributesNotImpactedByIf.html index 01ca8f5..d237b1a 100644 --- a/test/templates/conditionals/oneLineValueWithAdditionalAttributesNotImpactedByIf.html +++ b/test/templates/conditionals/oneLineValueWithAdditionalAttributesNotImpactedByIf.html @@ -4,6 +4,6 @@

One line if.

One line if.

-

One line if.

- - +

One line if.

+ + diff --git a/test/templates/looping/nestedObjectLoopLookup.html b/test/templates/looping/nestedObjectLoopLookup.html index 7430fac..d5605a0 100644 --- a/test/templates/looping/nestedObjectLoopLookup.html +++ b/test/templates/looping/nestedObjectLoopLookup.html @@ -4,5 +4,5 @@

{child.num}

- +
diff --git a/test/tests.js b/test/tests.js index 1273283..00db69f 100644 --- a/test/tests.js +++ b/test/tests.js @@ -5,6 +5,7 @@ import fs from 'fs' // 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` +// if multiple results are acceptable, make `expected` an array of strings rather than a string export default [ { @@ -104,7 +105,7 @@ export default [ message: 'should evaluate entire conditional and correctly show HTML comments (conditionals/commentConditional.html)', template: 'conditionals/commentConditional', run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), - expected: '

The variable \'something\' is present

' + expected: '

The variable \'something\' is present

' }, { message: 'should evaluate as false and as true (conditionals/ifElseIf.html)', @@ -260,19 +261,19 @@ export default [ message: 'should evaluate ' + expected: ['', ''] }, { message: 'should evaluate ' + expected: ['', ''] }, { 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', run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), - expected: '

One line if.

One line if.

One line if.

' + expected: ['

One line if.

One line if.

One line if.

', '

One line if.

One line if.

One line if.

'] }, { message: 'should evaluate one line if "if-something=\'\'" as false (conditionals/oneLineEmpty.html)', @@ -417,19 +418,19 @@ export default [ message: 'should evaluate as false and trigger condition with preceding HTML comment (conditionals/ifCommentElse.html)', template: 'conditionals/ifCommentElse', run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), - expected: '

The variable \'doesntexist\' is not present

' + 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', run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), - expected: '

The variable \'doesntexist\' is not present

' + 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', run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), - expected: '

The variable \'doesntexist\' is not present

' + expected: '

The variable \'doesntexist\' is not present

' }, { message: 'should evaluate the condition as true and not render the other conditions (conditionals/ifWithSiblingIfWithNestedIfElse.html)', @@ -646,7 +647,7 @@ export default [ message: 'should parse loop through nested object correctly (looping/nestedObjectLoopLookup.html)', template: 'looping/nestedObjectLoopLookup', run: async (teddy, template, model, assert, expected) => assert(teddy.render(template, model), expected), - expected: '

1

2

3

' + expected: ['

1

2

3

', '

1

2

3

'] }, { message: 'should parse nested loops correctly (looping/nestedLoopsObjectWithArrayOfObjects.html)', @@ -929,7 +930,7 @@ export default [ { message: 'should render plain HTML with no teddy tags with no changes (misc/plainHTML.html)', template: 'misc/plainHTML', - run: async (teddy, template, model, assert, expected) => { + runMocha: async (teddy, template, model, assert, expected) => { const teddyTemplate = teddy.render(template, model) assert(teddyTemplate, 'Plain HTML

This template contains no teddy tags. Just HTML.

') @@ -1626,7 +1627,6 @@ export default [ }, expected: '' } - // TODO: write bundler tests for client-side files that are exclusive to the playwright environent where the window variable is present ] } ] diff --git a/webpack.config.js b/webpack.config.js index 47b5a20..76350e7 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -139,13 +139,10 @@ export default [ fallback: { fs: false, path: false - } - /* - TODO: uncomment this when cheerioPolyfill is done + }, alias: { 'cheerio/slim': path.resolve(__dirname, 'cheerioPolyfill.js') } - */ } }, @@ -188,13 +185,10 @@ export default [ fallback: { fs: false, path: false - } - /* - TODO: uncomment this when cheerioPolyfill is done + }, alias: { 'cheerio/slim': path.resolve(__dirname, 'cheerioPolyfill.js') } - */ } }, @@ -237,13 +231,10 @@ export default [ fallback: { fs: false, path: false - } - /* - TODO: uncomment this when cheerioPolyfill is done + }, alias: { 'cheerio/slim': path.resolve(__dirname, 'cheerioPolyfill.js') } - */ } }, @@ -289,13 +280,10 @@ export default [ fallback: { fs: false, path: false - } - /* - TODO: uncomment this when cheerioPolyfill is done + }, alias: { 'cheerio/slim': path.resolve(__dirname, 'cheerioPolyfill.js') } - */ } }, @@ -338,13 +326,10 @@ export default [ fallback: { fs: false, path: false - } - /* - TODO: uncomment this when cheerioPolyfill is done + }, alias: { 'cheerio/slim': path.resolve(__dirname, 'cheerioPolyfill.js') } - */ } }, @@ -387,13 +372,10 @@ export default [ fallback: { fs: false, path: false - } - /* - TODO: uncomment this when cheerioPolyfill is done + }, alias: { 'cheerio/slim': path.resolve(__dirname, 'cheerioPolyfill.js') } - */ } }