@rstest/core 0.2.2 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/985.js CHANGED
@@ -7,37 +7,38 @@ export const __webpack_ids__ = [
7
7
  export const __webpack_modules__ = {
8
8
  "./src/core/rsbuild.ts": function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
9
9
  __webpack_require__.d(__webpack_exports__, {
10
- X: ()=>createRsbuildServer,
11
- z: ()=>prepareRsbuild
10
+ XD: ()=>createRsbuildServer,
11
+ zh: ()=>prepareRsbuild
12
12
  });
13
13
  var core_ = __webpack_require__("@rsbuild/core");
14
14
  var external_pathe_ = __webpack_require__("pathe");
15
15
  var utils = __webpack_require__("./src/utils/index.ts");
16
+ const RUNTIME_CHUNK_NAME = 'runtime';
16
17
  const pluginBasic = (context)=>({
17
18
  name: 'rstest:basic',
18
19
  setup: (api)=>{
19
- api.modifyRsbuildConfig(async (config)=>{
20
- config.environments = {
21
- [context.normalizedConfig.name]: {
22
- output: {
23
- target: 'node'
24
- }
25
- }
26
- };
27
- });
28
- api.modifyEnvironmentConfig(async (config, { mergeEnvironmentConfig })=>mergeEnvironmentConfig(config, {
20
+ api.modifyEnvironmentConfig(async (config, { mergeEnvironmentConfig, name })=>{
21
+ const { normalizedConfig: { resolve, source, output, tools, performance, dev, testEnvironment }, rootPath } = context.projects.find((p)=>p.environmentName === name);
22
+ return mergeEnvironmentConfig(config, {
23
+ performance,
24
+ tools,
25
+ resolve,
26
+ source,
27
+ output,
28
+ dev
29
+ }, {
29
30
  source: {
30
31
  define: {
31
32
  'import.meta.rstest': "global['@rstest/core']"
32
33
  }
33
34
  },
34
35
  output: {
35
- manifest: true,
36
+ manifest: `${name}-manifest.json`,
36
37
  sourceMap: {
37
38
  js: 'source-map'
38
39
  },
39
40
  distPath: {
40
- root: utils.zZ
41
+ root: context.projects.length > 1 ? `${utils.zZ}/${name}` : utils.zZ
41
42
  }
42
43
  },
43
44
  tools: {
@@ -51,7 +52,7 @@ export const __webpack_modules__ = {
51
52
  injectModulePathName: true,
52
53
  importMetaPathName: true,
53
54
  hoistMockModule: true,
54
- manualMockRoot: external_pathe_["default"].resolve(context.rootPath, '__mocks__')
55
+ manualMockRoot: external_pathe_["default"].resolve(rootPath, '__mocks__')
55
56
  }));
56
57
  config.module.parser ??= {};
57
58
  config.module.parser.javascript = {
@@ -74,7 +75,7 @@ export const __webpack_modules__ = {
74
75
  '.jsx',
75
76
  '.tsx'
76
77
  ];
77
- if ('node' === context.normalizedConfig.testEnvironment) config.resolve.mainFields = config.resolve.mainFields?.filter((filed)=>'module' !== filed) || [
78
+ if ('node' === testEnvironment) config.resolve.mainFields = config.resolve.mainFields?.filter((filed)=>'module' !== filed) || [
78
79
  'main'
79
80
  ];
80
81
  config.resolve.byDependency ??= {};
@@ -89,12 +90,13 @@ export const __webpack_modules__ = {
89
90
  nodeEnv: false,
90
91
  ...config.optimization || {},
91
92
  runtimeChunk: {
92
- name: 'runtime'
93
+ name: `${name}-${RUNTIME_CHUNK_NAME}`
93
94
  }
94
95
  };
95
96
  }
96
97
  }
97
- }));
98
+ });
99
+ });
98
100
  }
99
101
  });
100
102
  var external_node_path_ = __webpack_require__("node:path");
@@ -142,31 +144,32 @@ export const __webpack_modules__ = {
142
144
  });
143
145
  }
144
146
  }
