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

如何在Storybook中正确测试React多语言切换组件?

React + Storybook 多语言组件测试问题解答

问题1:如何在Story的play函数中获取useTranslation的i18n实例

由于Story的play函数并非React组件上下文,无法直接调用useTranslation Hook,但你可以直接导入项目中已初始化的i18n实例(通常项目会有单独的i18n配置文件,比如i18n.ts),以此动态获取当前语言对应的按钮文本。

修改后的Story代码示例

// 导入项目中已初始化的i18n实例
import i18n from '../path/to/your/i18n-config';
import { userEvent, waitFor } from '@storybook/testing-library';

export const Simple: Story = {
    args: {},
    play: async ({ canvasElement, step }) => {
        const canvas = within(canvasElement);
        // 动态获取当前语言对应的按钮显示文本
        const currentLangButtonText = i18n.t('ru');
        const button = canvas.getByRole('button', { name: currentLangButtonText });

        await step('按钮应存在于DOM中', async () => {
            expect(button).toBeInTheDocument();
        });

        await step('按钮应具备正确的type属性', async () => {
            expect(button).toHaveAttribute('type', 'button');
        });

        await step('按钮应包含指定样式类', async () => {
            expect(button).toHaveClass(
                'src-shared-ui-Button-Button-module__button',
                'src-shared-ui-Button-Button-module__lang'
            );
        });
    }
};

// 额外:测试语言切换交互的Story示例
export const ToggleLanguage: Story = {
    args: {},
    play: async ({ canvasElement, step }) => {
        const canvas = within(canvasElement);
        const initialLang = i18n.language;
        const targetLang = initialLang === 'ru' ? 'en' : 'ru';

        await step('初始状态下按钮显示对应语言文本', async () => {
            const button = canvas.getByRole('button', { name: i18n.t('ru') });
            expect(button).toBeInTheDocument();
        });

        await step('点击按钮切换语言', async () => {
            const button = canvas.getByRole('button', { name: i18n.t('ru') });
            await userEvent.click(button);
            // 等待语言切换状态更新
            await waitFor(() => expect(i18n.language).toBe(targetLang));
        });

        await step('切换后按钮文本同步更新', async () => {
            const updatedButton = canvas.getByRole('button', { name: i18n.t('ru') });
            expect(updatedButton).toBeInTheDocument();
        });
    }
};

问题2:当前测试方式的最佳实践优化

你的测试已经覆盖了基础UI验证,但可以从以下几个方向优化,让测试更健壮、符合最佳实践:

1. 避免硬编码CSS类名

直接断言自动生成的CSS类(如src-shared-ui-Button-Button-module__lang)会导致测试脆弱——一旦模块路径或类名修改,测试就会失效。建议:

  • 优先测试行为而非实现细节:比如验证按钮点击后语言切换的功能,而非依赖样式类;
  • 若必须验证样式类,可在Button组件中导出样式类常量(如export const ButtonClasses = { LANG: 'src-shared-ui-Button-Button-module__lang' }),测试时导入该常量而非硬编码字符串。

2. 拆分测试场景

将不同测试目标拆分为独立的Story,提升可读性和维护性:

  • InitialState:测试初始状态下的按钮显示与属性;
  • ToggleLanguage:测试语言切换的交互逻辑;
  • AccessibilityCheck:测试按钮的无障碍属性(如role、语义化标签)。

3. 利用Storybook插件增强测试

  • 使用@storybook/addon-a11y自动检查组件的无障碍合规性,减少手动编写无障碍测试的代码;
  • 使用@storybook/addon-interactions可视化交互测试步骤,方便调试。

4. 测试多语言初始化场景

创建不同的Story变体,覆盖不同初始语言的情况:

export const InitialLangEN: Story = {
    args: {},
    play: async ({ canvasElement, step }) => {
        // 强制设置初始语言为en
        await i18n.changeLanguage('en');
        const canvas = within(canvasElement);
        const button = canvas.getByRole('button', { name: i18n.t('ru') });
        
        await step('初始语言为en时按钮显示正确文本', async () => {
            expect(button).toBeInTheDocument();
        });
    }
};

5. 简化异步断言

对于同步断言(如toBeInTheDocument)无需添加await,仅在依赖异步操作的场景(如语言切换后的状态验证)使用waitFor或await。

内容的提问来源于stack exchange,提问作者rgdzv

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 07:47:28