For AI agents: the complete documentation index is available at /zh/llms.txt, the full documentation bundle is available at /zh/llms-full.txt, and this page is available as Markdown at /zh/guide/basic/css.md.
close
  • 简体中文
  • CSS

    Rstest 既可以通过 Rsbuild 工具链处理样式,也可以在测试不关心样式时替换样式导入。请根据测试目标选择配置:

    测试目标推荐方案
    只测组件逻辑,不检查样式使用默认样式处理
    使用 CSS Modules class name,或检查预处理器能否编译在 Node.js 测试中处理样式
    检查 computed styles、布局或视觉效果使用 Browser Mode

    在测试中处理样式

    Node.js 测试

    Rstest 内置支持 CSS 和 CSS Modules。在 Node.js 测试(包括 jsdom 和 happy-dom)中,Rstest 默认处理 CSS,但不输出 CSS 产物:

    • 普通 CSS 文件不会生成样式产物。
    • CSS Modules 会导出 class name 映射,可直接用于组件测试。
    • 没有匹配的 loader 或资源类型时,普通 .less.scss.sass 导入会导出空字符串(''),无需安装预处理器 plugin。
    • 启用 Less 或 Sass plugin 后,样式处理及其配置照常生效,编译错误仍会报出。

    兜底同样适用于 .module.less.module.scss.module.sass:默认导出为 {},因此 styles.button 的值为 undefined。需要真实 class name 映射时,请启用预处理器 plugin;希望用属性名作为类名时,可以替换样式导入

    用户配置的 loader、alias 和资源类型会保留原有行为。带 query 的导入(如 ?raw?url)需要对应的 plugin 或规则,不会使用兜底。样式文件仍须存在,兜底不会替换无法解析的导入。

    例如,.css.module.css 无需额外配置即可导入:

    Button.tsx
    import styles from './Button.module.css';
    import './reset.css';
    
    export function Button() {
      return <button className={styles.button}>Submit</button>;
    }
    Button.test.tsx
    import { expect, test } from '@rstest/core';
    import styles from './Button.module.css';
    
    test('loads CSS Modules', () => {
      expect(styles.button).toEqual(expect.any(String));
    });

    CSS Modules 常用 .module.css.module.less.module.scss 作为文件名。可以通过 output.cssModules 自定义 class name 生成规则和其他 CSS Modules 选项。

    添加 CSS 预处理器支持

    需要编译预处理器样式时,请启用对应的 Rsbuild plugin。下面以 Less 和 Sass 为例;如果使用其他预处理器,请先查看 Rsbuild plugin 列表 是否有对应的 plugin,再按相同方式注册。只需安装测试实际用到的 plugin。

    @rsbuild/plugin-less 用于编译 .less.module.less 文件:

    npm
    yarn
    pnpm
    bun
    deno
    npm add @rsbuild/plugin-less -D
    rstest.config.ts
    import { pluginLess } from '@rsbuild/plugin-less';
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      plugins: [pluginLess()],
    });

    @rsbuild/plugin-sass 用于编译 .sass.scss.module.sass.module.scss 文件:

    npm
    yarn
    pnpm
    bun
    deno
    npm add @rsbuild/plugin-sass -D
    rstest.config.ts
    import { pluginSass } from '@rsbuild/plugin-sass';
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      plugins: [pluginSass()],
    });

    如果项目通过 @rstest/adapter-rsbuild 复用 Rsbuild 配置,请把这些 plugin 配置在 rsbuild.config.ts 中,不要在 rstest.config.ts 中重复配置。

    Warning

    如果项目使用 @rstest/adapter-rspack,上面的 Rsbuild plugin 和 output.cssModules 示例不适用。该 adapter 使用 rspack.config.ts 中的 CSS 规则,请在 Rspack 配置中设置 Less、Sass 和 CSS Modules。

    Browser mode

    Node.js 测试可以检查样式导入值,但样式不会参与页面渲染。需要检查 computed styles、布局或视觉效果时,请使用 Browser Mode。Browser Mode 会在真实浏览器中运行组件并加载样式,不使用 Node.js 的空样式兜底;Less 和 Sass 需要对应的 plugin 或 loader。

    在逻辑测试中替换样式

    如果 Node.js 测试只检查组件逻辑,可以用测试替身替换样式导入。这样无需安装 Less 或 Sass plugin,也不会执行 CSS 预处理,但测试无法再验证被替换的样式。

    用 alias 替换少量导入

    如果只有少量确定的 CSS Modules 导入,可以把 resolve.aliasidentity-obj-proxy 配合使用。这个包会把属性名原样作为属性值返回,因此 styles.button 的值是 button

    npm
    yarn
    pnpm
    bun
    deno
    npm add identity-obj-proxy -D
    rstest.config.ts
    import { createRequire } from 'node:module';
    import { defineConfig } from '@rstest/core';
    
    const require = createRequire(import.meta.url);
    
    export default defineConfig({
      resolve: {
        alias: {
          './Button.module.less$': require.resolve('identity-obj-proxy'),
        },
      },
    });

    alias key 末尾的 $ 表示只匹配完整的导入请求,它只是 alias 配置中的标记,不属于实际导入路径。

    resolve.alias 按字符串前缀匹配,不支持正则表达式,因此适合替换少量且稳定的样式导入。alias 也可以指向项目内的测试替身;例如,对于 import './reset.less' 这类只执行副作用的导入,指向一个空模块即可。

    按扩展名批量替换

    样式导入较多时,可以通过 NormalModuleReplacementPlugin 按扩展名批量替换。下面的 Node.js 配置会把 CSS Modules 和只执行副作用的样式导入全部替换为 identity-obj-proxy

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      tools: {
        rspack(config, { rspack, isServer }) {
          if (!isServer) {
            return;
          }
    
          config.plugins.push(
            new rspack.NormalModuleReplacementPlugin(
              /\.(css|less|sass|scss)(?:\?.*)?$/,
              (resource) => {
                resource.request = 'identity-obj-proxy';
              },
            ),
          );
        },
      },
    });

    这两种替换方式都会跳过样式解析和编译,使用时需要留意以下限制:

    • styles.button 返回的是 button,不是实际构建生成的 class name。
    • Less、Sass 和 CSS Modules 语法不会经过校验。
    • 样式文件不存在或路径写错时不会报错,因为导入会在解析原文件之前被替换。
    • 无法测试 composes:global、样式产物,以及客户端与服务端 class name 是否一致。

    如果测试依赖其中任何一项,请保留真实样式处理;如果断言依赖最终渲染结果,请使用 Browser Mode。