145
- const pluginEntryWatch = ({ isWatch, globTestSourceEntries, setupFiles, configFilePath })=>({
147
+ const pluginEntryWatch = ({ isWatch, globTestSourceEntries, setupFiles, context })=>({
146
148
  name: 'rstest:entry-watch',
147
149
  setup: (api)=>{
148
- api.modifyRspackConfig(async (config)=>{
150
+ api.modifyRspackConfig(async (config, { environment })=>{
149
151
  if (isWatch) {
150
- config.plugins.push(new TestFileWatchPlugin(api.context.rootPath));
152
+ config.plugins.push(new TestFileWatchPlugin(environment.config.root));
151
153
  config.entry = async ()=>{
152
- const sourceEntries = await globTestSourceEntries();
154
+ const sourceEntries = await globTestSourceEntries(environment.name);
153
155
  return {
154
156
  ...sourceEntries,
155
- ...setupFiles
157
+ ...setupFiles[environment.name]
156
158
  };
157
159
  };
158
160
  config.watchOptions ??= {};
159
161
  config.watchOptions.ignored = (0, utils.bg)(config.watchOptions.ignored || []);
160
162
  if (0 === config.watchOptions.ignored.length) config.watchOptions.ignored.push('**/.git', '**/node_modules');
161
163
  config.watchOptions.ignored.push(utils.EJ, '**/*.snap');
164
+ const configFilePath = context.projects.find((project)=>project.environmentName === environment.name)?.configFilePath;
162
165
  if (configFilePath) config.watchOptions.ignored.push(configFilePath);
163
166
  } else {
164
167
  config.watch = false;
165
168
  config.watchOptions ??= {};
166
169
  config.watchOptions.ignored = '**/**';
167
- const sourceEntries = await globTestSourceEntries();
170
+ const sourceEntries = await globTestSourceEntries(environment.name);
168
171
  config.entry = {
169
- ...setupFiles,
172
+ ...setupFiles[environment.name],
170
173
  ...sourceEntries
171
174
  };
172
175
  }
@@ -196,10 +199,12 @@ export const __webpack_modules__ = {
196
199
  if (isNodeBuiltin) callback(void 0, request, 'commonjs' === dependencyType ? 'commonjs' : 'module-import');
197
200
  else callback();
198
201
  }
199
- const pluginExternal = (testEnvironment)=>({
202
+ const pluginExternal = (context)=>({
200
203
  name: 'rstest:external',
201
204
  setup: (api)=>{
202
- api.modifyRsbuildConfig(async (config, { mergeRsbuildConfig })=>mergeRsbuildConfig(config, {
205
+ api.modifyEnvironmentConfig(async (config, { mergeEnvironmentConfig, name })=>{
206
+ const { normalizedConfig: { testEnvironment } } = context.projects.find((p)=>p.environmentName === name);
207
+ return mergeEnvironmentConfig(config, {
203
208
  output: {
204
209
  externals: 'node' === testEnvironment ? [
205
210
  autoExternalNodeModules
@@ -216,7 +221,8 @@ export const __webpack_modules__ = {
216
221
  config.externals.push(autoExternalNodeBuiltin);
217
222
  }
218
223
  }
219
- }));
224
+ });
225
+ });
220
226
  }
221
227
  });
222
228
  class IgnoreModuleNotFoundErrorPlugin {
@@ -444,17 +450,13 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
444
450
  }
445
451
  const isMultiCompiler = (compiler)=>'compilers' in compiler && Array.isArray(compiler.compilers);
446
452
  const prepareRsbuild = async (context, globTestSourceEntries, setupFiles)=>{
447
- const { command, normalizedConfig: { isolate, plugins, resolve, source, output, tools, testEnvironment, performance, dev = {} } } = context;
453
+ const { command, normalizedConfig: { isolate, dev = {} } } = context;
448
454
  const debugMode = (0, utils._o)();
449
455
  core_.logger.level = debugMode ? 'verbose' : 'error';
450
456
  const writeToDisk = dev.writeToDisk || debugMode;
451
457
  const rsbuildInstance = await (0, core_.createRsbuild)({
452
458
  callerName: 'rstest',
453
459
  rsbuildConfig: {
454
- tools,
455
- resolve,
456
- source,
457
- output,
458
460
  server: {
459
461
  printUrls: false,
460
462
  strictPort: false,
@@ -467,9 +469,17 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
467
469
  hmr: false,
468
470
  writeToDisk
469
471
  },
470
- performance,
472
+ environments: Object.fromEntries(context.projects.map((project)=>[
473
+ project.environmentName,
474
+ {
475
+ plugins: project.normalizedConfig.plugins,
476
+ root: project.rootPath,
477
+ output: {
478
+ target: 'node'
479
+ }
480
+ }
481
+ ])),
471
482
  plugins: [
472
- ...plugins || [],
473
483
  pluginBasic(context),
474
484
  pluginIgnoreResolveError,
475
485
  pluginMockRuntime,
@@ -477,18 +487,64 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
477
487
  pluginEntryWatch({
478
488
  globTestSourceEntries,
479
489
  setupFiles,
480
- configFilePath: context.configFilePath,
490
+ context,
481
491
  isWatch: 'watch' === command
482
492
  }),
483
- pluginExternal(testEnvironment),
484
- !isolate ? pluginCacheControl(Object.values(setupFiles)) : null,
493
+ pluginExternal(context),
494
+ !isolate ? pluginCacheControl(Object.values(setupFiles).flatMap((files)=>Object.values(files))) : null,
485
495
  pluginInspect()
486
496
  ].filter(Boolean)
487
497
  }
488
498
  });
489
499
  return rsbuildInstance;
490
500
  };
491
- const createRsbuildServer = async ({ name, globTestSourceEntries, setupFiles, rsbuildInstance, normalizedConfig })=>{
501
+ const calcEntriesToRerun = (entries, chunks, buildData, runtimeChunkName)=>{
502
+ const entryToChunkHashesMap = new Map();
503
+ const buildChunkHashes = (entry)=>{
504
+ const validChunks = (entry.chunks || []).filter((chunk)=>chunk !== runtimeChunkName);
505
+ validChunks.forEach((chunkName)=>{
506
+ const chunkInfo = chunks?.find((c)=>c.names?.includes(chunkName));
507
+ if (chunkInfo) {
508
+ const existing = entryToChunkHashesMap.get(entry.testPath) || {};
509
+ existing[chunkName] = chunkInfo.hash ?? '';
510
+ entryToChunkHashesMap.set(entry.testPath, existing);
511
+ }
512
+ });
513
+ };
514
+ (entries || []).forEach(buildChunkHashes);
515
+ const entryToChunkHashes = Array.from(entryToChunkHashesMap.entries()).map(([name, chunks])=>({
516
+ name,
517
+ chunks
518
+ }));
519
+ const affectedTestPaths = new Set();
520
+ const deletedEntries = [];
521
+ if (buildData.entryToChunkHashes) {
522
+ const prevMap = new Map(buildData.entryToChunkHashes.map((e)=>[
523
+ e.name,
524
+ e.chunks
525
+ ]));
526
+ const currentNames = new Set(entryToChunkHashesMap.keys());
527
+ deletedEntries.push(...Array.from(prevMap.keys()).filter((name)=>!currentNames.has(name)));
528
+ const findAffectedEntry = (testPath)=>{
529
+ const currentChunks = entryToChunkHashesMap.get(testPath);
530
+ const prevChunks = prevMap.get(testPath);
531
+ if (!currentChunks) return;
532
+ if (!prevChunks) return void affectedTestPaths.add(testPath);
533
+ const hasChanges = Object.entries(currentChunks).some(([chunkName, hash])=>prevChunks[chunkName] !== hash);
534
+ if (hasChanges) affectedTestPaths.add(testPath);
535
+ };
536
+ entryToChunkHashesMap.forEach((_, testPath)=>{
537
+ findAffectedEntry(testPath);
538
+ });
539
+ }
540
+ buildData.entryToChunkHashes = entryToChunkHashes;
541
+ const affectedEntries = Array.from(affectedTestPaths).map((testPath)=>entries.find((e)=>e.testPath === testPath)).filter((entry)=>void 0 !== entry);
542
+ return {
543
+ affectedEntries,
544
+ deletedEntries
545
+ };
546
+ };
547
+ const createRsbuildServer = async ({ globTestSourceEntries, setupFiles, rsbuildInstance, normalizedConfig })=>{
492
548
  let rspackCompiler;
493
549
  const rstestCompilerPlugin = {
494
550
  name: 'rstest:compiler',
@@ -513,10 +569,26 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
513
569
  if (!rspackCompiler) throw new Error('rspackCompiler was not initialized');
514
570
  const outputFileSystem = isMultiCompiler(rspackCompiler) ? rspackCompiler.compilers[0].outputFileSystem : rspackCompiler.outputFileSystem;
515
571
  if (!outputFileSystem) throw new Error(`Expect outputFileSystem to be defined, but got ${outputFileSystem}`);
516
- const getRsbuildStats = async ({ fileFilters } = {})=>{
517
- const stats = await devServer.environments[name].getStats();
518
- const manifest = devServer.environments[name].context.manifest;
519
- const { entrypoints, outputPath, assets, hash, time: buildTime } = stats.toJson({
572
+ const readFile = async (fileName)=>new Promise((resolve, reject)=>{
573
+ outputFileSystem.readFile(fileName, (err, data)=>{
574
+ if (err) reject(err);
575
+ resolve('string' == typeof data ? data : data.toString());
576
+ });
577
+ });
578
+ const buildData = {};
579
+ const getEntryFiles = async (manifest, outputPath)=>{
580
+ const entryFiles = {};
581
+ const entries = Object.keys(manifest.entries);
582
+ for (const entry of entries){
583
+ const data = manifest.entries[entry];
584
+ entryFiles[entry] = ((data?.initial?.js || []).concat(data?.async?.js || []) || []).map((file)=>external_pathe_["default"].join(outputPath, file));
585
+ }
586
+ return entryFiles;
587
+ };
588
+ const getRsbuildStats = async ({ environmentName, fileFilters })=>{
589
+ const stats = await devServer.environments[environmentName].getStats();
590
+ const manifest = devServer.environments[environmentName].context.manifest;
591
+ const { entrypoints, outputPath, assets, hash, time: buildTime, chunks } = stats.toJson({
520
592
  all: false,
521
593
  hash: true,
522
594
  entrypoints: true,
@@ -524,41 +596,29 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
524
596
  assets: true,
525
597
  relatedAssets: true,
526
598
  cachedAssets: true,
599
+ chunks: true,
527
600
  timings: true
528
601
  });
529
- const readFile = async (fileName)=>new Promise((resolve, reject)=>{
530
- outputFileSystem.readFile(fileName, (err, data)=>{
531
- if (err) reject(err);
532
- resolve('string' == typeof data ? data : data.toString());
533
- });
534
- });
535
- const getEntryFiles = async ()=>{
536
- const entryFiles = {};
537
- const entries = Object.keys(manifest.entries);
538
- for (const entry of entries){
539
- const data = manifest.entries[entry];
540
- entryFiles[entry] = ((data?.initial?.js || []).concat(data?.async?.js || []) || []).map((file)=>external_pathe_["default"].join(outputPath, file));
541
- }
542
- return entryFiles;
543
- };
544
- const entryFiles = await getEntryFiles();
602
+ const entryFiles = await getEntryFiles(manifest, outputPath);
545
603
  const entries = [];
546
604
  const setupEntries = [];
547
- const sourceEntries = await globTestSourceEntries();
605
+ const sourceEntries = await globTestSourceEntries(environmentName);
548
606
  for (const entry of Object.keys(entrypoints)){
549
607
  const e = entrypoints[entry];
550
608
  const distPath = external_pathe_["default"].join(outputPath, e.assets[e.assets.length - 1].name);
551
- if (setupFiles[entry]) setupEntries.push({
609
+ if (setupFiles[environmentName][entry]) setupEntries.push({
552
610
  distPath,
553
- testPath: setupFiles[entry],
554
- files: entryFiles[entry]
611
+ testPath: setupFiles[environmentName][entry],
612
+ files: entryFiles[entry],
613
+ chunks: e.chunks || []
555
614
  });
556
615
  else if (sourceEntries[entry]) {
557
616
  if (fileFilters?.length && !fileFilters.includes(sourceEntries[entry])) continue;
558
617
  entries.push({
559
618
  distPath,
560
619
  testPath: sourceEntries[entry],
561
- files: entryFiles[entry]
620
+ files: entryFiles[entry],
621
+ chunks: e.chunks || []
562
622
  });
563
623
  }
564
624
  }
@@ -586,7 +646,11 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
586
646
  null
587
647
  ];
588
648
  }))).filter((asset)=>null !== asset[1]));
649
+ buildData[environmentName] ??= {};
650
+ const { affectedEntries, deletedEntries } = calcEntriesToRerun(entries, chunks, buildData[environmentName], `${environmentName}-${RUNTIME_CHUNK_NAME}`);
589
651
  return {
652
+ affectedEntries,
653
+ deletedEntries,
590
654
  hash,
591
655
  entries,
592
656
  setupEntries,
@@ -753,7 +817,7 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
753
817
  ].filter(Boolean),
754
818
  env: {
755
819
  NODE_ENV: 'test',
756
- FORCE_COLOR: '1',
820
+ FORCE_COLOR: '1' === process.env.NO_COLOR ? '0' : '1',
757
821
  ...process.env
758
822
  }
759
823
  });
@@ -772,10 +836,11 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
772
836
  }
773
837
  };
774
838
  return {
775
- runTests: async ({ entries, assetFiles, setupEntries, sourceMaps, updateSnapshot })=>{
839
+ runTests: async ({ entries, assetFiles, setupEntries, sourceMaps, project, updateSnapshot })=>{
840
+ const projectName = context.normalizedConfig.name;
841
+ const runtimeConfig = getRuntimeConfig(project);
776
842
  const setupAssets = setupEntries.flatMap((entry)=>entry.files || []);
777
843
  const entryLength = Object.keys(entries).length;
778
- const runtimeConfig = getRuntimeConfig(context);
779
844
  const results = await Promise.all(entries.map((entryInfo)=>{
780
845
  const { assetFiles: neededFiles, sourceMaps: neededSourceMaps } = filterAssetsByEntry(entryInfo, assetFiles, setupAssets, sourceMaps, entryLength);
781
846
  return pool.runTest({
@@ -783,6 +848,7 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
783
848
  entryInfo,
784
849
  assetFiles: neededFiles,
785
850
  context: {
851
+ project: projectName,
786
852
  rootPath: context.rootPath,
787
853
  runtimeConfig: (0, utils.Ok)(runtimeConfig)
788
854
  },
@@ -795,6 +861,7 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
795
861
  }).catch((err)=>{
796
862
  err.fullStack = true;
797
863
  return {
864
+ project: projectName,
798
865
  testPath: entryInfo.testPath,
799
866
  status: 'fail',
800
867
  name: '',
@@ -809,13 +876,15 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
809
876
  const testResults = results.flatMap((r)=>r.results);
810
877
  return {
811
878
  results,
812
- testResults
879
+ testResults,
880
+ project
813
881
  };
814
882
  },
815
- collectTests: async ({ entries, assetFiles, setupEntries, sourceMaps, updateSnapshot })=>{
883
+ collectTests: async ({ entries, assetFiles, setupEntries, sourceMaps, project, updateSnapshot })=>{
884
+ const runtimeConfig = getRuntimeConfig(project);
885
+ const projectName = project.normalizedConfig.name;
816
886
  const setupAssets = setupEntries.flatMap((entry)=>entry.files || []);
817
887
  const entryLength = Object.keys(entries).length;
818
- const runtimeConfig = getRuntimeConfig(context);
819
888
  return Promise.all(entries.map((entryInfo)=>{
820
889
  const { assetFiles: neededFiles, sourceMaps: neededSourceMaps } = filterAssetsByEntry(entryInfo, assetFiles, setupAssets, sourceMaps, entryLength);
821
890
  return pool.collectTests({
@@ -823,6 +892,7 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
823
892
  entryInfo,
824
893
  assetFiles: neededFiles,
825
894
  context: {
895
+ project: projectName,
826
896
  rootPath: context.rootPath,
827
897
  runtimeConfig: (0, utils.Ok)(runtimeConfig)
828
898
  },
@@ -835,6 +905,7 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
835
905
  }).catch((err)=>{
836
906
  err.fullStack = true;
837
907
  return {
908
+ project: projectName,
838
909
  testPath: entryInfo.testPath,
839
910
  tests: [],
840
911
  errors: [