import { TemplateResult } from 'lit-html';
import { render, html } from 'lit-html';
import { unsafeHTML } from 'lit-html/directives/unsafe-html';
import { waitForRender } from '../async-utils';
import { HTMLTestFixture } from './html-test-fixture';
import { DiffConfig } from '../semantic-diff/semantic-diff';
export { HTMLTestFixture };
export interface TestFixtureConfig extends DiffConfig {
componentName?: string;
}
function toLitTemplate(value: unknown) {
if (typeof value === 'string') {
return html`${unsafeHTML(value)}`;
}
if (value instanceof TemplateResult) {
return value;
}
// TODO: we can render anything directly without wrapping in 0.11 onwards
return html`${value}`;
}
/**
* Sets up a test fixture and renders the given value to the DOM.
* To avoid memory leaks, call teardown() after the test finished.
*
* This function returns synchronously, if dependent on async rendering
* use the testFixture() function instead.
*
* @param value the value to render. A string is rendered as HTML, any other
* values are passed to lit-html directly. Any valid lit value can be rendered.
* @returns the test fixture.
*/
export function testFixtureSync(value: unknown): HTMLTestFixture {
const fixture = document.createElement('html-test-fixture');
document.body.appendChild(fixture);
const template = toLitTemplate(value);
render(template, fixture);
return fixture as HTMLTestFixture;
}
/**
* Sets up a test fixtures, and waits for one render cycle to complete. Use this
* if dependent on async rendering. See testFixtureSync() for more.
*
* @param value the value to render.
* @returns a promise that resolves with the test fixture after one render cycle.
*/
export async function testFixture(value: unknown) {
const fixture = testFixtureSync(value);
await waitForRender;
return fixture;
}
/**
* Sets up a web component fixture. Uses testFixture(), but adds convenience when
* testing web components. The .component property can be used for retreiving the
* component, and assertEquals() will use the component's shadow root for diffing
* if it's used.
*
* @param value the value to render.
* @param componentName the name of the component. Optional, by default the first component found is used
* @returns a promise that resolves with the test fixture after one render cycle.
*/
export async function componentFixture(value: unknown, config: TestFixtureConfig = {}) {
const fixture = await testFixture(value);
fixture.mode = 'web-component';
fixture.componentName = config.componentName;
fixture.diffConfig = config;
return fixture;
}
/**
* Same as componentFixture(), but without waiting for a render.
*
* @param value the value to render.
* @param componentName the name of the component. Optional, by default the first component found is used
* @returns the test fixture.
*/
export function componentFixtureSync(value: unknown, config: TestFixtureConfig = {}) {
const fixture = testFixtureSync(value);
fixture.mode = 'web-component';
fixture.componentName = config.componentName;
fixture.diffConfig = config;
return fixture;
}