Skip to content

Test Svelte Component Slot Using svelte-htm

Mar 1, 2023 · 3 min read

This is a short guide on how to test a Svelte component with slot using the svelte-htm library.

Introduction

At the time of writing this article, there’s no way to pass in slot content to Svelte component using svelte-testing-library.

The workaround for this is usually by creating a separate dummy component that put some elements inside the slot and test the dummy component instead.

For example, say that we have a Button.svelte component.

<button>
<slot />
</button>

To test if the component inside the slot is rendered properly, we have to create a dummy component that use Button.svelte. We’ll call this component TestButton.svelte.

TestButton.svelte
<script>
import Button from ./Button.svelte;
</script>
<Button>
<div data-testid="slot-component">PLACEHOLDER</div>
</Button>

Finally, we can test the component.

// Other imports
import TestButton from "./TestButton.svelte";
describe("Button", () => {
it("should render component inside slot properly", () => {
render(TestButton);
expect(screen.getByTestId("slot-component")).toBeInTheDocument();
});
});

That works, but it’s certainly not a fun experience, and your project is probably going to be littered by bunches of dummy component.

Solution

The solution to this problem is to use svelte-htm.

svelte-htm allows us to write our Svelte components with JSX-like syntax. It completely eliminates our need of dummy component. We can test our Svelte component just like how we test components from JSX-based framework like React.

Now, let’s refactor our test using svelte-htm.

// Other imports
import html from `svelte-htm`;
import Button from './Button.svelte'
describe("Button", () => {
it("should render component inside slot properly", () => {
render(html`
<${Button}>
<div data-testid="slot-component">PLACEHOLDER</div>
</${Button}>
`);
expect(screen.getByTestId("slot-component")).toBeInTheDocument();
});
});

That’s all we need to do. Felt much more natural, right?

You might think that the syntax is still not as nice as testing JSX component, but it’s pretty close, and I would consider this solution a major leap compared to the dummy component solution.

In case you’re wondering how the test would look like for JSX component:

// Other imports
import Button from "./Button.tsx";
describe("Button", () => {
it("should render component inside slot properly", () => {
render(
<Button>
<div data-testid="slot-component">PLACEHOLDER</div>
</Button>,
);
expect(screen.getByTestId("slot-component")).toBeInTheDocument();
});
});

Testing Named Slot

We can test named slot just like how we test normal slot in the examples above.

Here is an example:

Let’s change our Button.svelte component to use named slot.

<button>
<div>
<slot name="icon" />
</div>
<div>
<slot name="label" />
</div>
</button>

Now, to test it:

// Other imports
import html from `svelte-htm`;
import Button from './Button.svelte'
describe("Button", () => {
it("should render component inside slot properly", () => {
render(html`
<${Button}>
<div slot="icon">ICON</div>
<div slot="label">Click me!</div>
</${Button}>
`);
// assertions here ...
});
});

You get the idea :)

Wrap Up

That’s it for this post. You should be able to test your Svelte components that have slot now. Happy testing!