Testing bindable properties in Svelte 5
I was recently working on a Svelte (5) component that was using a $bindable
property. When it came to writing a test for it, I got stuck on how to bind said property to a variable in my test module.
Suppose the component looks like this:
<script>
const { count = $bindable() } = props();
</script>
<button onclick={() => count = count + 1}>Click</button>
From another component you would call it like this:
<script>
let myCounter = $state(0):
</script>
<CountButton bind:count={myCounter}/>
<p>Count is {myCounter}</p>
But from a test:
it('updates the bound counter', async () => {
let boundCounter = 0;
const { container } = render(CountButton, {
props: {
counter: boundCounter // this is not bound and you can’t use bind:counter here
}
});
const button = container.querySelector('button'):
button.dispatchEvent(new Event('click'));
expect(boundCounter).toBe(1); // nope, still 0
});
There is a very simple solution to this problem. I could not find it in the docs nor on the Internet. Neither could any AI help me out.
What I ended up doing is checking out the compiled code of the parent component above. If you have installed Svelte plugins in for example VS Code, there is a button in the top right corner to see it.
And this is what bound properties get compiled to:
it('updates the bound counter', async () => {
let boundCounter = 0;
const { container } = render(CountButton, {
props: {
// simulate bind:count
get count() {
return boundCounter;
},
set count(value) {
boundCounter = value;
}
}
});
const button = container.querySelector('button'):
button.dispatchEvent(new Event('click'));
expect(boundCounter).toBe(1); // works
});
A getter and a setter! Of course!
And this is how you can test bound properties. And any other “magic” code.
Comments