When writing a unittest for Svelte 5 Class/Function that uses an $effect rune (with vitest) I am currently doing the $effect()
within a $effect.root()
. Otherwise I would get the following error (If there is a better way please let me know):
svelte error: effect_orphan
`$effect` can only be used inside an effect (e.g. during component initialisation)
at Module.effect_orphan
But this results in not destroying the $effect()
at the end of an unittest. The following example demonstrates this as it outputs "T1" twice:
let cntr = $state(1);
describe('effect test', () => {
test('test1', () => {
$effect.root(() => {
$effect(() => {
console.log('T1', cntr);
});
});
cntr += 1;
});
test('test2', () => {
$effect.root(() => {
$effect(() => {
console.log('T2', cntr);
});
});
cntr += 1;
});
});
the output is:
T1 2
T2 3
T1 3 <- how can I avoid that T1 still exists (and outputs data)?
$effect.root
returns a cleanup function. Call this at the end of the test.
E.g.
describe('effect test', () => {
let cleanup;
afterEach(() => cleanup?.());
test('test1', () => {
cleanup = $effect.root(() => {
// ...
});
cntr += 1;
});
});
Or on a single test:
test('test1', context => {
const cleanup = $effect.root(() => {
// ...
});
context.onTestFinished(() => cleanup());
cntr += 1;
});
(Using functions like afterEach
and onTestFinished
should ensure that the cleanup happens, even if an exception is thrown somewhere in the test.)