如何为InputSelect组件实现100%测试覆盖率?
实现InputSelect组件100%测试覆盖率的问题
问题说明
我在项目中用@storybook/testing-library和@storybook/jest测试InputSelect组件,测试用例全部通过,但代码覆盖率没到100%——第32行的(({ options, testId, ...rest }, ref) =>未被覆盖。已经测试了空选项、选项渲染、选项选择场景,还是没解决。
组件代码
export const InputSelect: FC<InputSelectProps> = forwardRef< InputSelectProps, HTMLSelectElement >(({ options, testId, ...rest }, ref) => isEmptyNode(options) ? null : ( <Select data-testid={testId} {...rest} ref={ref}> {options?.map((o) => ( <option key={o.value} value={o.value}> {o.children || o.value} </option> ))} </Select> ) );
现有测试用例
export const Default: Story = { parameters: { controls: { exclude: ['value', 'rootProps', 'testId', 'aria-errormessage'], }, }, args: { options: [ { value: 'option1', children: 'Select1' }, { value: 'option2', children: 'Select2' }, { value: 'option3', children: 'Select3' }, { value: 'option4', children: 'Select4' }, { value: 'option5', children: 'Select5' }, ], }, render: (args) => ( <> <InputSelect {...args} /> </> ), }; export const Tests: Story = { parameters: { controls: { exclude: ['value', 'rootProps', 'testId', 'aria-errormessage'], }, }, args: { ...Default.args, }, render: (args) => ( <> <InputSelect {...args} testId={'with-options'} /> <InputSelect {...args} options={[]} testId={'without-options'} /> </> ), play: async ({ args, canvasElement, step }) => { const canvas = within(canvasElement); const selectElement = canvas.queryByTestId( 'with-options' ) as HTMLSelectElement; await step('The component only renders if it has options', async () => { await expect(selectElement).toBeTruthy(); await expect(canvas.queryByTestId('without-options')).toBeFalsy(); const renderedOptions = within(selectElement).queryAllByRole('option'); expect(renderedOptions).toHaveLength(args.options?.length); }); await step('select options correctly', async () => { userEvent.selectOptions(selectElement, 'Select1'); expect(selectElement.value).toBe('option1'); userEvent.selectOptions(selectElement, 'Select2'); expect(selectElement.value).toBe('option2'); userEvent.selectOptions(selectElement, 'Select3'); expect(selectElement.value).toBe('option3'); userEvent.selectOptions(selectElement, 'Select4'); expect(selectElement.value).toBe('option4'); userEvent.selectOptions(selectElement, 'Select5'); expect(selectElement.value).toBe('option5'); }); }, };
解决方案
未覆盖的代码本质是三个场景没测到:ref参数的传递、options为null/undefined的情况、...rest额外props的传递。
1. 补充关键场景测试
修改Tests story,添加未覆盖场景的实例和测试步骤:
export const Tests: Story = { parameters: { controls: { exclude: ['value', 'rootProps', 'testId', 'aria-errormessage'], }, }, args: { ...Default.args, disabled: true, // 新增额外props用于测试 }, render: (args) => { const testRef = React.createRef<HTMLSelectElement>(); return ( <> <InputSelect {...args} testId={'with-options'} /> <InputSelect {...args} options={[]} testId={'without-options'} /> <InputSelect {...args} ref={testRef} testId={'with-ref'} /> {/* 测试ref传递 */} <InputSelect {...args} options={null} testId={'options-null'} /> {/* 测试options为null */} <InputSelect {...args} options={undefined} testId={'options-undefined'} /> {/* 测试options为undefined */} </> ); }, play: async ({ args, canvasElement, step }) => { const canvas = within(canvasElement); const selectElement = canvas.queryByTestId( 'with-options' ) as HTMLSelectElement; await step('The component only renders if it has options', async () => { await expect(selectElement).toBeTruthy(); await expect(canvas.queryByTestId('without-options')).toBeFalsy(); const renderedOptions = within(selectElement).queryAllByRole('option'); expect(renderedOptions).toHaveLength(args.options?.length); }); await step('select options correctly', async () => { userEvent.selectOptions(selectElement, 'Select1'); expect(selectElement.value).toBe('option1'); userEvent.selectOptions(selectElement, 'Select2'); expect(selectElement.value).toBe('option2'); userEvent.selectOptions(selectElement, 'Select3'); expect(selectElement.value).toBe('option3'); userEvent.selectOptions(selectElement, 'Select4'); expect(selectElement.value).toBe('option4'); userEvent.selectOptions(selectElement, 'Select5'); expect(selectElement.value).toBe('option5'); }); // 新增测试步骤:验证ref绑定 await step('Test ref is correctly bound', async () => { const refElement = canvas.queryByTestId('with-ref') as HTMLSelectElement; expect(refElement.tagName).toBe('SELECT'); }); // 新增测试步骤:处理null/undefined的options await step('Handle null/undefined options correctly', async () => { expect(canvas.queryByTestId('options-null')).toBeFalsy(); expect(canvas.queryByTestId('options-undefined')).toBeFalsy(); }); // 新增测试步骤:验证额外props传递 await step('Pass extra props correctly', async () => { expect(selectElement.disabled).toBe(true); }); }, };
完成以上修改后,就能覆盖所有未命中的代码分支,达到100%测试覆盖率。
内容的提问来源于stack exchange,提问作者Hasan
相关产品推荐
相关产品推荐

