close

extends

  • 类型: ExtendConfig | ExtendConfigFn | (ExtendConfig | ExtendConfigFn)[]
  • 默认值: undefined

extends 选项允许你从外部来源扩展 Rstest 配置,例如使用适配器将其他构建工具的配置转换为 Rstest 兼容格式。

这样可以实现以下功能:

  • 适配器集成: 通过 @rstest/adapter-rslib 等适配器从其他构建工具配置中扩展 Rstest 配置
  • 异步配置: 从外部源异步加载配置
  • 配置合并: 自动将扩展配置与本地 Rstest 配置合并
  • 可组合预设: 通过 extends 数组组合多个共享配置

基本用法(对象)

type ExtendConfig = Omit<RstestConfig, 'projects'>;

ExtendConfigRstestConfig 子集,不包含 projects 字段。

你可以用它从外部源扩展 Rstest 配置。Rstest 会按合并规则将扩展配置与本地配置合并。

import { defineConfig } from '@rstest/core';
import { sharedConfig } from './shared.config';

export default defineConfig({
  extends: sharedConfig,
  // 本地配置
  testTimeout: 10000,
  retry: 2,
});

函数用法

type ExtendConfigFn = (
  userConfig: Readonly<RstestConfig>,
) => ExtendConfig | Promise<ExtendConfig>;

ExtendConfigFn 是一个接收用户配置(只读)并返回扩展配置的函数。

它适用于加载外部配置文件、获取远程配置或基于用户设置进行动态配置。

import { defineConfig } from '@rstest/core';

export default defineConfig({
  extends: async (user) => {
    const useJsdom = user.testEnvironment === 'jsdom';
    return {
      setupFiles: useJsdom ? ['<rootDir>/setupDomTests.ts'] : undefined,
      source: {
        define: {
          BUILD_TARGET: '"test" ',
        },
      },
    };
  },
  testTimeout: 10_000,
});

多个 extends

当你需要组合多个预设时,可以给 extends 传入数组。

Rstest 会按从左到右的顺序依次解析数组。后面的条目会覆盖前面的冲突字段,而本地配置仍然拥有最高优先级。

当数组项为函数时,每个 ExtendConfigFn 都会基于原始的用户配置独立解析。数组顺序只影响最终合并优先级,不会影响传给每个函数的输入。

import { defineConfig } from '@rstest/core';
import { withRslibConfig } from '@rstest/adapter-rslib';
import { sharedConfig } from './shared.config';

export default defineConfig({
  extends: [
    sharedConfig,
    withRslibConfig({}),
    (userConfig) => ({
      globals: userConfig.retry !== undefined,
    }),
  ],
  testTimeout: 10_000,
});

配置合并

Rstest 对对象配置执行深度合并,对基本类型配置执行简单覆盖。本地配置优先于扩展配置。

extends 为数组时,优先级顺序如下:

extends[0] < extends[1] < ... < extends[n] < local config

主要合并规则如下:

  • testTimeoutretryglobals 这类基本类型字段由后者直接覆盖前者。
  • setupFilesglobalSetupplugins 会拼接,方便多个预设共同追加配置。
  • includereporterscoverage.reporters 会被后者整体替换。
  • sourceresolveoutputtoolsenvcoverage 等对象字段会执行深度合并。
  • browser 会执行浅合并,后者的同名属性覆盖前者。
  • 每个扩展配置中的 projects 都会被忽略。
import { defineConfig } from '@rstest/core';

export default defineConfig({
  extends: [
    {
      testEnvironment: 'jsdom',
      setupFiles: ['./setup-a.ts'],
      testTimeout: 5000,
      source: {
        define: {
          BASE_URL: '"https://example.com"',
        },
      },
    },
    {
      globals: true,
      setupFiles: ['./setup-b.ts'],
      source: {
        define: {
          API_URL: '"https://api.example.com"',
        },
      },
    },
  ],
  // 本地配置
  testTimeout: 10000,
  retry: 2,
});

// 结果:
// {
//   testEnvironment: 'jsdom',
//   globals: true,
//   testTimeout: 10000,
//   retry: 2,
//   setupFiles: ['./setup-a.ts', './setup-b.ts'],
//   source: {
//     define: {
//       BASE_URL: '"https://example.com"',
//       API_URL: '"https://api.example.com"',
//     },
//   },
// }

使用适配器

示例:从 Rslib 配置扩展

使用 @rstest/adapter-rslib 适配器可从现有 Rslib 配置文件扩展 Rstest 配置。该适配器会自动映射兼容选项,如 source.definesource.includesource.exclude 等。

import { defineConfig } from '@rstest/core';
import { withRslibConfig } from '@rstest/adapter-rslib';

export default defineConfig({
  extends: withRslibConfig({}),
  // 额外的 Rstest 特定配置
  coverage: {
    enabled: true,
    reporters: ['text', 'html'],
  },
});

限制

extends 配置不支持 projects 字段。要定义多个项目,请单独扩展每个项目:

export default defineConfig({
  projects: [
    {
      extends: withRslibConfig({ libId: 'node' }),
      include: ['tests/node/**/*.{test,spec}.?(c|m)[jt]s'],
    },
    {
      extends: withRslibConfig({ libId: 'react' }),
      include: ['tests/react/**/*.{test,spec}.?(c|m)[jt]s?(x)'],
    },
  ],
});