Here’s how Zustand’s test-case uses ErrorBoundary.

DDD
풀어 주다: 2024-09-18 11:45:32
원래의
532명이 탐색했습니다.

In this article, we will analyze ErrorBoundary class component in Zustand’s test case. Error handling is a crucial part of any React application.

Here’s how Zustand’s test-case uses ErrorBoundary.

Overview of the Test Case

Here’s the test case we’ll be exploring:

// Picked from https://github.com/pmndrs/zustand/blob/v4.5.5/tests/basic.test.tsx#L378
it('can throw an error in equality checker', async () => {
  console.error = vi.fn()
  type State = { value: string | number }

  const initialState: State = { value: 'foo' }
  const useBoundStore = createWithEqualityFn(() => initialState, Object.is)
  const { setState } = useBoundStore
  const selector = (s: State) => s
  const equalityFn = (a: State, b: State) =>
    // @ts-expect-error This function is supposed to throw an error
    a.value.trim() === b.value.trim()

  class ErrorBoundary extends ClassComponent<
    { children?: ReactNode | undefined },
    { hasError: boolean }
  > {
    constructor(props: { children?: ReactNode | undefined }) {
      super(props)
      this.state = { hasError: false }
    }
    static getDerivedStateFromError() {
      return { hasError: true }
    }
    render() {
      return this.state.hasError ? <div>errored</div> : this.props.children
    }
  }

  function Component() {
    useBoundStore(selector, equalityFn)
    return <div>no error</div>
  }

  const { findByText } = render(
    <StrictMode>
      <ErrorBoundary>
        <Component />
      </ErrorBoundary>
    </StrictMode>,
  )
  await findByText('no error')

  act(() => {
    setState({ value: 123 })
  })
  await findByText('errored')
})
로그인 후 복사

This test verifies that when an error occurs inside an equality checker, the error is caught and handled gracefully by an ErrorBoundary component.

Key Concepts in the Test Case

1. Zustand’s createWithEqualityFn

Zustand allows you to define stores with custom equality functions using createWithEqualityFn. In this test, the initial state is defined as:

const initialState: State = { value: 'foo' }
로그인 후 복사

The createWithEqualityFn function is used to create a store where the equality function is defined to compare states based on whether the value property is equal. In this case, the equality checker is intentionally set to throw an error when value is of a type other than string:

You can intentionally throw errors in your test cases to ensure your code handles errors as expected.

const equalityFn = (a: State, b: State) =>
  a.value.trim() === b.value.trim() // Throws error if 'value' is not a string
로그인 후 복사

The test case expects this equality function to fail when value becomes a number, causing the error handler to come into play.

2. Custom ErrorBoundary Component

React’s ErrorBoundary component is a common pattern used to catch JavaScript errors in a component tree, and Zustand has taken this approach to test how errors within their state management are handled. This particular test case defines a custom ErrorBoundary component directly inside the test. I mean, how often do you come across a test case that has the custom ErrorBoundary with in a “test case”?

class ErrorBoundary extends ClassComponent<
    { children?: ReactNode | undefined },
    { hasError: boolean }
  > {
    constructor(props: { children?: ReactNode | undefined }) {
      super(props)
      this.state = { hasError: false }
    }
    static getDerivedStateFromError() {
      return { hasError: true }
    }
    render() {
      return this.state.hasError ? <div>errored</div> : this.props.children
    }
  }
로그인 후 복사

How it works:

  • The component uses the lifecycle method getDerivedStateFromError() to catch errors and update its state (hasError) to true.

  • If an error is detected, the component renders

    errored
    . Otherwise, it renders its children.

In typical production use, ErrorBoundary components are created as reusable elements to catch and display errors across the application. However, embedding the ErrorBoundary directly inside a test case like this provides fine-grained control over error testing, allowing you to assert that the component reacts correctly when errors occur in specific parts of the application.

3. Testing Error Handling with Vitest

In this test case, Vitest is used as the testing framework. Here’s how it works with Zustand:

  • Rendering the Component: The Component that uses the useBoundStore hook is rendered inside the ErrorBoundary within a React StrictMode block. This ensures that errors inside the equality checker can be caught.
const { findByText } = render(
    <StrictMode>
      <ErrorBoundary>
        <Component />
      </ErrorBoundary>
    </StrictMode>,
  )
  await findByText('no error')
로그인 후 복사
  • At this point, the test verifies that no error has been thrown yet and checks for the text no error.

  • Triggering the Error: After the component is initially rendered without errors, the test triggers an error by updating the store’s state to a number:

act(() => {   setState({ value: 123 }) })
로그인 후 복사
  • This causes the equality function to throw an error, as value.trim() is no longer valid for a number type.

  • Asserting the Error Handling: Once the error is thrown, the ErrorBoundary catches it, and the test waits for the UI to render the errored message:

await findByText('errored')
로그인 후 복사
  • This assertion confirms that the error was properly caught and displayed by the ErrorBoundary

Why This Approach is Unique

What makes this test case particularly interesting is the use of an inline ErrorBoundary component within a unit test. Typically, error boundaries are part of the main React app, wrapping components in the main render tree. However, Zustand's approach to create an error boundary in the test suite itself offers a more flexible and isolated way to test how errors are handled under specific conditions.

By directly controlling the boundary within the test, Zustand ensures:

  1. Granularity: The test can focus on how errors in a particular part of the application (like the equality checker) are handled, without needing to rely on global error boundaries.

  2. Test Isolation: The ErrorBoundary exists only within the scope of this test, reducing potential side effects or dependencies on the app’s broader error-handling logic.

About us:

At Think Throo, we are on a mission to teach the advanced codebase architectural concepts used in open-source projects.

10x your coding skills by practising advanced architectural concepts in Next.js/React, learn the best practices and build production-grade projects.

We are open source — https://github.com/thinkthroo/thinkthroo (Do give us a star!)

Up skill your team with our advanced courses based on codebase architecture. Reach out to us at hello@thinkthroo.com to learn more!

References:

  1. https://github.com/pmndrs/zustand/blob/v4.5.5/tests/basic.test.tsx#L378



위 내용은 Here’s how Zustand’s test-case uses ErrorBoundary.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!