mirror of
https://github.com/jlengrand/open-wc.git
synced 2026-03-10 08:31:19 +00:00
feat(testing-helpers): add scoped-elements support
This commit is contained in:
committed by
Benny Powers
parent
5c62c144e2
commit
f265d9e9d5
@@ -29,8 +29,12 @@
|
||||
"fixtures"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"lit-element": "^2.2.1",
|
||||
"lit-html": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@open-wc/scoped-elements": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"lit-html": "^1.0.0",
|
||||
"webpack-merge": "^4.1.5"
|
||||
|
||||
@@ -5,6 +5,8 @@ import { isValidRenderArg } from './lib.js';
|
||||
/**
|
||||
* @typedef {object} FixtureOptions
|
||||
* @property {Element} [parentNode] optional parent node to render the fixture's template to
|
||||
* @property {import('@open-wc/scoped-elements').ScopedElementsMap} [scopedElements] optional scoped-elements
|
||||
* definition map
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,6 +3,7 @@ import { fixtureWrapper } from './fixtureWrapper.js';
|
||||
import { render } from './lit-html.js';
|
||||
import { elementUpdated } from './elementUpdated.js';
|
||||
import { NODE_TYPES } from './lib.js';
|
||||
import { getScopedElementsTemplate } from './scopedElementsWrapper.js';
|
||||
|
||||
/**
|
||||
* @typedef {
|
||||
@@ -35,7 +36,12 @@ const isUsefulNode = ({ nodeType, textContent }) => {
|
||||
*/
|
||||
export function litFixtureSync(template, options = {}) {
|
||||
const wrapper = fixtureWrapper(options.parentNode);
|
||||
render(template, wrapper);
|
||||
|
||||
render(
|
||||
options.scopedElements ? getScopedElementsTemplate(template, options.scopedElements) : template,
|
||||
wrapper,
|
||||
);
|
||||
|
||||
if (template instanceof TemplateResult) {
|
||||
return /** @type {T} */ (wrapper.firstElementChild);
|
||||
}
|
||||
@@ -52,9 +58,17 @@ export function litFixtureSync(template, options = {}) {
|
||||
* @param {import('./fixture-no-side-effect.js').FixtureOptions} [options]
|
||||
* @returns {Promise<T>}
|
||||
*/
|
||||
export async function litFixture(template, options) {
|
||||
export async function litFixture(template, options = {}) {
|
||||
const el = litFixtureSync(template, options);
|
||||
await elementUpdated(el);
|
||||
|
||||
if (options.scopedElements) {
|
||||
const [node] = Array.from(el.shadowRoot.childNodes).filter(isUsefulNode);
|
||||
await elementUpdated(/** @type {T} */ (node));
|
||||
|
||||
return /** @type {T} */ (node);
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
return el;
|
||||
}
|
||||
|
||||
69
packages/testing-helpers/src/scopedElementsWrapper.js
Normal file
69
packages/testing-helpers/src/scopedElementsWrapper.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import { ScopedElementsMixin } from '@open-wc/scoped-elements';
|
||||
import { html, LitElement, TemplateResult } from 'lit-element';
|
||||
import { nothing } from 'lit-html';
|
||||
import { isIterable } from './lib.js';
|
||||
|
||||
/** @typedef {import('@open-wc/scoped-elements').ScopedElementsMap} ScopedElementsMap */
|
||||
|
||||
const transform = template => {
|
||||
if (isIterable(template)) {
|
||||
return [...template].map(v => transform(v));
|
||||
}
|
||||
|
||||
if (template instanceof TemplateResult) {
|
||||
return html(template.strings, ...template.values);
|
||||
}
|
||||
|
||||
return template;
|
||||
};
|
||||
|
||||
class ScopedElementsTestWrapper extends ScopedElementsMixin(LitElement) {
|
||||
static get properties() {
|
||||
return {
|
||||
scopedElements: { type: Object },
|
||||
template: { type: Object },
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
/** @type {ScopedElementsMap} */
|
||||
this.scopedElements = {};
|
||||
|
||||
/** @type {TemplateResult|{}} */
|
||||
this.template = nothing;
|
||||
}
|
||||
|
||||
async firstUpdated() {
|
||||
// @ts-ignore
|
||||
await super.firstUpdated();
|
||||
|
||||
Object.keys(this.scopedElements).forEach(key =>
|
||||
this.defineScopedElement(key, this.scopedElements[key]),
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return transform(this.template);
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
customElements.define('scoped-elements-test-wrapper', ScopedElementsTestWrapper);
|
||||
|
||||
/**
|
||||
* Wraps the template inside a scopedElements component
|
||||
*
|
||||
* @param {import('./litFixture').LitHTMLRenderable} template
|
||||
* @param {ScopedElementsMap} scopedElements
|
||||
* @returns {TemplateResult}
|
||||
*/
|
||||
export function getScopedElementsTemplate(template, scopedElements) {
|
||||
return html`
|
||||
<scoped-elements-test-wrapper
|
||||
.scopedElements="${scopedElements}"
|
||||
.template="${template}"
|
||||
></scoped-elements-test-wrapper>
|
||||
`;
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
import { html } from 'lit-html';
|
||||
import { fixtureWrapper } from './fixtureWrapper.js';
|
||||
import { elementUpdated } from './elementUpdated.js';
|
||||
import { litFixture } from './litFixture.js';
|
||||
|
||||
/**
|
||||
* Setups an element synchronously from the provided string template and puts it in the DOM.
|
||||
@@ -25,7 +27,12 @@ export function stringFixtureSync(template, options = {}) {
|
||||
* @param {import('./fixture-no-side-effect.js').FixtureOptions} [options]
|
||||
* @returns {Promise<T>}
|
||||
*/
|
||||
export async function stringFixture(template, options) {
|
||||
export async function stringFixture(template, options = {}) {
|
||||
if (options.scopedElements) {
|
||||
// @ts-ignore
|
||||
return litFixture(html([template]), options);
|
||||
}
|
||||
|
||||
const el = stringFixtureSync(template, options);
|
||||
await elementUpdated(el);
|
||||
// @ts-ignore
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// @ts-ignore
|
||||
import sinon from 'sinon';
|
||||
// @ts-ignore
|
||||
import { html as litHtml, LitElement } from 'lit-element';
|
||||
import { expect } from './setup.js';
|
||||
import { cachedWrappers } from '../src/fixtureWrapper.js';
|
||||
import { defineCE } from '../src/helpers.js';
|
||||
@@ -361,4 +362,42 @@ describe('fixtureSync & fixture', () => {
|
||||
await fixture(html`<${litTag}></${litTag}>`);
|
||||
expect(counter).to.equal(2);
|
||||
});
|
||||
|
||||
it('supports scoped-elements', async () => {
|
||||
class TestClass extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
foo: { type: String },
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.foo = '';
|
||||
}
|
||||
|
||||
render() {
|
||||
return litHtml`
|
||||
<div>${this.foo}</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
const elString = await fixture('<test-class foo="bar"></test-class>', {
|
||||
scopedElements: {
|
||||
'test-class': TestClass,
|
||||
},
|
||||
});
|
||||
|
||||
expect(elString).shadowDom.to.equal('<div>bar</div>');
|
||||
|
||||
const elLit = await fixture(html` <test-class foo="bar"></test-class> `, {
|
||||
scopedElements: {
|
||||
'test-class': TestClass,
|
||||
},
|
||||
});
|
||||
|
||||
expect(elLit).shadowDom.to.equal('<div>bar</div>');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user