diff --git a/packages/chai-dom-equals/README.md b/packages/chai-dom-equals/README.md index 59859cb7..700cf764 100644 --- a/packages/chai-dom-equals/README.md +++ b/packages/chai-dom-equals/README.md @@ -53,7 +53,7 @@ it('has the following shadow dom', async () => { ``` ## Literal matching -By default dom is diffed 'semantically'. Differences in whitespace, newlines, attributes/class order are ignored and style, script and commend nodes are removed. +By default dom is diffed 'semantically'. Differences in whitespace, newlines, attributes/class order are ignored and style, script and comment nodes are removed. If you want to match literally instead you can use some of the provided utilities to handle diffing on browsers with the shadow dom polyfill: diff --git a/packages/chai-dom-equals/chai-dom-equals.js b/packages/chai-dom-equals/chai-dom-equals.js index bcec5d07..2b217658 100644 --- a/packages/chai-dom-equals/chai-dom-equals.js +++ b/packages/chai-dom-equals/chai-dom-equals.js @@ -68,9 +68,11 @@ export const chaiDomEquals = (chai, utils) => { try { new chai.Assertion(actualHTML).to.equal(expectedHTML); } catch (error) { + /* eslint-disable no-console */ console.log('Snapshot changed, want to accept the change:'); console.log(''); console.log(actualHTML); + /* eslint-enable no-console */ throw error; } @@ -82,9 +84,11 @@ export const chaiDomEquals = (chai, utils) => { try { new chai.Assertion(actualHTML).to.equal(expectedHTML); } catch (error) { + /* eslint-disable no-console */ console.log('Snapshot changed, want to accept the change:'); console.log(''); console.log(actualHTML); + /* eslint-enable no-console */ throw error; } diff --git a/packages/chai-dom-equals/test/bdd-setup.js b/packages/chai-dom-equals/test/bdd-setup.js index 8fe7883c..bfd71d8e 100644 --- a/packages/chai-dom-equals/test/bdd-setup.js +++ b/packages/chai-dom-equals/test/bdd-setup.js @@ -1,6 +1,6 @@ // do manual setup and not use testing to not have circle dependencies import { chai } from '@bundled-es-modules/chai'; -import { cachedWrappers } from '@open-wc/testing-helpers/fixture.js'; +import { cachedWrappers } from '@open-wc/testing-helpers/fixtureWrapper.js'; import { chaiDomEquals } from '../chai-dom-equals.js'; // register-cleanup diff --git a/packages/testing-helpers/README.md b/packages/testing-helpers/README.md index a1431ba4..3b203e1b 100644 --- a/packages/testing-helpers/README.md +++ b/packages/testing-helpers/README.md @@ -26,10 +26,10 @@ it('can instantiate an element', async () => { ## Test a custom element with properties ```js -import { html, litFixture } from '@open-wc/testing-helpers'; +import { html, fixture } from '@open-wc/testing-helpers'; it('can instantiate an element with properties', async () => { - const el = await litFixture(html``); + const el = await fixture(html``); expect(el.foo).to.equal('bar'); } ``` @@ -57,7 +57,7 @@ This is using a "workaround" which is not performant for rerenders. As this is usually not a problem for tests it's ok here but do NOT use it in production code. ```js -import { html, litFixture, defineCE, unsafeStatic } from '@open-wc/testing-helpers'; +import { html, fixture, defineCE, unsafeStatic } from '@open-wc/testing-helpers'; const tagName = defineCE(class extends MyMixin(HTMLElement) { constructor() { @@ -66,7 +66,7 @@ const tagName = defineCE(class extends MyMixin(HTMLElement) { } }); const tag = unsafeStatic(tagName); -const el = litFixture(html`<${tag} .bar=${'baz'}>`); +const el = fixture(html`<${tag} .bar=${'baz'}>`); expect(el.bar).to.equal('baz'); ``` @@ -74,9 +74,9 @@ expect(el.bar).to.equal('baz'); If you need to wait for multiple elements to update you can use `nextFrame`. ```js -import { nextFrame, aTimeout, html, litFixture } from '@open-wc/testing-helpers'; +import { nextFrame, aTimeout, html, fixture } from '@open-wc/testing-helpers'; -const el = await litFixture(html``); +const el = await fixture(html``); expect(el.foo).to.equal('bar'); el.foo = 'baz'; await nextFrame(); diff --git a/packages/testing-helpers/fixture.d.ts b/packages/testing-helpers/fixture.d.ts index d0fc4a29..593cbece 100644 --- a/packages/testing-helpers/fixture.d.ts +++ b/packages/testing-helpers/fixture.d.ts @@ -1,5 +1,4 @@ -type PropsFunction = (element: HTMLElement) => Object; -type FixtureProps = Object | PropsFunction; -export class FixtureWrapper extends HTMLElement { }; -export function fixtureSync(template: string, props?: FixtureProps): FixtureWrapper; -export async function fixture(template: string, setup?: FixtureProps): Promise; +import { TemplateResult } from 'lit-html'; + +export function fixtureSync(template: string | TemplateResult): Element; +export function fixture(template: string | TemplateResult): Promise; diff --git a/packages/testing-helpers/fixture.js b/packages/testing-helpers/fixture.js index 10e58bd1..3eb0cc93 100644 --- a/packages/testing-helpers/fixture.js +++ b/packages/testing-helpers/fixture.js @@ -1,54 +1,34 @@ +import { TemplateResult } from 'lit-html'; import { nextFrame } from './helpers.js'; - -export const cachedWrappers = []; - -/** - * Creates a wrapper as a direct child of `` to put the tested element into. - * Needed to run a `connectedCallback()` on a tested element. - * - * @returns {HTMLElement} - * @private - */ -export class FixtureWrapper { - constructor() { - const wrapper = document.createElement('div'); - document.body.appendChild(wrapper); - cachedWrappers.push(wrapper); - return wrapper; - } -} +import { stringFixtureSync } from './stringFixture.js'; +import { litFixtureSync } from './litFixture.js'; /** * Setups an element synchronously from the provided string template and puts it in the DOM. * Allows to specify properties via an object or a function taking the element as an argument. * - * @param {string} template - * @param {Object|function(element: HTMLElement)} props - * @returns {HTMLElement} + * @param {string | TemplateResult} template + * @returns {Element} */ -export function fixtureSync(template, props = {}) { - const parent = document.createElement('div'); // we need a real dom node for getters/setters - parent.innerHTML = template; - const element = parent.children[0]; - const properties = typeof props === 'function' ? props(element) : props; - Object.keys(properties).forEach(prop => { - element[prop] = properties[prop]; - }); - const wrapper = new FixtureWrapper(); - wrapper.appendChild(element); - return wrapper.children[0]; +export function fixtureSync(template) { + if (typeof template === 'string') { + return stringFixtureSync(template); + } + if (template instanceof TemplateResult) { + return litFixtureSync(template); + } + throw new Error('Invalid template provided - string or lit-html TemplateResult is supported'); } /** * Setups an element asynchronously from the provided string template and puts it in the DOM. * Allows to specify properties via an object or a function taking the element as an argument. * - * @param {string} template - * @param {Object|function(element: HTMLElement)} props - * @returns {Promise} + * @param {string | TemplateResult} template + * @returns {Promise} */ -export async function fixture(template, setup = {}) { - const result = fixtureSync(template, setup); +export async function fixture(template) { + const result = fixtureSync(template); await nextFrame(); return result; } diff --git a/packages/testing-helpers/fixtureWrapper.d.ts b/packages/testing-helpers/fixtureWrapper.d.ts new file mode 100644 index 00000000..2c333ed8 --- /dev/null +++ b/packages/testing-helpers/fixtureWrapper.d.ts @@ -0,0 +1,2 @@ +export const cachedWrappers: Array; +export function fixtureWrapper(): Element; diff --git a/packages/testing-helpers/fixtureWrapper.js b/packages/testing-helpers/fixtureWrapper.js new file mode 100644 index 00000000..336703f2 --- /dev/null +++ b/packages/testing-helpers/fixtureWrapper.js @@ -0,0 +1,16 @@ +/** @type Array */ +export const cachedWrappers = []; + +/** + * Creates a wrapper as a direct child of `` to put the tested element into. + * Needed to run a `connectedCallback()` on a tested element. + * + * @returns {Element} + * @private + */ +export function fixtureWrapper() { + const wrapper = document.createElement('div'); + document.body.appendChild(wrapper); + cachedWrappers.push(wrapper); + return wrapper; +} diff --git a/packages/testing-helpers/helpers.d.ts b/packages/testing-helpers/helpers.d.ts index 1609bd9e..98a9bdac 100644 --- a/packages/testing-helpers/helpers.d.ts +++ b/packages/testing-helpers/helpers.d.ts @@ -2,9 +2,9 @@ type Constructor = new (...args: any[]) => T; export function defineCE(klass: TBase): string; export function isIE(): boolean -export async function aTimeout(ms: int): void -export async function triggerBlurFor(element: HTMLElement): void -export async function triggerFocusFor(element: HTMLElement): void -export async function oneEvent(element: HTMLElement, eventName: string): Event -export async function nextFrame(): void -export async function flush(): void +export function aTimeout(ms: number): Promise +export function triggerBlurFor(element: HTMLElement): Promise +export function triggerFocusFor(element: HTMLElement): Promise +export function oneEvent(element: HTMLElement, eventName: string): Promise +export function nextFrame(): Promise +export function flush(): Promise diff --git a/packages/testing-helpers/helpers.js b/packages/testing-helpers/helpers.js index ddda3acc..8356a593 100644 --- a/packages/testing-helpers/helpers.js +++ b/packages/testing-helpers/helpers.js @@ -11,7 +11,7 @@ let defineCECounter = 0; * const el = fixture(`<${tag}>`); * // test el * - * @param {function()} klass + * @param {function} klass * @returns {string} */ export function defineCE(klass) { diff --git a/packages/testing-helpers/index.d.ts b/packages/testing-helpers/index.d.ts index 05cb9ede..826029b3 100644 --- a/packages/testing-helpers/index.d.ts +++ b/packages/testing-helpers/index.d.ts @@ -1,12 +1,13 @@ -export { html, unsafeStatic } from './lit-html'; +export { html, unsafeStatic } from './lit-html.js'; export { - aTimeout, - defineCE, - isIE, - nextFrame, - oneEvent, triggerBlurFor, triggerFocusFor, -} from './helpers'; -export { litFixture, litFixtureSync } from './litFixture'; -export { fixture, fixtureSync } from './fixture'; + oneEvent, + isIE, + defineCE, + aTimeout, + nextFrame, +} from './helpers.js'; +export { litFixture, litFixtureSync } from './litFixture.js'; +export { stringFixture, stringFixtureSync } from './stringFixture.js'; +export { fixture, fixtureSync } from './fixture.js'; diff --git a/packages/testing-helpers/index.js b/packages/testing-helpers/index.js index a15b2848..826029b3 100644 --- a/packages/testing-helpers/index.js +++ b/packages/testing-helpers/index.js @@ -9,4 +9,5 @@ export { nextFrame, } from './helpers.js'; export { litFixture, litFixtureSync } from './litFixture.js'; +export { stringFixture, stringFixtureSync } from './stringFixture.js'; export { fixture, fixtureSync } from './fixture.js'; diff --git a/packages/testing-helpers/litFixture.d.ts b/packages/testing-helpers/litFixture.d.ts index 9e4f036c..b119ed05 100644 --- a/packages/testing-helpers/litFixture.d.ts +++ b/packages/testing-helpers/litFixture.d.ts @@ -1,4 +1,4 @@ -import { FixtureWrapper } from './fixture'; +import { TemplateResult } from 'lit-html'; -export function litFixtureSync(template: TemplateResult): FixtureWrapper; -export async function litFixture(template: TemplateResult): Promise; +export function litFixtureSync(template: TemplateResult): Element; +export function litFixture(template: TemplateResult): Promise; diff --git a/packages/testing-helpers/litFixture.js b/packages/testing-helpers/litFixture.js index 8a7d54b7..cb3fa6bb 100644 --- a/packages/testing-helpers/litFixture.js +++ b/packages/testing-helpers/litFixture.js @@ -1,15 +1,15 @@ -import { FixtureWrapper } from './fixture.js'; +import { fixtureWrapper } from './fixtureWrapper.js'; import { render } from './lit-html.js'; import { nextFrame } from './helpers.js'; /** * Setups an element synchronously from the provided lit-html template and puts it in the DOM. * - * @param {TemplateResult} template - * @returns {HTMLElement} + * @param {import('lit-html').TemplateResult} template + * @returns {Element} */ export function litFixtureSync(template) { - const wrapper = new FixtureWrapper(); + const wrapper = fixtureWrapper(); render(template, wrapper); return wrapper.children[0]; } @@ -17,8 +17,8 @@ export function litFixtureSync(template) { /** * Setups an element asynchronously from the provided lit-html template and puts it in the DOM. * - * @param {TemplateResult} template - * @returns {Promise} + * @param {import('lit-html').TemplateResult} template + * @returns {Promise} */ export async function litFixture(template) { const fixture = litFixtureSync(template); diff --git a/packages/testing-helpers/stringFixture.js b/packages/testing-helpers/stringFixture.js new file mode 100644 index 00000000..ab6f403d --- /dev/null +++ b/packages/testing-helpers/stringFixture.js @@ -0,0 +1,28 @@ +import { nextFrame } from './helpers.js'; +import { fixtureWrapper } from './fixtureWrapper.js'; + +/** + * Setups an element synchronously from the provided string template and puts it in the DOM. + * Allows to specify properties via an object or a function taking the element as an argument. + * + * @param {string} template + * @returns {Element} + */ +export function stringFixtureSync(template) { + const wrapper = fixtureWrapper(); + wrapper.innerHTML = template; + return wrapper.children[0]; +} + +/** + * Setups an element asynchronously from the provided string template and puts it in the DOM. + * Allows to specify properties via an object or a function taking the element as an argument. + * + * @param {string} template + * @returns {Promise} + */ +export async function stringFixture(template) { + const result = stringFixtureSync(template); + await nextFrame(); + return result; +} diff --git a/packages/testing-helpers/test/bdd-setup.js b/packages/testing-helpers/test/bdd-setup.js index 8064c873..003640bc 100644 --- a/packages/testing-helpers/test/bdd-setup.js +++ b/packages/testing-helpers/test/bdd-setup.js @@ -1,5 +1,5 @@ // do manual setup and not use testing to not have circle dependencies -import { cachedWrappers } from '../fixture.js'; +import { cachedWrappers } from '../fixtureWrapper.js'; // register-cleanup if (afterEach) { diff --git a/packages/testing-helpers/test/fixture.test.js b/packages/testing-helpers/test/fixture.test.js new file mode 100644 index 00000000..66023d2a --- /dev/null +++ b/packages/testing-helpers/test/fixture.test.js @@ -0,0 +1,48 @@ +import { expect } from '@bundled-es-modules/chai'; +import { html, fixture, fixtureSync } from '../index.js'; + +class TestComponent2 extends HTMLElement {} +customElements.define('test-component2', TestComponent2); + +describe('fixtureSync & fixture', () => { + it('supports strings', async () => { + /** + * @param {Element} element + */ + function testElement(element) { + expect(element.getAttribute('foo')).to.equal('bar'); + } + + const elementSync = fixtureSync(html` + + `); + testElement(elementSync); + + const elementAsync = await fixture(html` + + `); + testElement(elementAsync); + }); + + it('supports lit-html TemplateResult with properties', async () => { + const myFunction = () => {}; + + /** + * @param {Element} element + */ + function testElement(element) { + expect(element.propNumber).to.equal(10); + expect(element.propFunction).to.equal(myFunction); + } + + const elementSync = fixtureSync(html` + + `); + testElement(elementSync); + + const elementAsync = await fixture(html` + + `); + testElement(elementAsync); + }); +}); diff --git a/packages/testing-helpers/test/index.html b/packages/testing-helpers/test/index.html index f57d8f3a..f9d0628b 100644 --- a/packages/testing-helpers/test/index.html +++ b/packages/testing-helpers/test/index.html @@ -13,7 +13,12 @@