You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jest结合TS复用Storybook故事时报id属性类型不兼容错误

问题现象

使用Jest + React Testing Library复用Storybook故事编写单元测试时,向渲染的故事传入故事中预定义的args参数,抛出Types of property 'id' are incompatible类型错误。

相关依赖版本
"@storybook/react": "^6.5.9",
"@storybook/testing-react": "^1.2.4",
"@testing-library/react": "^13.3.0",
"jest": "^28.1.1",
// 其余依赖省略
问题相关代码

测试文件代码

报错位置为render(<Checkbox {...Checkbox.args} />)行。

import * as React from 'react';
import { screen, render } from '@testing-library/react';

import { Default as Checkbox } from '../../stories/AccountCheckbox.stories';

const renderCheckbox = () => {
  render(<Checkbox {...Checkbox.args} />); // 类型报错抛出位置
}

describe('<AccountCheckbox />', () => {
  test('should display account information', () => {
    renderCheckbox();

    expect(screen.getByTestId('example-test-id')).toBeInTheDocument();
  });
});

Story文件代码

import React from 'react';
import { ComponentMeta, ComponentStory } from '@storybook/react';

import AccountCheckbox from '../components/AccountCheckbox';
import { StoryAppWrapper } from '../../.storybook/wrapper/StoryAppWrapper';

export default {
  title: 'AccountCheckbox',
  component: AccountCheckbox,
  decorators: [(Story) => <StoryAppWrapper>{Story()}</StoryAppWrapper>]
} as ComponentMeta<typeof AccountCheckbox>;

const Template: ComponentStory<typeof AccountCheckbox> = (args) => (
  <AccountCheckbox {...args} />
);

export const Default = Template.bind({});

Default.args = {
  id: 'example-id',
  testId: 'example-test-id',
  label: 'Account 1',
  selected: false,
  onChange: () => { },
};

组件类型定义

export type CheckboxProps = {
  id: string;
  testId: string;
  label: string;
  selected: boolean;
  onChange: any;
};

组件实现代码

import * as React from 'react';
import { Checkbox } from 'custom-lib';

import { CheckboxProps } from '../../types/types';

const AccountCheckbox = ({
  id,
  testId,
  label,
  selected,
  onChange,
}: CheckboxProps): JSX.Element => {
  return (
    <Checkbox
      id={id}
      data-testid={testId}
      label={label}
      state={selected ? 'true' : 'false'}
      onChange={onChange}
    />
  );
};

export default AccountCheckbox;
报错根因

类型错误来自错误的Story渲染写法,核心问题有两点:

  • 类型不匹配:直接从stories文件导入的Default是Storybook内部封装的Story函数,它的Props类型除了业务组件的CheckboxProps,还包含Storybook注入的上下文属性(比如故事唯一标识id、渲染上下文参数等)。手动展开Checkbox.args传入时,TypeScript会将业务定义的id: string和Story上下文内置的id属性做类型校验,两者类型定义不兼容直接抛出错误。
  • 逻辑缺失:手动渲染原始Story对象、手动传args的写法,会跳过@storybook/testing-react的自动处理逻辑,包括全局/故事级装饰器(比如代码中配置的StoryAppWrapper包装器)、默认args合并、参数类型对齐等,就算绕过类型校验,运行时也大概率因为缺少上下文出现渲染异常。
修复方案

使用@storybook/testing-react官方提供的composeStories工具处理导入的Story对象,工具会自动完成类型对齐、装饰器包装、args绑定,不需要手动展开args。
修复后的测试文件代码如下:

import * as React from 'react';
import { screen, render } from '@testing-library/react';
// 引入官方Story处理工具
import { composeStories } from '@storybook/testing-react';
// 导入stories文件的所有导出
import * as CheckboxStories from '../../stories/AccountCheckbox.stories';

// 处理所有故事,自动完成类型转换、装饰器绑定、args注入
const { Default: Checkbox } = composeStories(CheckboxStories);

const renderCheckbox = () => {
  // 直接渲染处理后的Story即可,默认自动带入Default.args配置
  render(<Checkbox />);
  // 若需要覆盖默认args,直接作为props传入即可,类型会自动和CheckboxProps对齐
  // 例:render(<Checkbox testId="overwritten-test-id" />)
}

describe('<AccountCheckbox />', () => {
  test('should display account information', () => {
    renderCheckbox();
    expect(screen.getByTestId('example-test-id')).toBeInTheDocument();
  });
});

内容的提问来源于stack exchange,提问作者Hyun Jae Lee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 18:57:21