4

I have a stencil component that looks something like this:

    export class MyBadge {
      @Prop() skin: string = 'primary';
      render(){
        return (
        <span class={`skin-${this.skin}`} />
      )

I want to write a unit test that checks that the rendered component applies the given skin property. I have a test that compares the rendered component to my expected html, using expect(page.root).toEqualHtml(´< span class=primary >´). This test works! However, when I try to modify the prop, using template, it fails to run the test.

    import { newSpecPage } from '@stencil/core/testing';
    import { MyBadge } from './my-badge'
    it('should have "secondary" skin', async () => {
     const page = newSpecPage({
            components: [MyBadge],
            template: () => (`
              <my-badge skin=secondary></my-badge>
              `), 
          });
          expect(page.root).toEqualHtml(`
          <span class="skin-secondary">
          ...
          `);
        });

This gives the error expect toEqualHtml() value is "null" and the test fails

I have also tried including the bellow html under the it, but that fails too.

html: `<my-badge></my-badge>`,

Removing the template option makes the test work, however it then does not see the updated prop.

I wanted to use the template option based on this answer: https://github.com/ionic-team/stencil/issues/1923

I've also tried a few different syntaxes, I'm not clear on how to wrap the template string.

I've been looking around for documentation on this but I can't seem to find what I'm looking for. Any help would be appreciated!

Edit: Cleaned up the code based on suggestions from @Simon Hänisch

Itself
  • 75
  • 1
  • 7
  • I realized that in my case, setting the property directly like this works: `html: ''` However I'm still unclear on how to use template to set properties, and how best to test that the component gets the given properties. – Itself Mar 16 '21 at 09:58
  • The key concept I had not understood before Simon's answer was that the spec file should be tsx, which would the allow it to work with template, as you describe. Cheers! – Itself Mar 19 '21 at 13:29

1 Answers1

7

Your template is returning a string, not JSX. You basically get a document with <badge skin=secondary></badge> as a string in it, not an actual badge element.

BTW badge is not a valid custom element name, it needs to have a dash (-) in its name. There are also syntax errors in your example code, like your component should

return (
  <span class={`skin-${this.skin}`} />
)

(back ticks for the class string were missing and the tag wasn't closed)

Assuming that all this is just mistakes when writing this question and you actually have a line with newSpecPage in your code (that's also missing here), here's what you need to do:

  1. Change the extension of your spec test file to .tsx.
  2. Add import { h } from '@stencil/core';.
  3. Write some actual JSX as the return value of your template.
import { h } from '@stencil/core';
import { newSpecPage } from '@stencil/core/testing';
import { MyBadge } from './my-badge';

it('should have "secondary" skin', async () => {
  const page = newSpecPage({
    components: [MyBadge],
    template: () => <my-badge skin="secondary" />,
  });

  expect(page.root).toEqualHtml('<span class="skin-secondary"></span>');
});

You can't use both options template and html at the same time (or at least it doesn't make sense, I'm not sure which one will take precedence), because they are different ways of setting the content for the page. If you use template, you can directly use JSX syntax to bind any kind of value to props etc. If you use html, it has to be a string with the html content of your page, and in that case you can only bind string values to props.

If you wanted to use html in your example instead, it would need to be

const page = newSpecPage({
  components: [MyBadge],
  html: `<my-badge skin="secondary"></my-badge>`,
});

I don't think you can use the self-closing syntax in this case because it's not valid for custom elements, see this answer.

Simon Hänisch
  • 4,740
  • 2
  • 30
  • 42
  • Thank you Simon, for this very well written and thoughtful answer. I will improve my question syntax based on your feedback, and try again with the template in the code. – Itself Mar 19 '21 at 13:17
  • I really should have read this more conscientiously: !!! 1. Change the extension of your spec test file to .tsx. !!! This almost drove me crazy for an hour or two. Thanks!! – Zaphoid Mar 01 '23 at 20:57