Skip to content
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

Asserting on Stencil's Mock* objects breaks expect's diffs #2743

Closed
itsravenous opened this issue Nov 19, 2020 · 2 comments
Closed

Asserting on Stencil's Mock* objects breaks expect's diffs #2743

itsravenous opened this issue Nov 19, 2020 · 2 comments
Labels

Comments

@itsravenous
Copy link

itsravenous commented Nov 19, 2020

Stencil version:

 @stencil/core@2.3.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 an asserting that inspects one of the Mock* objects from Stencil (e.g. MockCustomEvent), fails, expect throws this error:

PrettyFormatPluginError: Cannot convert a Symbol value to a numberTypeError: Cannot convert a Symbol value to a number
        at isNaN (<anonymous>)

      at Object.get (node_modules/@stencil/core/mock-doc/index.cjs:18:10)
          at Proxy.toString (<anonymous>)
      at printBasicValue (node_modules/pretty-format/build/index.js:149:31)
      at printer (node_modules/pretty-format/build/index.js:367:23)
      at printObjectProperties (node_modules/pretty-format/build/collections.js:171:21)
      at printComplexValue (node_modules/pretty-format/build/index.js:295:48)
      at printer (node_modules/pretty-format/build/index.js:378:10)
      at printObjectProperties (node_modules/pretty-format/build/collections.js:171:21)
      at printComplexValue (node_modules/pretty-format/build/index.js:295:48)

Expected behavior:
I should be able to assert on these objects and see a diff of the expected vs actual. I

Steps to reproduce:

  1. Create a new stencil project (I used the app variant but I guess it doesn't matter which)
  2. Change my-component.tsx and my-component.spec.ts as below

Related code:

my-component.tsx:

import { Component, Prop, Event, h } from '@stencil/core';
import { EventEmitter } from '@stencil/router/dist/types/stencil.core';
import { format } from '../../utils/utils';

@Component({
  tag: 'my-component',
  styleUrl: 'my-component.css',
  shadow: false,
})
export class MyComponent {
  @Event() someEvent: EventEmitter;

  handleClick() {
    this.someEvent.emit();
  }

  render() {
    return (
      <div>
        <button onClick={() => this.handleClick()}>Click me</button>
      </div>
    );
  }
}

my-component.spec.ts:

import { newSpecPage } from '@stencil/core/testing';
import { MyComponent } from './my-component';

describe('my-component', () => {
  it('emits an event when clicked', async () => {
    const page = await newSpecPage({
      components: [MyComponent],
      html: `<my-component></my-component>`,
    });

    const host = page.body.querySelector('my-component');
    const button = page.body.querySelector('button');
    // Spy on the events dispatched by the web component
    const dispatchSpy = jest.spyOn(host, 'dispatchEvent');
    // Click the actual button, using the regular old DOM method
    button.click();

    expect(dispatchSpy).toHaveBeenCalledWith(expect.objectContaining({ type: 'someEvent' }));
  });
});

In this case I can of course work around this like so:

expect(dispatchSpy.mock.calls[0][0]).toHaveProperty('type': 'someEvent');

but it's much less readable.

Other information:
The problem appears to occur here:

if (!isNaN(prop as any)) {

What I think is happening is that expect is trying to run toString() on the object. AIUI, this will access the Symbol.toStringTag property on the object (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag).

I'm not exactly sure what the fix would be - perhaps implementing toStringTag on Stencil classes? Or just ignoring symbol props in the attrHandler function?

@ionitron-bot ionitron-bot bot added the triage label Nov 19, 2020
@rmirro
Copy link

rmirro commented Mar 11, 2021

I've been experiencing the same issues today with jest matchers where the opposite case throws exactly as you've described.

<my-component> exists below...

const { root } = await newSpecPage(...);
expect(root.shadowRoot.querySelector('my-component')).toBeTruthy();  // passes
expect(root.shadowRoot.querySelector('my-component')).not.toBeTruthy();  // throws with `PrettyFormatPluginError`
expect(root.shadowRoot.querySelector('my-component')).toBeFalsy();  // throws with `PrettyFormatPluginError`

The reason this became apparent is because I was testing for a component to not exist (toBeFalsy()). However, when it does mistakenly exist, the error that is thrown is not relevant to the test failure.

I ended up with this for now because having "MY-COMPONENT" in the test failure message seems better than PrettyFormatPluginError... 😄

expect(root.shadowRoot.querySelector('my-component')?.nodeName).toBeUndefined();

@rwaskiewicz
Copy link
Member

Hey @itsravenous 👋

I apologize that it took so long for a member of the team to respond to this issue. I believe this may have been fixed in #2788 (which would have been fixed in v2.4.0), although I can't say 100% for sure. In any case, I tested this with both Stencil 2.4.0 and Stencil 3.2.0, and this issue appears to have been resolved. As such, I'm going to close this issue.

@rmirro The issue you describe sounds similar, but different. If you're willing/able to, can you please create a new issue for the team to take a look?

Once again, I apologize for the poor turnaround time on this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants