svelte-testing-library
svelte-testing-library copied to clipboard
Testing slots?
Perhaps this is more svelte API question, but it's not clear how to test component slots, for example:
Badge.svelte:
<span class="badge">
<slot />
</span>
Badge.spec.js:
describe('Badge', () => {
test('should render text', () => {
// Where to pass child text?
const { container } = render(Badge, { props: { color: 'primary' } });
});
});
Looking for default slots primarily, and do not want to add props for this.
Yes it's more a svelte API question that should be redirected to their repository.
Anyway:
import Button from './Button.svelte';
const { container } = render(Badge, { props: { color: 'primary' }, slots: { default: Button } });
afaik is still wip, there's no way to declare slots from the Component API, see:
- https://github.com/sveltejs/svelte/issues/2588
- https://github.com/sveltejs/svelte/pull/2684
we could patch the workaround until it is merged to the main api, what do you think?
something like:
import Badge from './Badge.svelte';
import Button from './Button.svelte';
const { container } = render(
Badge,
{ props: { color: 'primary' } }, // component props
{ slots: { default: Button } } // component ctx
);
ping @benmonro @EmilTholin
2684 looks like it would work and I'm of the opinion that we should wait for that to be merged but I'll defer to @EmilTholin
I agree with the rest of you that it's a Svelte API issue and that 2684 will resolve it.
In the meantime you could do the less than ideal solution of creating a test-specific component that renders Badge
with a Button
child component.
<!-- TestBadgeSlot.svelte -->
<Badge>
<Button />
</Badge>
// Badge.test.js
import TestBadgeSlot from './TestBadgeSlot.svelte';
const { container } = render(
TestBadgeSlot,
{ props: { color: 'primary' } }
);
Thanks for the info, I'll wait until sveltejs/svelte#2684 is merged.
Feel free to close this if you prefer, or open if you'd like to track status.
If by chance it's not merged for some reason a patch in this lib would be very useful 🙏
Closing for now not feel free to reopen if that doesn't get merged in svelte
The mentioned issue (sveltejs/svelte#268) has been closed in favor of another refactoring in the svelte repo (which is still open!). Are there any news on how slots can be tested?
the new pr to svelte api is still open: https://github.com/sveltejs/svelte/pull/4296
this suggestion still stands: https://github.com/testing-library/svelte-testing-library/issues/48#issuecomment-522029988
If it helps, I worked around this by adding an optional children
prop ala React:
https://github.com/bestguy/sveltestrap/blob/master/src/Alert.svelte#L37
that will conditionally render the slot unless children
is passed.
Allows testing like: https://github.com/bestguy/sveltestrap/blob/master/src/test/Alert.spec.js#L8
Not perfect 🤷♂️ but helps until there is a better option
wait for the pr merged.
Still actual.
Should this be reopened until https://github.com/sveltejs/svelte/pull/4296 is merged?
It has been a year with no movement on that svelte PR. Can we open this again?
Sure
FWIW I discovered this library recently: https://github.com/DockYard/svelte-inline-compile which I am now using in svelte-headlessui. I think something like this library seems to me to be the nicest way of dealing with this, though it's not perfect.
@rgossiaux @akolyte01 I am one of the developers of https://github.com/DockYard/svelte-inline-compile. This week we plan to make it work for Vitest, a new trending test runner better suited for sveltekit apps than jest. We are working with the core team to make the testing experience nicer out of the box. But it will remain usable in jest. The current syntax makes almost impossible to test slots and multiple components cooperating among them.
For whoever is interested, we've released two packages that make testing components much nicer than the current state of things in Jest. It is similar to https://github.com/DockYard/svelte-inline-compile but less complicated internally and with less drawbacks.
Right now the experience of testing components that take slots, actions or that must interact with other components was pretty bad. Essentially the only way was to create a on-off component in the test folder that used your component in the way you wanted and render that component instead.
Our package https://github.com/dockyard/svelte-inline-component allows to define components inline in the test itself. This is an example using sveltekit/vitest and this package:
import { render } from '@testing-library/svelte'
import { svelte } from 'svelte-inline-component';
describe('DefinitionEntry.svelte', () => {
it('renders a link with the given href', async () => {
const { getByTestId } = render(await svelte`
<script>import DefinitionEntry from '$lib/DefinitionEntry.svelte';</script>
<DefinitionEntry background="gray">
<svelte:fragment slot="dt">I'm the description term</svelte:fragment>
<svelte:fragment slot="dd">I'm the description definition</svelte:fragment>
</DefinitionEntry>
`);
expect(getByTestId('definition-entry')).to.have.class('bg-gray-50');
expect(getByTestId('dt')).to.have.text("I'm the description term");
expect(getByTestId('dd')).to.have.text("I'm the description definition");
});
});
I'm biased but IMO it is SO. MUCH. NICER to invoke components in tests with the same syntax you use in regular app code that I can't go back.
There are some downsides that we're working on to polish, like publishing VSCode plugin that enables svelte syntax and intellisense inside the strings for better developer experience. But it's very functional.
@cibernox I agree that is nice. feel free to update the testing-library.com docs to list this as an alternative, that will help raise awareness of your library too
@benmonro I'll take a look. I'm not sure how to frame it within the docs of testing-library, because right now there's a lot of "if"s. Namely, that your app must use vitest, which is, as their own documentation takes great care of explaining, not production ready (although in my opinion, neither is jest and yet everyone uses it).
I would frame it just like that, maybe put a yellow warning at the top stating this is still early in development. But in my opinion, it's totally fine to offer alternative runners/environments. Additionally, you could also put it in the 'ecosystem' section and maybe just link to it there.
How are we currently supposed to test something that is like this currently? It just doesn't work. The Layout component takes a slot ands obviously this library doesn't support that, right? Is the workaround to use something like svelte-inline-compile?
ParentComponent.svelte
<div
class="position"
in:fade={{ duration: 200 }}
out:fade|local={{ duration: 200 }}
>
<div
class="feedback-frame"
in:fly={{ y: 30, duration: 200 }}
out:fly|local={{ y: 30, duration: 200 }}
>
<div class="close">
<ClearButton on:click={cancelFeedback} />
</div>
<Layout gap="XS">
{#if step === 0}
<div class="ratings">
{#each ratings as number}
<ActionButton
size="L"
emphasized
selected={number === rating}
on:click={() => (step = 1)}
>
{number}
</ActionButton>
{/each}
</div>
{:else if step === 1}
<Heading size="XS">What could be improved most in Budibase?</Heading>
<Divider />
<RadioGroup bind:value={improvements} {options} />
<div class="footer">
<Detail size="S">STEP 2 OF 3</Detail>
<ButtonGroup>
<Button secondary on:click={() => (step -= 1)}>Previous</Button>
<Button primary on:click={() => (step += 1)}>Next</Button>
</ButtonGroup>
</div>
{/if}
</Layout>
</div>
</div>
Layout.svelte
<div
style="align-content:{alignContent};justify-items:{justifyItems};"
class:horizontal
class="container paddingX-{!noPadding && paddingX} paddingY-{!noPadding &&
paddingY} gap-{!noGap && gap}"
>
<slot />
</div>
Any news on this?
For whoever is interested, we've released two packages that make testing components much nicer than the current state of things in Jest. It is similar to https://github.com/DockYard/svelte-inline-compile but less complicated internally and with less drawbacks.
This is great, thank you for your efforts with the library @cibernox - it would be amazing if the render()
function would natively support taking Svelte inline components as an argument. In the React world, I've written so many tests using the same approach (using jSX) and I couldn't go without it:
render(<Button>Click me</Button>)
I'm currently using svelte-htm and it works well 👍
I'm currently using svelte-htm and it works well 👍
@ivanhofer Can you share how you use svelte-htm
?
This error pops out when I try to pass component to the html template literals:
render(html`<${MyComponent} //>`)
TypeError: Cannot read properties of undefined (reading '$$')
It seems this issue hasn't been addressed https://github.com/sveltejs/svelte/issues/6584
@davipon it worked fine until we upgraded our dependencies a few weeks back.
Now we use patch-package
to work around the issue.
Changing parent_component.$$.root
to parent_component?.$$.root
will not have any side effects when running an application normally, but fixex the tests.
@davipon that looks like an issue in https://github.com/kenoxa/svelte-htm. I filed an issue there to see if the author can resolve it: https://github.com/kenoxa/svelte-htm/issues/234
@benmccann Thank you for your input. I'll dive into the issue and see how I can help to resolve that.
Any news on this? svelte-htm
does not support Svelte 4 https://github.com/kenoxa/svelte-htm/issues/269
How do you test slots
?
same as looking for new solution for sveltev4