-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
[Feature] Web Component (Lit) support for test-ct #14241
Comments
If I understand the current architecture, the const locator = await mount(comp: T, opts?: U); uses // Primitive value -> root.innerHTML = (comp ?? '').toString():
mount(undefined) -> <div id="root"></div>
mount(0) -> <div id="root">0</div>
mount('hello') -> <div id="root">hello</div>
mount('<button>Click me</button>') -> <div id="root"><button>Click me</button></div>
// Object instanceof HTMLElement -> root.appendChild(comp):
mount(document.createElement('div')) -> <div id="root"><div></div></div>
// That should also work for Custom Elements (Web Components) if you've registered it:
mount(new MyComponent()) -> <div id="root"><my-component></my-component></div>
// A base-plugin could also auto-register custom elements if they're not already:
// if(!customElements.get(compName)) customElements.define(compName, comp);
// Functions could just mount the awaited return value:
// Note: if return value is also a function, throw Error to prevent recursion
mount(() => 'hello') -> <div id="root">hello</div>
mount(async () => 'hello') -> <div id="root">hello</div>
// Array could just be iterated/joined:
mount([1, 1]) -> <div id="root">11</div>
// If an Object isn't supported, it can just fail the test.
mount({}) -> Error('Unknown component type, did you forget to import test from a plugin?')
mount(new Date()) -> Error('Unknown component type, did you forget to import test from a plugin?') Since React, Vue and Svelte plugins all share some code in common and eventually libraries/frameworks requiring a plugin/build-step/other tooling would need to do some similar pattern and return their mount function, but for the raw patterns/libraries out there I think it would actually be nice to be able to component test out of the box when no work is needed like ReactDOM.render, Vue.createApp().mount, etc. |
I'm not 100% clear on why the test runner needs to know about There is a concept of a component "registry" in each of the existing plugins but it's not clear what that is for. Maybe it's important to the existing reporter infrastructure? The plugins also load in the framework-specific Vite plugins which could potentially be externalized (#14295), or decoupled into a build-agnostic config. |
The only reason current |
Looking at the docs page for Playwright component testing, I was confused that there's no "no framework" option. Eg I'd like to test vanilla web components or plain html + js. Lit (and Angular :) ) would be great, but given a good foundation those could be added by the community. Are there any examples for "no framework" component testing? |
Just published a NPM package for lit and native web components until there is official support: https://github.com/sand4rt/playwright-ct-web. |
Sample code using evaluate: test("display in a small container", async ({ page }) => {
await page.goto("/debug-page")
await page.evaluate(() => {
const body = document.querySelector("body")
if (body) {
body.innerHTML = `<div style="height:200px; background-color: red;">
<my-web-component></my-web-component>
</div>`
}
})
await page.screenshot() // to see the result
}) The only requirement is to have a "debug-page" somewhere where you can put your components + load relevant JS code of your app. Edit: as a nicer reusable function: export async function mount(page: Page, html: string) {
await page.goto("/components") // we need a page that loads the relevant JS (it's possible to list all your registered web components in this page, if you are patient enough)
await page.evaluate((html) => {
const body = document.querySelector("body") // you can craft yourself a nicer page with a specific "#component" div
if (body) {
body.innerHTML = html
}
}, html) // it's not a normal closure, you have to pass the argument again here
} Note that rendering plain HTML is however slightly different from rendering Lit elements using |
@eric-burel oh, manually |
Thank you @sand4rt and @eric-burel for work arounds. I'd love to have "in-library" support for testing lit web components in Playwright. We're exploring adding Playwright testing to Microsoft Graph Toolkit and would like to have component level tests rather than only page level tests hitting our Storybook site. |
@eric-burel Thanks to your example we were able to use Playwright to test Lit components in the docmaps project. Much appreciated! Just a note for everyone, that example is not using Playwright component testing at all. It is a way to render Lit components dynamically with import { expect, Locator, test, Page, Request, Route } from '@playwright/test'; Another note: when he says you can't set properties, he is referring to a specific Lit feature called property expressions. His approach does support setting ordinary properties on Lit components via html attributes, like so: async function renderWidget(page: Page, id: string) {
await page.goto('/');
await page.evaluate(
({ serverUrl, id }) => {
const root = document.querySelector('#root');
if (root) {
console.log('body found');
root.innerHTML = `<docmaps-widget serverurl='${serverUrl}' doi='${id}'></docmaps-widget>`;
}
},
{ serverUrl: STAGING_SERVER_URL, id }, // This is not a regular closure, so we need to pass in the variables we want to use
);
await page.waitForSelector('docmaps-widget');
return page.locator('docmaps-widget');
} Here's a link to the part of our project that is tested with this strategy for anyone who wants to see it applied in the real world. |
No chance you would want to send a PR to this repo to add it, with the experience you have about this? :) Would be amazing having native support. |
Hopefully in the future ;) Angular is first: #27783 |
Feature request - support for web components in "component test" mode.
Looking into the Svelte/React/Vue implementation, I think it would be even simpler to do for native web components since there is no framework-specific Vite plugin needed, even if using a library like Lit. You might even consider web components the base case for component tests, since all you need is the environment setup/teardown; this would open up experimentation with lesser-known frameworks that aren't going to get an official plugin since they can do some work in userspace for "mount" style commands.
The text was updated successfully, but these errors were encountered: