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
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:
.tsx
.import { h } from '@stencil/core';
.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.