ionic-team / stencil

A toolchain for building scalable, enterprise-ready component systems on top of TypeScript and Web Component standards. Stencil components can be distributed natively to React, Angular, Vue, and traditional web developers from a single, framework-agnostic codebase.
https://stenciljs.com
Other
12.58k stars 789 forks source link

E2E Snapshot Test Bug / No coverage #1378

Closed juansuh closed 4 years ago

juansuh commented 5 years ago

Stencil version:

 @stencil/core@0.14.2
puppeteer@1.8.0
jest@23.6.0

I'm submitting a: [x] bug report [ ] feature request [ ] support request => Please do not submit support requests here, use one of these channels: https://stencil-worldwide.herokuapp.com/ or https://forum.ionicframework.com/

Current behavior: When running an E2E test on a component, if that component contains nested render functions, then snapshot tests will come back with a skeleton element that provides no useful data for testing.

For instance, a class that contains:

render() {
   return (
      <div> { some renderFn() } </div>
   );
}

will return as a snapshot:

exports[`ComponentX should match snapshot 1`] = `"<div> </div>"`;

Apologies that more detailed code can't be provided, since it's company code and I can't share it.

Here are some errors that are printed to console as well, they print under the test that just "passed".

console.error node_modules/@stencil/core/dist/testing/index.js:25166
      JSHandle@error 3 MENU-TREE

Expected behavior: When we snapshot test components, we want to see the internal elements that are rendered, just as we can see the internal elements of the parent render function. Unit tests are working fine and some components have no issues with snapshot tests, but coverage on all necessary components would be nice.

Steps to reproduce: Here is a render() functions that's provided me with empty elements, as well as the snapshot test structure I use.

Snapshot test general structure:

describe('xComponent', () => {
  let page: E2EPage;
  const pageList: CoverageEntry[][] = [];
  let element: E2EElement;

  beforeEach(async () => {
    page = await newE2EPage();
    await page.setContent(`<x-component></x-componentt>`);
    element = await page.find('x-component');

    await page.coverage.startJSCoverage();
    await page.waitForChanges();
  });

  afterEach(async () => {
    const jsCoverage = await page.coverage.stopJSCoverage();
    pageList.push(jsCoverage);
  });

  afterAll(() => aggregateCoverage('X Component', pageList));

  it('should match snapshot', () => {
    expect(element.outerHTML).toMatchSnapshot();
  });
});

An example that would give a skeleton snapshot:

render() {
    return (
      <x-component role="application" onKeyDown={(event: KeyboardEvent) => this.handleKeyDown(event)}>
        {this.renderFn(conditional ? choice1 : choice2)}
      </x-component>
    );
  }

would return:

exports[`xComponent should match snapshot 1`] = `"<div></div>"`;

Other information: There's no stack trace since there's no real error going on, but I am positive that the source of the issue is the nested render functions. I've tried modifying the test in multiple ways to point at different names of the element and outer/inner html but all to no avail, I either get a null error or an empty element.

I appreciate any assistance and sorry I can't just copy and dump all my code here, as I have around 5 examples total that don't work. If you need any more information I will be watching this thread with great interest.

adamdbradley commented 4 years ago

This should be fixed in the latest version. If it's still a problem, would you be able to create an issue with a thorough description on how to replicate this? Thanks