Svelte-тестирование: реактивный оператор не обновляется с помощью jest.advanceTimersByTime()
Я хочу протестировать некоторый код Svelte, обновленный с помощью
setInterval
Перезвони. Я использую реактивный оператор следующим образом (logThem
используется только в тестовых целях):
<script>
import { onDestroy } from 'svelte';
export let logThem = (count, remaining) => console.log(`count=${count} || remaining=${remaining}`);
const NB_OF_SECONDS = 5;
let count = 0;
$: remaining = NB_OF_SECONDS - count;
const increment = () => {
count++;
logThem(count, remaining);
if (remaining === 1) {
clearInterval(interval);
}
};
const interval = setInterval(increment, 1000);
onDestroy(() => {
clearInterval(interval);
});
</script>
<h1>Timer of 5 sec.</h1>
<p>
{#if remaining }
Time remaining: {remaining} sec.
{:else}
Time's up.
{/if}
</p>
При тестировании в браузере все работает нормально, получаю такие логи:
count=1 || remaining=5
count=2 || remaining=4
count=3 || remaining=3
count=4 || remaining=2
count=5 || remaining=1
Проблема в том, что я не могу выполнить следующие тесты:
import { render } from "@testing-library/svelte";
import App from "./App.svelte";
const logThemIn = (context) => jest.fn((count, remaining) => {
console.log(`[${context}] count=${count} || remaining=${remaining}`);
});
describe("App", () => {
beforeEach(() => {
jest.useFakeTimers();
});
it("should render count down -- using testing library", () => {
const logThem = logThemIn('Testing Library');
const { container } = render(App, { props: { logThem } });
expect(container).toContainHTML("Time remaining: 5 sec.");
expect(setInterval).toHaveBeenCalledTimes(1);
expect(setInterval).toHaveBeenLastCalledWith(expect.any(Function), 1000);
jest.advanceTimersByTime(5000);
expect(logThem).toHaveBeenCalledTimes(5);
const fifthCall = logThem.mock.calls[4];
const count = fifthCall[0];
const remaining = fifthCall[1];
expect(count).toEqual(5);
expect(remaining).toEqual(1);
});
});
Результат:
● App › should render count down -- using testing library
expect(received).toEqual(expected) // deep equality
Expected: 1
Received: 5
24 | const remaining = fifthCall[1];
25 | expect(count).toEqual(5);
> 26 | expect(remaining).toEqual(1);
| ^
27 | });
at Object.<anonymous> (App.spec.js:26:23)
Что значит:
- В
setInterval
на самом деле был назван - В
increment
функция действительно правильно вызывалась 5 раз - Тем не менее
remaining
переменная не обновляется...
Я проверил скомпилированный код (в
bundle.js
) и функция увеличения делает недействительным
count
:
const increment = () => {
$$invalidate(2, count++, count);
logThem(count, remaining);
if (remaining === 1) {
clearInterval(interval);
}
};
Так же
update()
процесс аннулирует
remaining
когда
count
"пачкается":
$$self.$$.update = () => {
if ($$self.$$.dirty & /*count*/ 4) {
$$invalidate(0, remaining = NB_OF_SECONDS - count);
}
};
Код находится в следующем репо: https://github.com/gcruchon/tests/tree/main/svelte-timer
Что я делаю неправильно в своем тесте? Любая помощь будет принята с благодарностью:)