Svelte testing library won't detect component updates

938 views Asked by At

My component:

<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>

test code:

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();
  });
});

mock file (__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;

Jest config at <project root>/jest.config.js:

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']
};

If I print the component state by console.log(render(...).component), it prints that loggedIn state is correctly set as 'yes' and 'no' in each case. But the actual render result obtained by render(...).container.innerHTML, nothing's updated.

Plus the Jest output prints a weird error:

    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)

If I try "printing" loggedIn's value to HTML output, like

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

The output says loggedIn is 'yes' or 'no', but the if branches don't just seem to work.

Is there anything I'm doing wrong? Thanks in advance.

1

There are 1 answers

1
wooseop On

Using components from carbon-components-svelte seems to be the reason. I made them get injected via slots, so that during the test no Carbon components were actually rendered or even imported. Now tests are running okay.