Svelte-тестирование: реактивный оператор не обновляется с помощью jest.advanceTimersByTime()

Я хочу протестировать некоторый код Svelte, обновленный с помощью setIntervalПерезвони. Я использую реактивный оператор следующим образом (logThem используется только в тестовых целях):

App.svelte:

<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

Проблема в том, что я не могу выполнить следующие тесты:

App.spec.js:

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

Что я делаю неправильно в своем тесте? Любая помощь будет принята с благодарностью:)

0 ответов

Другие вопросы по тегам