storybookjs / testing-library

Instrumented version of Testing Library for Storybook Interactions
MIT License
56 stars 8 forks source link

[Bug] Missing shadow dom #24

Open ariefurtado opened 2 years ago

ariefurtado commented 2 years ago

Describe the bug

Currently, it is not possible to use the library with Web Components because of missing shadow dom...

Steps to reproduce the behavior

  1. Create a project with Web Components and Storybook and Interaction tests
  2. Create a component with shadow: true and a stories file for that component
  3. Create a play function that tries to find an element within the component shadow dom
  4. Run the storybook and check the interaction tests console

Expected behavior

Should be able to find the element within the shadow dom.

ariefurtado commented 2 years ago

I have forked the project, and based on this comment from an issue of the dom-testing-library, I have swapped the @testing-library/dom dependency for the testing-library__dom.

commentary about the issue: https://github.com/testing-library/dom-testing-library/issues/742#issuecomment-674987855

my library fork: https://github.com/ariefurtado/testing-library

For those that wants to try the forked version, I created a tag within the fork and its working! https://github.com/ariefurtado/testing-library/tree/v0.0.1_shadow

ps: since this is my first time forking and doing all of this, I ask you folks not to be too harsh with me ^^

ps²: this is not a production ready implementation and cannot be merged into the original project and we have to wait for a stable solution.

yannbf commented 2 years ago

Hey @ariefurtado thanks a lot for the work you did there! I tested it out and it's awesome.

Although your solution does add support for web components, there is a slight problem there, given the fact that it's using a community fork of testing library from 2 years ago:

If you are very interested in making this possible in the actual @testing-library/dom package, can you reach out to me on twitter? There is a possible long term solution but for that I need help from someone who is well versed into the web components world.

ericclemmons commented 2 years ago

I just ran into this issue and, with interactions, this is how I'm working around it:

MyThing.play = async ({args, canvasElement}) => {
  const wc = canvasElement.querySelector(
    'my-thing',
  ) as HTMLElement;

  // Wait for Shadow DOM to be mounted & `open`
  const root = await waitFor(
    () => (wc.shadowRoot as ShadowRoot).firstElementChild as HTMLElement,
    {
      timeout: 5000,
    },
  );

  const screen = within(root);

  ...
};

Perhaps this could be documented away?

benelan commented 2 years ago

@ericclemmons Unfortunately this doesn't work for us:

export const WithLabel = WithLabelTemplate.bind({});

WithLabel.play = async ({ canvasElement }) => {
  const wc = canvasElement.querySelector("calcite-input") as HTMLInputElement;

  const root = await waitFor(() => (wc.shadowRoot as ShadowRoot).firstElementChild as HTMLElement, {
    timeout: 5000
  });

  const screen = within(root);
  const input = screen.getByTestId("input-with-label") as HTMLInputElement;
  await userEvent.type(input, "foo bar baz");
};

We get this error: image

What did you put in the rest of your play function? I'm skeptical about the work around since @testing-library/dom doesn't provide access to web component browser APIs, but I hope I'm wrong.


@yannbf I don't have twitter, but my team and I would like to connect about the long term solution. We are creating Calcite Components and may be able to help with the web component side of the equation. We want to migrate to chromatic and this is the only thing blocking us. Let me know how we can help and/or how we should connect. Thanks!

ziyafenn commented 2 years ago

Still no support?

yannbf commented 2 years ago

@yannbf I don't have twitter, but my team and I would like to connect about the long term solution. We are creating Calcite Components and may be able to help with the web component side of the equation. We want to migrate to chromatic and this is the only thing blocking us. Let me know how we can help and/or how we should connect. Thanks!

Sorry I missed this @benelan, I'll reach out on Linkedin.

SavvasNicoleCandiotti commented 1 year ago

@yannbf @benelan any updates 😊?

ariefurtado commented 1 year ago

Hello again @yannbf, this has been a very long year for me, and a lot of stuff hapenned so i could not see this issue progressing.

I played with the solution presented by @ericclemmons and thought that something was off. Then I've searched the docs for the waitFor function and came up with a refactor that got me there.

I've created the function withinShadowRoot to make it easy to re-use.

export async function withinShadowRoot(customElement: HTMLElement, selector: string) {
    const webc = customElement.querySelector(selector);

    await waitFor(
        () => {
            const shadowRootFirstEl = webc.shadowRoot.firstElementChild as HTMLElement;
            return expect(shadowRootFirstEl).toContainElement(shadowRootFirstEl);
        },
        { timeout: 1000 },
    );

    // force type HTMLElement to ignore the type checking of the "within" function
    return within(webc.shadowRoot as any as HTMLElement);
}

With this function, all that is needed to interact with the elements in the shadowRoot is to await for the function to return and we can use it. Example:

// CSF3 StoryObj
export const Default: StoryObj<PzlButtonStoryArgs> = {
  render: Template.bind({}),

  args: { 
    onClick: event => action('Button Clicked')(event),
    children: <p>click me</p>
  },

  play: async ({ canvasElement }) => {
    const webc = await withinShadowRoot(canvasElement, 'pzl-button');
    const buttonEl = await webc.findByRole('button');
    await userEvent.click(buttonEl);
  }
};

I'm not sure about the efficiency and I have not tested enough, but for now, it is doing the trick.

image

Thanks everyone ^^

ps: please forgive my english... 😳

SavvasNicoleCandiotti commented 1 year ago

@ariefurtado can't wait to give this a try over the weekend! Cheers!

sujarajan commented 10 months ago

Hello @yannbf,

any updates on this?