diff --git a/packages/ui/components/core/test/SlotMixin.polyfill.test.js b/packages/ui/components/core/test/SlotMixin.polyfill.test.js new file mode 100644 index 0000000000..5b9ebdd4f3 --- /dev/null +++ b/packages/ui/components/core/test/SlotMixin.polyfill.test.js @@ -0,0 +1,40 @@ +import sinon from 'sinon'; +import { defineCE, expect, fixture, unsafeStatic, html } from '@open-wc/testing'; +import { ScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js'; +import { SlotMixin } from '@lion/ui/core.js'; +import { LitElement } from 'lit'; + +it('supports scoped elements when polyfill loaded', async () => { + // @ts-ignore the scoped-custom-element-registry polyfill makes sure `ShadowRoot.prototype.createElement` is defined + const createElementSpy = sinon.spy(ShadowRoot.prototype, 'createElement'); + + class ScopedEl extends LitElement {} + + const tagName = defineCE( + class extends ScopedElementsMixin(SlotMixin(LitElement)) { + static get scopedElements() { + return { + // @ts-expect-error + ...super.scopedElements, + 'scoped-elm': ScopedEl, + }; + } + + get slots() { + return { + ...super.slots, + template: () => html``, + }; + } + + render() { + return html``; + } + }, + ); + + const tag = unsafeStatic(tagName); + await fixture(html`<${tag}>`); + + expect(createElementSpy.getCalls()).to.have.length(1); +}); diff --git a/packages/ui/components/core/test/SlotMixin.test.js b/packages/ui/components/core/test/SlotMixin.test.js index 413dbf77c9..e9b6dd57cc 100644 --- a/packages/ui/components/core/test/SlotMixin.test.js +++ b/packages/ui/components/core/test/SlotMixin.test.js @@ -1,6 +1,4 @@ -import sinon from 'sinon'; import { defineCE, expect, fixture, fixtureSync, unsafeStatic, html } from '@open-wc/testing'; -import { ScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js'; import { SlotMixin } from '@lion/ui/core.js'; import { LitElement } from 'lit'; @@ -8,24 +6,6 @@ import { LitElement } from 'lit'; * @typedef {import('../types/SlotMixinTypes.js').SlotHost} SlotHost */ -// @ts-ignore -const createElementNative = ShadowRoot.prototype.createElement; -function mockScopedRegistry() { - const outputObj = { createElementCallCount: 0 }; - // @ts-expect-error wait for browser support - ShadowRoot.prototype.createElement = (tagName, options) => { - outputObj.createElementCallCount += 1; - // Return an element that lit can use as render target - return createElementNative(tagName, options); - }; - return outputObj; -} - -function unMockScopedRegistry() { - // @ts-expect-error wait for browser support - ShadowRoot.prototype.createElement = createElementNative; -} - describe('SlotMixin', () => { it('inserts provided element into light dom and sets slot', async () => { const tag = defineCE( @@ -566,86 +546,4 @@ describe('SlotMixin', () => { expect(el._templateNode.textContent).to.equal('1'); }); }); - - describe('Scoped Registries', () => { - it('supports scoped elements when polyfill loaded', async () => { - const outputObj = mockScopedRegistry(); - - class ScopedEl extends LitElement {} - - const tagName = defineCE( - // @ts-ignore - class extends ScopedElementsMixin(SlotMixin(LitElement)) { - static get scopedElements() { - return { - // @ts-expect-error - ...super.scopedElements, - 'scoped-elm': ScopedEl, - }; - } - - get slots() { - return { - ...super.slots, - template: () => html``, - }; - } - - render() { - return html``; - } - }, - ); - - const tag = unsafeStatic(tagName); - await fixture(html`<${tag}>`); - - expect(outputObj.createElementCallCount).to.equal(1); - - unMockScopedRegistry(); - }); - - it('does not scope elements when polyfill not loaded', async () => { - // @ts-expect-error - ShadowRoot.prototype.createElement = null; - class ScopedEl extends LitElement {} - - const tagName = defineCE( - class extends ScopedElementsMixin(SlotMixin(LitElement)) { - static get scopedElements() { - return { - // @ts-expect-error - ...super.scopedElements, - 'scoped-el': ScopedEl, - }; - } - - get slots() { - return { - ...super.slots, - template: () => html``, - }; - } - - render() { - return html``; - } - }, - ); - - const renderTarget = document.createElement('div'); - const el = document.createElement(tagName); - - // We don't use fixture, so we limit the amount of calls to document.createElement - const docSpy = sinon.spy(document, 'createElement'); - document.body.appendChild(renderTarget); - renderTarget.appendChild(el); - - expect(docSpy.callCount).to.equal(2); - - document.body.removeChild(renderTarget); - docSpy.restore(); - unMockScopedRegistry(); - }); - }); }); diff --git a/web-test-runner.config.mjs b/web-test-runner.config.mjs index 5f269c6da5..f89be72ae8 100644 --- a/web-test-runner.config.mjs +++ b/web-test-runner.config.mjs @@ -3,7 +3,7 @@ import { playwrightLauncher } from '@web/test-runner-playwright'; const devMode = process.argv.includes('--dev-mode'); -const packages = fs +const testGroups = fs .readdirSync('packages') .filter( dir => fs.statSync(`packages/${dir}`).isDirectory() && fs.existsSync(`packages/${dir}/test`), @@ -18,21 +18,54 @@ const packages = fs fs.existsSync(`packages/ui/components/${dir}/test`), ) .map(dir => ({ name: dir, path: `packages/ui/components/${dir}/test` })), - ); + ) + .map(pkg => ({ + name: pkg.name, + files: `${pkg.path}/**/*.test.js`, + })); -/** - * @type {import('@web/test-runner').TestRunnerConfig['testRunnerHtml']} - * - */ -const testRunnerHtml = testRunnerImport => - ` +const testsThatShouldRunWithScopedCustomElementRegistryPolyfill = testGroups.map(testGroup => { + const files = [ + testGroup.files, + `!${testGroup.files.replace('*.test.js', '*.no-polyfill.test.js')}`, + ]; + return { + name: testGroup.name, + files, + /** + * @type {import('@web/test-runner').TestRunnerConfig['testRunnerHtml']} + * + */ + testRunnerHtml: testRunnerImport => ` -`; +`, + }; +}); + +const testsThatShouldNotRunWithPolyfill = testGroups.map(testGroup => { + const files = [testGroup.files, `!${testGroup.files.replace('*.test.js', '*.polyfill.test.js')}`]; + + return { + name: testGroup.name, + files, + /** + * @type {import('@web/test-runner').TestRunnerConfig['testRunnerHtml']} + * + */ + testRunnerHtml: testRunnerImport => ` + + + + + +`, + }; +}); export default { nodeResolve: { exportConditions: [devMode && 'development'] }, @@ -51,14 +84,13 @@ export default { timeout: '5000', }, }, - testRunnerHtml, browsers: [ playwrightLauncher({ product: 'firefox', concurrency: 1 }), playwrightLauncher({ product: 'chromium' }), playwrightLauncher({ product: 'webkit' }), ], - groups: packages.map(pkg => ({ - name: pkg.name, - files: `${pkg.path}/**/*.test.js`, - })), + groups: [].concat([ + ...testsThatShouldRunWithScopedCustomElementRegistryPolyfill, + ...testsThatShouldNotRunWithPolyfill, + ]), };