Svelte 测试库不会检测组件更新

问题描述

我的组件:

<script lang="ts">
  import { Button } from 'carbon-components-svelte';
  import firebase from 'firebase/app';
  import { auth } from '../../firebase-shortcut';
  import AuthButton from '../auth/AuthButton.svelte';

  let loggedIn: 'loading' | 'yes' | 'no' = 'loading';
  let userName: string;
  auth.onAuthStateChanged((x) => {
    loggedIn = Boolean(x) ? 'yes' : 'no';
    if (x) {
      userName = x.displayName;
    };
  })

  const googleProvider = {
    instance: new firebase.auth.GoogleAuthProvider(),name: 'Google'
  };
</script>

<section>
  <div>
    {#if loggedIn === 'yes'}
      <Button as let:props kind="secondary">
        <span {...props}>{userName}</span>
      </Button>
    {:else if loggedIn === 'no'}
      <AuthButton provider={googleProvider} />
    {:else}<!-- loggedIn === 'loading' -->
      <Button skeleton aria-busy="true" />
    {/if}
  </div>
</section>

测试代码

import Toolbar from './Toolbar.svelte';
import { render,act } from '@testing-library/svelte';

jest.mock('../../firebase-shortcut');
const { __setAuthState } = require('../../firebase-shortcut');

describe('Toolbar',() => {
  it('should render loader',() => {
    const { queryByText } = render(Toolbar);

    const result = queryByText('로딩...');
    expect(result).toBeTruthy();
  });

  it('should render user when signed in',async () => {
    const displayName = '우섭';
    const { queryByText } = render(Toolbar);

    __setAuthState({ displayName });
    await act();

    const result = queryByText(displayName);
    expect(result).toBeTruthy();
  });

  it('should render button when not signed in',async () => {
    const { queryByRole } = render(Toolbar);

    __setAuthState(null);
    await act();

    const result = queryByRole('button');
    expect(result).toBeTruthy();
  });
});

模拟文件__mocks__/firebase-shortcut.ts):

import type firebase from 'firebase/app';

const mocked = jest.createMockFromModule('./firebase-shortcut') as any;

let onAuthStateChanged: (x: Partial<firebase.User>) => void;
mocked.auth = {
  onAuthStateChanged: (f: (x: firebase.User) => void) => {
    onAuthStateChanged = f;
  },};
mocked.__setAuthState = (x: Partial<firebase.User>) => {
  onAuthStateChanged && onAuthStateChanged(x);
};

module.exports = mocked;

<project root>/jest.config.js 处的 Jest 配置:

module.exports = {
  preset: 'ts-jest',transform: {
    '^.+\\.svelte$': ['svelte-jester',{ preprocess: true }],'^.+\\.ts$': 'ts-jest',},setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'],modulefileExtensions: ['js','ts','svelte']
};

如果我通过 console.log(render(...).component) 打印组件状态,它会打印 loggedIn 状态在每种情况下都正确设置为 'yes''no'。但是render(...).container.innerHTML得到的实际渲染结果,什么都没有更新。

加上 Jest 输出打印一个奇怪的错误

    TypeError: Cannot read property 'd' of undefined



      at Object.destroy [as d] (src/components/toolbar/Toolbar.svelte:296:40)
      at destroy_component (node_modules/svelte/internal/index.js:1434:36)
      at Toolbar.$destroy (node_modules/svelte/internal/index.js:1552:9)
      at Toolbar.$destroy (node_modules/svelte/internal/index.js:1665:15)
      at cleanupAtContainer (node_modules/@testing-library/svelte/dist/pure.js:116:48)
          at Array.forEach (<anonymous>)
      at cleanup (node_modules/@testing-library/svelte/dist/pure.js:126:37)
      at Object.<anonymous>.afterEach (node_modules/@testing-library/svelte/dist/index.js:27:23)

如果我尝试将 loggedIn 的值“打印”到 HTML 输出,例如

<section>
...
    {loggedIn}
    {#if loggedIn === 'yes'}
...

输出显示 loggedIn 是“是”或“否”,但 if 分支似乎不只是工作。

我做错了什么吗?提前致谢。

解决方法

使用来自 carbon-components-svelte 的组件似乎是原因。我让它们通过 slot 注入,​​因此在测试期间没有实际渲染甚至导入 Carbon 组件。现在测试运行正常。