sand4rt / playwright-ct-web

Playwright Web component testing.
https://www.npmjs.com/package/@sand4rt/experimental-ct-web
MIT License
41 stars 3 forks source link

Idea/Feature: provide more powerful way to create test cases (mount) #14

Open davidkron opened 1 year ago

davidkron commented 1 year ago

I am currently searching for and experimenting with alternatives to @web/test-runner and @open-oc/testing for testing custom components and also stumbled over playwright-ct and your library. For simple use cases it seems to work well, but I have created some tests already with @web/test-runner, which I fail to rewrite using mount.

For example one of the problems is, that mount seems to only work for creating single component instances:

const component = await mount(Button, {
  props: {
    title: 'Submit',
  },
});

This only works for the very simplest of use-cases. A more real-world usage (especially in the example of testing a custom button component) would be something like this, where not only the component itself, but maybe some wrapper element or children are necessary to construct a realistic test case:

const el = await fixture(html`
  <form>
    <my-button type="submit">Submit</my-button>
  </form>
`);

I was wondering if it was possible to make mount more powerful and provide something similar to the fixtures helper from https://www.npmjs.com/package/@open-wc/testing-helpers#user-content-test-a-custom-element-with-properties? Even better if one could (optionally) provide a template using lit-html to write better readable test cases.

sand4rt commented 1 year ago

Hi, does the slot API cover your case?:

https://github.com/sand4rt/playwright-ct-web/blob/master/ct-web-lit/tests/slots.spec.ts

test('render a component as slot', async ({ mount }) => {
  const component = await mount(Form, {
    slots: {
      default: '<button-component title="Submit" />', // component is registered globally in /playwright/index.ts
    },
  });
  await expect(component).toContainText('Submit');
});
davidkron commented 1 year ago

I am more looking to utilize the full potential of lit-html.

For example: maybe I want to test a custom directive:

const myvalue = 'asdf';
const el = await fixture(html`
  <form>
    <input type="text" .value=${mydirective(myvalue)}></input>
  </form>
`);
sand4rt commented 1 year ago

@davidkron i'm hesitant to add the html``; because it differs from the Playwright API. I do however think that there should be support for directives.

Do you have more use cases that are not supported but are with the html``; API?

davidkron commented 1 year ago

I would say that the 6 primary use cases that the lit template syntax supports are succinctly described in the first table on the page https://lit.dev/docs/templates/expressions/

Of course the event binding syntax is pretty popular in lit, but I am not sure if something like this would be even possible to support. Because as I understand, in Playwright the testing code is run in the Node context and the rendered component is run in the browser context.

sand4rt commented 1 year ago

Thanks for your reply. directives and attributes don't seem to be supported at the moment:

Type Example
Child nodes See slots.spec.ts
Attributes Not sure if this is useful for testing yet, but there is an open PR for it
Boolean Attributes See render.spec.ts
Properties See render.spec.ts
Event listeners See events.spec.ts
Element directives Not supported yet

*https://lit.dev/docs/templates/expressions

I will look into directive support, but i don't see a good reason to deviate from Playwright's API.

jamieomaguire commented 1 year ago

It's a bit hacky but as a get around you can do stuff like this @davidkron:

 await page.evaluate(() => {
  const formHTML = `
    <form id="testForm" action="/foo" method="POST">
        <input type="text" id="username" name="username" required>
        <input type="password" id="password" name="password" required>
        <my-button id="submitButton" type="submit">Submit</my-button> <- the web component to test
    </form>
  `;
   document.body.innerHTML = formHTML;
});