Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run every test with and without scoped-element-registry polyfill #2353

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions packages/ui/components/core/test/SlotMixin.polyfill.test.js
Original file line number Diff line number Diff line change
@@ -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`<scoped-elm></scoped-elm>`,
};
}

render() {
return html`<slot name="template"></slot>`;
}
},
);

const tag = unsafeStatic(tagName);
await fixture(html`<${tag}></${tag}>`);

expect(createElementSpy.getCalls()).to.have.length(1);
});
102 changes: 0 additions & 102 deletions packages/ui/components/core/test/SlotMixin.test.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,11 @@
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';

/**
* @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(
Expand Down Expand Up @@ -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`<scoped-elm></scoped-elm>`,
};
}

render() {
return html`<slot name="template"></slot>`;
}
},
);

const tag = unsafeStatic(tagName);
await fixture(html`<${tag}></${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`<scoped-el></scoped-el>`,
};
}

render() {
return html`<slot name="template"></slot>`;
}
},
);

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();
});
});
});
59 changes: 45 additions & 14 deletions web-test-runner.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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`),
Expand All @@ -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 testsThatMustRunWithScopedCustomElementRegistryPolyfill = 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 => `
<html>
<head>
<script src="/node_modules/@webcomponents/scoped-custom-element-registry/scoped-custom-element-registry.min.js"></script>
<script type="module" src="${testRunnerImport}"></script>
</head>
</html>
`;
`,
};
});

const testsThatMustRunWithoutPolyfill = 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 => `
<html>
<head>
<script type="module" src="${testRunnerImport}"></script>
</head>
</html>
`,
};
});

export default {
nodeResolve: { exportConditions: [devMode && 'development'] },
Expand All @@ -51,14 +84,12 @@ 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: testsThatMustRunWithoutPolyfill.concat([
...testsThatMustRunWithScopedCustomElementRegistryPolyfill,
]),
};