vitest 4.0.0-beta.11 → 4.0.0-beta.12

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.
Files changed (55) hide show
  1. package/LICENSE.md +4 -101
  2. package/dist/browser.d.ts +3 -3
  3. package/dist/browser.js +2 -2
  4. package/dist/chunks/{benchmark.LXhJ0F0X.js → benchmark.DHKMYAts.js} +1 -1
  5. package/dist/chunks/{browser.d.Dx7DO_Ce.d.ts → browser.d.D9YV3JvA.d.ts} +1 -1
  6. package/dist/chunks/{cac.elvK37c9.js → cac.r1gel_VZ.js} +16 -9
  7. package/dist/chunks/{cli-api.C7plPyhs.js → cli-api.CpywZzJV.js} +95 -148
  8. package/dist/chunks/{config.d.B_LthbQq.d.ts → config.d.DGazh2r6.d.ts} +3 -1
  9. package/dist/chunks/{console.CiTi59Jy.js → console.CTJL2nuH.js} +3 -5
  10. package/dist/chunks/{coverage.CG6Uhorw.js → coverage.CiB0fs_7.js} +44 -62
  11. package/dist/chunks/{creator.08Gi-vCA.js → creator.DfXDsUyL.js} +6 -8
  12. package/dist/chunks/{global.d.BK3X7FW1.d.ts → global.d.BcFPD2LN.d.ts} +0 -13
  13. package/dist/chunks/{globals.BjvYA-AD.js → globals.DC4ntO86.js} +5 -5
  14. package/dist/chunks/{index.DIWhzsUh.js → index.Bt-upxGS.js} +6 -12
  15. package/dist/chunks/{index.BwBttQPf.js → index.CHrBLuEH.js} +33 -38
  16. package/dist/chunks/{index.X0nbfr6-.js → index.Dc3xnDvT.js} +48 -289
  17. package/dist/chunks/{index.AZOjjqWP.js → index.Dnl38iQ_.js} +2 -2
  18. package/dist/chunks/{index.BhY64fF0.js → index.uLUz1RDt.js} +1 -1
  19. package/dist/chunks/{inspector.CvQD-Nie.js → inspector.Br76Q2Mb.js} +1 -4
  20. package/dist/chunks/{moduleRunner.d.BNa-CL9e.d.ts → moduleRunner.d.CeYc7nZ0.d.ts} +1 -1
  21. package/dist/chunks/{node.BsdMi6DV.js → node.BwAWWjHZ.js} +2 -3
  22. package/dist/chunks/{plugin.d.C5phQR6o.d.ts → plugin.d.XreRXLXS.d.ts} +1 -1
  23. package/dist/chunks/{reporters.d.CVzhsTvK.d.ts → reporters.d.CJVTaaWb.d.ts} +39 -3
  24. package/dist/chunks/{resolveSnapshotEnvironment.DQVamkje.js → resolveSnapshotEnvironment.BsJpmVZR.js} +7 -8
  25. package/dist/chunks/{rpc.jKGRSXIH.js → rpc.cD77ENhU.js} +12 -13
  26. package/dist/chunks/{setup-common.NAWRuMRP.js → setup-common.BewgbkTd.js} +5 -5
  27. package/dist/chunks/{startModuleRunner.oAuCu1yL.js → startModuleRunner.DPBo3mme.js} +40 -48
  28. package/dist/chunks/{test.KC5tH8hC.js → test.CTuWuHYH.js} +5 -5
  29. package/dist/chunks/{typechecker.gXq-5P3n.js → typechecker.BfOQ86_a.js} +54 -77
  30. package/dist/chunks/{utils.DGKhod2J.js → utils.CG9h5ccR.js} +1 -4
  31. package/dist/chunks/{vi.CiJ0Laa6.js → vi.B2--mG9U.js} +35 -144
  32. package/dist/chunks/{worker.rPGLlbkW.js → worker.DVTUM2IW.js} +11 -15
  33. package/dist/chunks/{worker.d.B_Fd9M_w.d.ts → worker.d.buwuBpBt.d.ts} +1 -1
  34. package/dist/cli.js +3 -3
  35. package/dist/config.d.ts +6 -6
  36. package/dist/coverage.d.ts +5 -5
  37. package/dist/coverage.js +3 -3
  38. package/dist/environments.js +1 -1
  39. package/dist/index.d.ts +8 -8
  40. package/dist/index.js +5 -5
  41. package/dist/module-evaluator.d.ts +3 -3
  42. package/dist/module-evaluator.js +10 -12
  43. package/dist/module-runner.js +2 -2
  44. package/dist/node.d.ts +8 -8
  45. package/dist/node.js +10 -10
  46. package/dist/reporters.d.ts +5 -5
  47. package/dist/reporters.js +3 -3
  48. package/dist/runners.d.ts +1 -1
  49. package/dist/runners.js +6 -6
  50. package/dist/snapshot.js +2 -2
  51. package/dist/suite.js +2 -2
  52. package/dist/worker-base.js +30 -32
  53. package/dist/worker-vm.js +19 -30
  54. package/dist/workers/runVmTests.js +10 -10
  55. package/package.json +18 -19
@@ -20,13 +20,13 @@ import { a as isWindows } from './env.D4Lgay0q.js';
20
20
  import * as nodeos from 'node:os';
21
21
  import nodeos__default, { tmpdir } from 'node:os';
22
22
  import { isatty } from 'node:tty';
23
+ import { rootDir } from '../path.js';
23
24
  import EventEmitter from 'node:events';
24
25
  import { c as createBirpc } from './index.Bgo3tNWt.js';
25
26
  import Tinypool$1, { Tinypool } from 'tinypool';
26
- import { w as wrapSerializableConfig, a as Typechecker } from './typechecker.gXq-5P3n.js';
27
+ import { w as wrapSerializableConfig, a as Typechecker } from './typechecker.BfOQ86_a.js';
27
28
  import { MessageChannel } from 'node:worker_threads';
28
29
  import { hasFailed } from '@vitest/runner/utils';
29
- import { rootDir } from '../path.js';
30
30
  import { isCI, provider } from 'std-env';
31
31
  import { r as resolveCoverageProviderModule } from './coverage.D_JHT54q.js';
32
32
 
@@ -2403,17 +2403,17 @@ async function groupFilesByEnv(files) {
2403
2403
  if (envOptionsJson?.endsWith("*/"))
2404
2404
  // Trim closing Docblock characters the above regex might have captured
2405
2405
  envOptionsJson = envOptionsJson.slice(0, -2);
2406
- const envOptions = JSON.parse(envOptionsJson || "null"), envKey = env === "happy-dom" ? "happyDOM" : env, environment = {
2407
- name: env,
2408
- options: envOptions ? { [envKey]: envOptions } : null
2409
- };
2406
+ const envOptions = JSON.parse(envOptionsJson || "null");
2410
2407
  return {
2411
2408
  file: {
2412
2409
  filepath,
2413
2410
  testLocations: testLines
2414
2411
  },
2415
2412
  project,
2416
- environment
2413
+ environment: {
2414
+ name: env,
2415
+ options: envOptions ? { [env === "happy-dom" ? "happyDOM" : env]: envOptions } : null
2416
+ }
2417
2417
  };
2418
2418
  }));
2419
2419
  return groupBy(filesWithEnv, ({ environment }) => environment.name);
@@ -2609,8 +2609,8 @@ function createMethodsRPC(project, options = {}) {
2609
2609
  async transform(id) {
2610
2610
  const environment = project.vite.environments.__vitest_vm__;
2611
2611
  if (!environment) throw new Error(`The VM environment was not defined in the Vite config. This is a bug in Vitest. Please, open a new issue with reproduction.`);
2612
- const url = normalizeResolvedIdToUrl(environment, fileURLToPath$1(id)), result = await environment.transformRequest(url).catch(handleRollupError);
2613
- return { code: result?.code };
2612
+ const url = normalizeResolvedIdToUrl(environment, fileURLToPath$1(id));
2613
+ return { code: (await environment.transformRequest(url).catch(handleRollupError))?.code };
2614
2614
  },
2615
2615
  async onQueued(file) {
2616
2616
  if (options.collect) ctx.state.collectFiles(project, [file]);
@@ -2675,15 +2675,13 @@ function createChildProcessChannel$1(project, collect = false) {
2675
2675
  },
2676
2676
  timeout: -1
2677
2677
  });
2678
- project.vitest.onCancel((reason) => rpc.onCancel(reason));
2679
- const channel = {
2678
+ return project.vitest.onCancel((reason) => rpc.onCancel(reason)), {
2680
2679
  onMessage: (callback) => emitter.on(events.message, callback),
2681
2680
  postMessage: (message) => emitter.emit(events.response, message),
2682
2681
  onClose: () => {
2683
2682
  emitter.removeAllListeners(), rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
2684
2683
  }
2685
2684
  };
2686
- return channel;
2687
2685
  }
2688
2686
  function createForksPool(vitest, { execArgv, env }, specifications) {
2689
2687
  const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length, threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1), recommendedCount = vitest.config.watch ? threadsCount : Math.min(threadsCount, specifications.length), poolOptions = vitest.config.poolOptions?.forks ?? {}, maxThreads = poolOptions.maxForks ?? vitest.config.maxWorkers ?? recommendedCount, minThreads = vitest.config.watch ? Math.min(recommendedCount, maxThreads) : 0, options = {
@@ -2781,14 +2779,12 @@ function createWorkerChannel$1(project, collect) {
2781
2779
  },
2782
2780
  timeout: -1
2783
2781
  });
2784
- project.vitest.onCancel((reason) => rpc.onCancel(reason));
2785
- const onClose = () => {
2786
- port.close(), workerPort.close(), rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
2787
- };
2788
- return {
2782
+ return project.vitest.onCancel((reason) => rpc.onCancel(reason)), {
2789
2783
  workerPort,
2790
2784
  port,
2791
- onClose
2785
+ onClose: () => {
2786
+ port.close(), workerPort.close(), rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
2787
+ }
2792
2788
  };
2793
2789
  }
2794
2790
  function createThreadsPool(vitest, { execArgv, env }, specifications) {
@@ -2883,8 +2879,7 @@ function createTypecheckPool(vitest) {
2883
2879
  async function onParseEnd(project, { files, sourceErrors }) {
2884
2880
  const checker = project.typechecker, { packs, events } = checker.getTestPacksAndEvents();
2885
2881
  if (await vitest._testRun.updated(packs, events), !project.config.typecheck.ignoreSourceErrors) sourceErrors.forEach((error) => vitest.state.catchError(error, "Unhandled Source Error"));
2886
- const processError = !hasFailed(files) && !sourceErrors.length && checker.getExitCode();
2887
- if (processError) {
2882
+ if (!hasFailed(files) && !sourceErrors.length && checker.getExitCode()) {
2888
2883
  const error = new Error(checker.getOutput());
2889
2884
  error.stack = "", vitest.state.catchError(error, "Typecheck Error");
2890
2885
  }
@@ -2927,14 +2922,14 @@ function createTypecheckPool(vitest) {
2927
2922
  async function runTests(specs) {
2928
2923
  const specsByProject = groupBy(specs, (spec) => spec.project.name), promises = [];
2929
2924
  for (const name in specsByProject) {
2930
- const project = specsByProject[name][0].project, files = specsByProject[name].map((spec) => spec.moduleId), promise = createDefer(), _p = new Promise((resolve) => {
2925
+ const project = specsByProject[name][0].project, files = specsByProject[name].map((spec) => spec.moduleId), promise = createDefer(), triggered = await new Promise((resolve) => {
2931
2926
  const _i = setInterval(() => {
2932
2927
  if (!project.typechecker || rerunTriggered.has(project)) resolve(true), clearInterval(_i);
2933
2928
  });
2934
2929
  setTimeout(() => {
2935
2930
  resolve(false), clearInterval(_i);
2936
2931
  }, 500).unref();
2937
- }), triggered = await _p;
2932
+ });
2938
2933
  if (project.typechecker && !triggered) {
2939
2934
  const testFiles = project.typechecker.getTestFiles();
2940
2935
  for (const file of testFiles) await vitest._testRun.enqueued(project, file);
@@ -2963,14 +2958,10 @@ function getDefaultThreadsCount(config) {
2963
2958
  function getWorkerMemoryLimit(config, pool) {
2964
2959
  if (pool === "vmForks") {
2965
2960
  const opts = config.poolOptions?.vmForks ?? {};
2966
- if (opts.memoryLimit) return opts.memoryLimit;
2967
- const workers = opts.maxForks ?? getDefaultThreadsCount(config);
2968
- return 1 / workers;
2961
+ return opts.memoryLimit ? opts.memoryLimit : 1 / (opts.maxForks ?? getDefaultThreadsCount(config));
2969
2962
  } else {
2970
2963
  const opts = config.poolOptions?.vmThreads ?? {};
2971
- if (opts.memoryLimit) return opts.memoryLimit;
2972
- const workers = opts.maxThreads ?? getDefaultThreadsCount(config);
2973
- return 1 / workers;
2964
+ return opts.memoryLimit ? opts.memoryLimit : 1 / (opts.maxThreads ?? getDefaultThreadsCount(config));
2974
2965
  }
2975
2966
  }
2976
2967
  /**
@@ -3009,7 +3000,6 @@ function stringToBytes(input, percentageReference) {
3009
3000
  return null;
3010
3001
  }
3011
3002
 
3012
- const suppressWarningsPath$1 = resolve(rootDir, "./suppress-warnings.cjs");
3013
3003
  function createChildProcessChannel(project, collect) {
3014
3004
  const emitter = new EventEmitter(), events = {
3015
3005
  message: "message",
@@ -3039,15 +3029,13 @@ function createChildProcessChannel(project, collect) {
3039
3029
  },
3040
3030
  timeout: -1
3041
3031
  });
3042
- project.vitest.onCancel((reason) => rpc.onCancel(reason));
3043
- const channel = {
3032
+ return project.vitest.onCancel((reason) => rpc.onCancel(reason)), { channel: {
3044
3033
  onMessage: (callback) => emitter.on(events.message, callback),
3045
3034
  postMessage: (message) => emitter.emit(events.response, message),
3046
3035
  onClose: () => {
3047
3036
  emitter.removeAllListeners(), rpc.$close(/* @__PURE__ */ new Error("[vitest-pool]: Pending methods while closing rpc"));
3048
3037
  }
3049
- };
3050
- return { channel };
3038
+ } };
3051
3039
  }
3052
3040
  function createVmForksPool(vitest, { execArgv, env }, specifications) {
3053
3041
  const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length, threadsCount = vitest.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1), recommendedCount = vitest.config.watch ? threadsCount : Math.min(threadsCount, specifications.length), poolOptions = vitest.config.poolOptions?.vmForks ?? {}, maxThreads = poolOptions.maxForks ?? vitest.config.maxWorkers ?? recommendedCount, minThreads = vitest.config.watch ? Math.min(recommendedCount, maxThreads) : 0, options = {
@@ -3057,10 +3045,7 @@ function createVmForksPool(vitest, { execArgv, env }, specifications) {
3057
3045
  minThreads,
3058
3046
  env,
3059
3047
  execArgv: [
3060
- "--experimental-import-meta-resolve",
3061
3048
  "--experimental-vm-modules",
3062
- "--require",
3063
- suppressWarningsPath$1,
3064
3049
  ...poolOptions.execArgv ?? [],
3065
3050
  ...execArgv
3066
3051
  ],
@@ -3105,7 +3090,7 @@ function createVmForksPool(vitest, { execArgv, env }, specifications) {
3105
3090
  if (configs.has(project)) return configs.get(project);
3106
3091
  const _config = project.serializedConfig, config = wrapSerializableConfig(_config);
3107
3092
  return configs.set(project, config), config;
3108
- }, filesByEnv = await groupFilesByEnv(specs), promises = Object.values(filesByEnv).flat(), results = await Promise.allSettled(promises.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))), errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
3093
+ }, filesByEnv = await groupFilesByEnv(specs), promises = Object.values(filesByEnv).flat(), errors = (await Promise.allSettled(promises.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates)))).filter((r) => r.status === "rejected").map((r) => r.reason);
3109
3094
  if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
3110
3095
  };
3111
3096
  };
@@ -3122,7 +3107,6 @@ function getMemoryLimit$1(config) {
3122
3107
  return typeof memory === "number" ? stringToBytes(limit, config.watch ? memory / 2 : memory) : typeof limit === "number" && limit > 1 || typeof limit === "string" && limit.at(-1) !== "%" ? stringToBytes(limit) : null;
3123
3108
  }
3124
3109
 
3125
- const suppressWarningsPath = resolve(rootDir, "./suppress-warnings.cjs");
3126
3110
  function createWorkerChannel(project, collect) {
3127
3111
  const channel = new MessageChannel(), port = channel.port2, workerPort = channel.port1, rpc = createBirpc(createMethodsRPC(project, { collect }), {
3128
3112
  eventNames: ["onCancel"],
@@ -3151,10 +3135,7 @@ function createVmThreadsPool(vitest, { execArgv, env }, specifications) {
3151
3135
  minThreads,
3152
3136
  env,
3153
3137
  execArgv: [
3154
- "--experimental-import-meta-resolve",
3155
3138
  "--experimental-vm-modules",
3156
- "--require",
3157
- suppressWarningsPath,
3158
3139
  ...poolOptions.execArgv ?? [],
3159
3140
  ...execArgv
3160
3141
  ],
@@ -3200,7 +3181,7 @@ function createVmThreadsPool(vitest, { execArgv, env }, specifications) {
3200
3181
  if (configs.has(project)) return configs.get(project);
3201
3182
  const config = project.serializedConfig;
3202
3183
  return configs.set(project, config), config;
3203
- }, filesByEnv = await groupFilesByEnv(specs), promises = Object.values(filesByEnv).flat(), results = await Promise.allSettled(promises.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))), errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
3184
+ }, filesByEnv = await groupFilesByEnv(specs), promises = Object.values(filesByEnv).flat(), errors = (await Promise.allSettled(promises.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates)))).filter((r) => r.status === "rejected").map((r) => r.reason);
3204
3185
  if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error.");
3205
3186
  };
3206
3187
  };
@@ -3217,6 +3198,7 @@ function getMemoryLimit(config) {
3217
3198
  return typeof memory === "number" ? stringToBytes(limit, config.watch ? memory / 2 : memory) : typeof limit === "number" && limit > 1 || typeof limit === "string" && limit.at(-1) !== "%" ? stringToBytes(limit) : null;
3218
3199
  }
3219
3200
 
3201
+ const suppressWarningsPath = resolve$1(rootDir, "./suppress-warnings.cjs");
3220
3202
  const builtinPools = [
3221
3203
  "forks",
3222
3204
  "threads",
@@ -3239,18 +3221,24 @@ function createPool(ctx) {
3239
3221
  vmThreads: null,
3240
3222
  vmForks: null,
3241
3223
  typescript: null
3242
- }, viteMajor = Number(version.split(".")[0]), potentialConditions = new Set(viteMajor >= 6 ? ctx.vite.config.ssr.resolve?.conditions ?? [] : [
3224
+ }, viteMajor = Number(version.split(".")[0]), conditions = [...new Set(viteMajor >= 6 ? ctx.vite.config.ssr.resolve?.conditions ?? [] : [
3243
3225
  "production",
3244
3226
  "development",
3245
3227
  ...ctx.vite.config.resolve.conditions
3246
- ]), conditions = [...potentialConditions].filter((condition) => {
3228
+ ])].filter((condition) => {
3247
3229
  return condition === "production" ? ctx.vite.config.isProduction : condition === "development" ? !ctx.vite.config.isProduction : true;
3248
3230
  }).map((condition) => {
3249
3231
  return viteMajor >= 6 && condition === "development|production" ? ctx.vite.config.isProduction ? "production" : "development" : condition;
3250
3232
  }).flatMap((c) => ["--conditions", c]), execArgv = process.execArgv.filter((execArg) => execArg.startsWith("--cpu-prof") || execArg.startsWith("--heap-prof") || execArg.startsWith("--diagnostic-dir"));
3251
3233
  async function executeTests(method, files, invalidate) {
3252
3234
  const options = {
3253
- execArgv: [...execArgv, ...conditions],
3235
+ execArgv: [
3236
+ ...execArgv,
3237
+ ...conditions,
3238
+ "--experimental-import-meta-resolve",
3239
+ "--require",
3240
+ suppressWarningsPath
3241
+ ],
3254
3242
  env: {
3255
3243
  TEST: "true",
3256
3244
  VITEST: "true",
@@ -3355,7 +3343,7 @@ class BaseSequencer {
3355
3343
  async shard(files) {
3356
3344
  const { config } = this.ctx, { index, count } = config.shard, [shardStart, shardEnd] = this.calculateShardRange(files.length, index, count);
3357
3345
  return [...files].map((spec) => {
3358
- const fullPath = resolve$1(slash(config.root), slash(spec.moduleId)), specPath = fullPath?.slice(config.root.length);
3346
+ const specPath = resolve$1(slash(config.root), slash(spec.moduleId))?.slice(config.root.length);
3359
3347
  return {
3360
3348
  spec,
3361
3349
  hash: hash("sha1", specPath, "hex")
@@ -3578,10 +3566,8 @@ function resolveConfig$1(vitest, options, viteConfig) {
3578
3566
  maxForks: Number.parseInt(process.env.VITEST_MAX_FORKS)
3579
3567
  }
3580
3568
  };
3581
- const poolThreadsOptions = [["threads", "maxThreads"], ["vmThreads", "maxThreads"]];
3582
- for (const [poolOptionKey, workerOptionKey] of poolThreadsOptions) if (resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey]) resolved.poolOptions[poolOptionKey][workerOptionKey] = resolveInlineWorkerOption(resolved.poolOptions[poolOptionKey][workerOptionKey]);
3583
- const poolForksOptions = [["forks", "maxForks"], ["vmForks", "maxForks"]];
3584
- for (const [poolOptionKey, workerOptionKey] of poolForksOptions) if (resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey]) resolved.poolOptions[poolOptionKey][workerOptionKey] = resolveInlineWorkerOption(resolved.poolOptions[poolOptionKey][workerOptionKey]);
3569
+ for (const [poolOptionKey, workerOptionKey] of [["threads", "maxThreads"], ["vmThreads", "maxThreads"]]) if (resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey]) resolved.poolOptions[poolOptionKey][workerOptionKey] = resolveInlineWorkerOption(resolved.poolOptions[poolOptionKey][workerOptionKey]);
3570
+ for (const [poolOptionKey, workerOptionKey] of [["forks", "maxForks"], ["vmForks", "maxForks"]]) if (resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey]) resolved.poolOptions[poolOptionKey][workerOptionKey] = resolveInlineWorkerOption(resolved.poolOptions[poolOptionKey][workerOptionKey]);
3585
3571
  if (!builtinPools.includes(resolved.pool)) resolved.pool = resolvePath(resolved.pool, resolved.root);
3586
3572
  if (mode === "benchmark") {
3587
3573
  resolved.benchmark = {
@@ -3597,10 +3583,8 @@ function resolveConfig$1(vitest, options, viteConfig) {
3597
3583
  if (options.outputJson) resolved.benchmark.outputJson = options.outputJson;
3598
3584
  }
3599
3585
  if (typeof resolved.diff === "string") resolved.diff = resolvePath(resolved.diff, resolved.root), resolved.forceRerunTriggers.push(resolved.diff);
3600
- // the server has been created, we don't need to override vite.server options
3601
- const api = resolveApiServerConfig(options, defaultPort);
3602
3586
  if (resolved.api = {
3603
- ...api,
3587
+ ...resolveApiServerConfig(options, defaultPort),
3604
3588
  token: crypto.randomUUID()
3605
3589
  }, options.related) resolved.related = toArray(options.related).map((file) => resolve$1(resolved.root, file));
3606
3590
  /*
@@ -3675,10 +3659,11 @@ function resolveConfig$1(vitest, options, viteConfig) {
3675
3659
  if (resolved.browser.api = resolveApiServerConfig(resolved.browser, defaultBrowserPort) || { port: defaultBrowserPort }, resolved.browser.enabled) {
3676
3660
  if (resolved.browser.ui) resolved.includeTaskLocation ??= true;
3677
3661
  } else if (resolved.ui) resolved.includeTaskLocation ??= true;
3678
- const htmlReporter = toArray(resolved.reporters).some((reporter) => {
3662
+ if (typeof resolved.browser.trace === "string" || !resolved.browser.trace) resolved.browser.trace = { mode: resolved.browser.trace || "off" };
3663
+ if (resolved.browser.trace.tracesDir != null) resolved.browser.trace.tracesDir = resolvePath(resolved.browser.trace.tracesDir, resolved.root);
3664
+ if (toArray(resolved.reporters).some((reporter) => {
3679
3665
  return Array.isArray(reporter) ? reporter[0] === "html" : false;
3680
- });
3681
- if (htmlReporter) resolved.includeTaskLocation ??= true;
3666
+ })) resolved.includeTaskLocation ??= true;
3682
3667
  return resolved.server ??= {}, resolved.server.deps ??= {}, resolved.testTimeout ??= resolved.browser.enabled ? 15e3 : 5e3, resolved.hookTimeout ??= resolved.browser.enabled ? 3e4 : 1e4, resolved;
3683
3668
  }
3684
3669
  function isBrowserEnabled(config) {
@@ -3788,8 +3773,8 @@ Update your dependencies and make sure the versions match.`));
3788
3773
  }
3789
3774
  async getUntestedFiles(testedFiles) {
3790
3775
  if (this.options.include == null) return [];
3791
- const rootMapper = this.getUntestedFilesByRoot.bind(this, testedFiles, this.options.include), matrix = await Promise.all(this.roots.map(rootMapper));
3792
- return matrix.flatMap((files) => files);
3776
+ const rootMapper = this.getUntestedFilesByRoot.bind(this, testedFiles, this.options.include);
3777
+ return (await Promise.all(this.roots.map(rootMapper))).flatMap((files) => files);
3793
3778
  }
3794
3779
  createCoverageMap() {
3795
3780
  throw new Error("BaseReporter's createCoverageMap was not overwritten");
@@ -3850,10 +3835,7 @@ Update your dependencies and make sure the versions match.`));
3850
3835
  if (!this.options.reportOnFailure) await this.cleanAfterRun();
3851
3836
  }
3852
3837
  async reportCoverage(coverageMap, { allTestsRun }) {
3853
- await this.generateReports(coverageMap || this.createCoverageMap(), allTestsRun);
3854
- // In watch mode we need to preserve the previous results if cleanOnRerun is disabled
3855
- const keepResults = !this.options.cleanOnRerun && this.ctx.config.watch;
3856
- if (!keepResults) await this.cleanAfterRun();
3838
+ if (await this.generateReports(coverageMap || this.createCoverageMap(), allTestsRun), !(!this.options.cleanOnRerun && this.ctx.config.watch)) await this.cleanAfterRun();
3857
3839
  }
3858
3840
  async reportThresholds(coverageMap, allTestsRun) {
3859
3841
  const resolvedThresholds = this.resolveThresholds(coverageMap);
@@ -2,11 +2,12 @@ import { existsSync, writeFileSync, readFileSync } from 'node:fs';
2
2
  import { mkdir, writeFile } from 'node:fs/promises';
3
3
  import { resolve, dirname, relative } from 'node:path';
4
4
  import { detectPackageManager, installPackage } from './index.D3XRDfWc.js';
5
- import { p as prompt, f as findUp } from './index.X0nbfr6-.js';
5
+ import { p as prompt, a as any } from './index.Dc3xnDvT.js';
6
6
  import { x } from 'tinyexec';
7
7
  import c from 'tinyrainbow';
8
8
  import { c as configFiles } from './constants.D_Q9UYh-.js';
9
9
  import 'node:process';
10
+ import 'node:module';
10
11
  import 'node:url';
11
12
  import './_commonjsHelpers.BFTU3MAI.js';
12
13
  import 'readline';
@@ -297,12 +298,11 @@ async function generateExampleFiles(framework, lang) {
297
298
  // eslint-disable-next-line no-console
298
299
  const log = console.log;
299
300
  function getProviderOptions() {
300
- const providers = {
301
+ return Object.entries({
301
302
  playwright: "Playwright relies on Chrome DevTools protocol. Read more: https://playwright.dev",
302
303
  webdriverio: "WebdriverIO uses WebDriver protocol. Read more: https://webdriver.io",
303
304
  preview: "Preview is useful to quickly run your tests in the browser, but not suitable for CI."
304
- };
305
- return Object.entries(providers).map(([provider, description]) => {
305
+ }).map(([provider, description]) => {
306
306
  return {
307
307
  title: provider,
308
308
  description,
@@ -476,9 +476,7 @@ function getProviderDocsLink(provider) {
476
476
  }
477
477
  function sort(choices, value) {
478
478
  const index = choices.findIndex((i) => i.value === value);
479
- if (index === -1) return choices;
480
- const item = choices.splice(index, 1)[0];
481
- return [item, ...choices];
479
+ return index === -1 ? choices : [choices.splice(index, 1)[0], ...choices];
482
480
  }
483
481
  function fail() {
484
482
  process.exitCode = 1;
@@ -603,7 +601,7 @@ async function create() {
603
601
  if (frameworkPlugin) dependenciesToInstall.push(frameworkPlugin);
604
602
  const pkgManager = await detectPackageManager();
605
603
  log(), await installPackages(pkgManager, dependenciesToInstall.filter((pkg) => !dependencies[pkg]));
606
- const rootConfig = await findUp(configFiles, { cwd: process.cwd() });
604
+ const rootConfig = any(configFiles, { cwd: process.cwd() });
607
605
  let scriptCommand = "vitest";
608
606
  if (log(), rootConfig) {
609
607
  const configPath = resolve(dirname(rootConfig), `vitest.browser.config.${lang}`);
@@ -4,19 +4,6 @@ import { SnapshotState } from '@vitest/snapshot';
4
4
  import { B as BenchmarkResult } from './benchmark.d.DAaHLpsq.js';
5
5
  import { U as UserConsoleLog } from './environment.d.BsToaxti.js';
6
6
 
7
- declare global {
8
- namespace Chai {
9
- interface ContainSubset {
10
- (expected: any): Assertion;
11
- }
12
- interface Assertion {
13
- containSubset: ContainSubset;
14
- }
15
- interface Assert {
16
- containSubset(val: any, exp: any, msg?: string): void;
17
- }
18
- }
19
- }
20
7
  interface SnapshotMatcher<T> {
21
8
  <U extends { [P in keyof T] : any }>(snapshot: Partial<U>, hint?: string): void;
22
9
  (hint?: string): void;
@@ -1,20 +1,20 @@
1
1
  import { g as globalApis } from './constants.D_Q9UYh-.js';
2
- import { i as index } from './index.AZOjjqWP.js';
3
- import './vi.CiJ0Laa6.js';
2
+ import { i as index } from './index.Dnl38iQ_.js';
3
+ import './vi.B2--mG9U.js';
4
4
  import '@vitest/expect';
5
5
  import '@vitest/runner';
6
6
  import '@vitest/runner/utils';
7
- import './utils.DGKhod2J.js';
7
+ import './utils.CG9h5ccR.js';
8
8
  import '@vitest/utils/timers';
9
- import './_commonjsHelpers.BFTU3MAI.js';
10
9
  import '@vitest/snapshot';
11
10
  import '@vitest/utils/error';
12
11
  import '@vitest/utils/helpers';
13
12
  import '@vitest/spy';
14
13
  import '@vitest/utils/offset';
15
14
  import '@vitest/utils/source-map';
15
+ import './_commonjsHelpers.BFTU3MAI.js';
16
16
  import './date.-jtEtIeV.js';
17
- import './benchmark.LXhJ0F0X.js';
17
+ import './benchmark.DHKMYAts.js';
18
18
  import 'expect-type';
19
19
  import 'vite/module-runner';
20
20
 
@@ -238,10 +238,10 @@ const skipKeys = [
238
238
  "parent"
239
239
  ];
240
240
  function getWindowKeys(global, win, additionalKeys = []) {
241
- const keysArray = [...additionalKeys, ...KEYS], keys = new Set(keysArray.concat(Object.getOwnPropertyNames(win)).filter((k) => {
241
+ const keysArray = [...additionalKeys, ...KEYS];
242
+ return new Set(keysArray.concat(Object.getOwnPropertyNames(win)).filter((k) => {
242
243
  return skipKeys.includes(k) ? false : k in global ? keysArray.includes(k) : true;
243
244
  }));
244
- return keys;
245
245
  }
246
246
  function isClassLikeName(name) {
247
247
  return name[0] === name[0].toUpperCase();
@@ -393,23 +393,18 @@ var jsdom = {
393
393
  });
394
394
  const clearWindowErrors = catchWindowErrors(dom.window);
395
395
  dom.window.Buffer = Buffer, dom.window.jsdom = dom;
396
- // inject web globals if they missing in JSDOM but otherwise available in Nodejs
397
- // https://nodejs.org/dist/latest/docs/api/globals.html
398
- const globalNames = [
396
+ for (const name of [
399
397
  "structuredClone",
400
398
  "BroadcastChannel",
401
399
  "MessageChannel",
402
400
  "MessagePort",
403
401
  "TextEncoder",
404
402
  "TextDecoder"
405
- ];
406
- for (const name of globalNames) {
403
+ ]) {
407
404
  const value = globalThis[name];
408
405
  if (typeof value !== "undefined" && typeof dom.window[name] === "undefined") dom.window[name] = value;
409
406
  }
410
- // since we are providing Node.js's Fetch API,
411
- // we also should override other APIs they use
412
- const overrideGlobals = [
407
+ for (const name of [
413
408
  "fetch",
414
409
  "Request",
415
410
  "Response",
@@ -418,8 +413,7 @@ var jsdom = {
418
413
  "AbortSignal",
419
414
  "URL",
420
415
  "URLSearchParams"
421
- ];
422
- for (const name of overrideGlobals) {
416
+ ]) {
423
417
  const value = globalThis[name];
424
418
  if (typeof value !== "undefined") dom.window[name] = value;
425
419
  }
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readFileSync, promises } from 'node:fs';
2
2
  import { mkdir, writeFile, readdir, stat, readFile } from 'node:fs/promises';
3
3
  import { resolve, dirname, isAbsolute, relative, basename, normalize } from 'pathe';
4
- import { g as getOutputFile, h as hasFailedSnapshot, T as TypeCheckError } from './typechecker.gXq-5P3n.js';
4
+ import { g as getOutputFile, h as hasFailedSnapshot, T as TypeCheckError } from './typechecker.BfOQ86_a.js';
5
5
  import { performance as performance$1 } from 'node:perf_hooks';
6
6
  import { getTestName, hasFailed, getTests, getSuites, getTasks, getFullName } from '@vitest/runner/utils';
7
7
  import { slash, toArray, isPrimitive } from '@vitest/utils/helpers';
@@ -171,9 +171,9 @@ async function writeBlob(content, filename) {
171
171
  }
172
172
  async function readBlobs(currentVersion, blobsDirectory, projectsArray) {
173
173
  // using process.cwd() because --merge-reports can only be used in CLI
174
- const resolvedDir = resolve(process.cwd(), blobsDirectory), blobsFiles = await readdir(resolvedDir), promises = blobsFiles.map(async (filename) => {
175
- const fullPath = resolve(resolvedDir, filename), stats = await stat(fullPath);
176
- if (!stats.isFile()) throw new TypeError(`vitest.mergeReports() expects all paths in "${blobsDirectory}" to be files generated by the blob reporter, but "${filename}" is not a file`);
174
+ const resolvedDir = resolve(process.cwd(), blobsDirectory), promises = (await readdir(resolvedDir)).map(async (filename) => {
175
+ const fullPath = resolve(resolvedDir, filename);
176
+ if (!(await stat(fullPath)).isFile()) throw new TypeError(`vitest.mergeReports() expects all paths in "${blobsDirectory}" to be files generated by the blob reporter, but "${filename}" is not a file`);
177
177
  const content = await readFile(fullPath, "utf-8"), [version, files, errors, moduleKeys, coverage, executionTime] = parse(content);
178
178
  if (!version) throw new TypeError(`vitest.mergeReports() expects all paths in "${blobsDirectory}" to be files generated by the blob reporter, but "${filename}" is not a valid blob file`);
179
179
  return {
@@ -456,8 +456,7 @@ class BaseReporter {
456
456
  let suffix = c.dim("(") + state + c.dim(")") + this.getDurationPrefix(testModule.task);
457
457
  const diagnostic = testModule.diagnostic();
458
458
  if (diagnostic.heap != null) suffix += c.magenta(` ${Math.floor(diagnostic.heap / 1024 / 1024)} MB heap used`);
459
- const title = this.getEntityPrefix(testModule);
460
- return ` ${title} ${testModule.task.name} ${suffix}`;
459
+ return ` ${this.getEntityPrefix(testModule)} ${testModule.task.name} ${suffix}`;
461
460
  }
462
461
  printTestSuite(testSuite) {
463
462
  if (!this.renderSucceed) return;
@@ -479,12 +478,16 @@ class BaseReporter {
479
478
  printAnnotations(test, console, padding = 0) {
480
479
  const annotations = test.annotations();
481
480
  if (!annotations.length) return;
482
- const PADDING = " ".repeat(padding);
483
- annotations.forEach(({ location, type, message }) => {
481
+ const PADDING = " ".repeat(padding), groupedAnnotations = {};
482
+ for (const group in annotations.forEach((annotation) => {
483
+ const { location, type } = annotation;
484
+ let group;
484
485
  if (location) {
485
486
  const file = relative(test.project.config.root, location.file);
486
- this[console](`${PADDING}${c.blue(F_POINTER)} ${c.gray(`${file}:${location.line}:${location.column}`)} ${c.bold(type)}`);
487
- } else this[console](`${PADDING}${c.blue(F_POINTER)} ${c.bold(type)}`);
487
+ group = `${c.gray(`${file}:${location.line}:${location.column}`)} ${c.bold(type)}`;
488
+ } else group = c.bold(type);
489
+ groupedAnnotations[group] ??= [], groupedAnnotations[group].push(annotation);
490
+ }), groupedAnnotations) this[console](`${PADDING}${c.blue(F_POINTER)} ${group}`), groupedAnnotations[group].forEach(({ message }) => {
488
491
  this[console](`${PADDING} ${c.blue(F_DOWN_RIGHT)} ${message}`);
489
492
  });
490
493
  }
@@ -508,13 +511,10 @@ class BaseReporter {
508
511
  }
509
512
  getDurationPrefix(task) {
510
513
  const duration = task.result?.duration && Math.round(task.result?.duration);
511
- if (duration == null) return "";
512
- const color = duration > this.ctx.config.slowTestThreshold ? c.yellow : c.green;
513
- return color(` ${duration}${c.dim("ms")}`);
514
+ return duration == null ? "" : (duration > this.ctx.config.slowTestThreshold ? c.yellow : c.green)(` ${duration}${c.dim("ms")}`);
514
515
  }
515
516
  onWatcherStart(files = this.ctx.state.getFiles(), errors = this.ctx.state.getUnhandledErrors()) {
516
- const failed = errors.length > 0 || hasFailed(files);
517
- if (failed) this.log(withLabel("red", "FAIL", "Tests failed. Watching for file changes..."));
517
+ if (errors.length > 0 || hasFailed(files)) this.log(withLabel("red", "FAIL", "Tests failed. Watching for file changes..."));
518
518
  else if (this.ctx.isCancelling) this.log(withLabel("red", "CANCELLED", "Test run cancelled. Watching for file changes..."));
519
519
  else this.log(withLabel("green", "PASS", "Waiting for file changes..."));
520
520
  const hints = [c.dim("press ") + c.bold("h") + c.dim(" to show help")];
@@ -564,8 +564,8 @@ class BaseReporter {
564
564
  shouldLog(log, taskState) {
565
565
  if (this.ctx.config.silent === true || this.ctx.config.silent === "passed-only" && taskState !== "failed") return false;
566
566
  if (this.ctx.config.onConsoleLog) {
567
- const task = log.taskId ? this.ctx.state.idMap.get(log.taskId) : void 0, entity = task && this.ctx.state.getReportedEntity(task), shouldLog = this.ctx.config.onConsoleLog(log.content, log.type, entity);
568
- if (shouldLog === false) return false;
567
+ const task = log.taskId ? this.ctx.state.idMap.get(log.taskId) : void 0, entity = task && this.ctx.state.getReportedEntity(task);
568
+ if (this.ctx.config.onConsoleLog(log.content, log.type, entity) === false) return false;
569
569
  }
570
570
  return true;
571
571
  }
@@ -615,7 +615,7 @@ class BaseReporter {
615
615
  if (errors.length) this.ctx.logger.printUnhandledErrors(errors), this.error();
616
616
  }
617
617
  reportBenchmarkSummary(files) {
618
- const benches = getTests(files), topBenches = benches.filter((i) => i.result?.benchmark?.rank === 1);
618
+ const topBenches = getTests(files).filter((i) => i.result?.benchmark?.rank === 1);
619
619
  this.log(`\n${withLabel("cyan", "BENCH", "Summary\n")}`);
620
620
  for (const bench of topBenches) {
621
621
  const group = bench.suite || bench.file;
@@ -893,11 +893,10 @@ class SummaryReporter {
893
893
  else if (state === "failed") this.modules.failed++;
894
894
  else if (module.task.mode === "todo" && state === "skipped") this.modules.todo++;
895
895
  else if (state === "skipped") this.modules.skipped++;
896
- const left = this.modules.total - this.modules.completed;
897
896
  // Keep finished tests visible in summary for a while if there are more tests left.
898
897
  // When a new test starts in onTestModuleQueued it will take this ones place.
899
898
  // This reduces flickering by making summary more stable.
900
- if (left > this.maxParallelTests) this.finishedModules.set(module.id, setTimeout(() => {
899
+ if (this.modules.total - this.modules.completed > this.maxParallelTests) this.finishedModules.set(module.id, setTimeout(() => {
901
900
  this.removeTestModule(module.id);
902
901
  }, FINISHED_TEST_CLEANUP_TIME_MS).unref());
903
902
  else
@@ -1122,12 +1121,12 @@ function capturePrintError(error, ctx, options) {
1122
1121
  } }), console = new Console(writable), logger = {
1123
1122
  error: console.error.bind(console),
1124
1123
  highlight: ctx.logger.highlight.bind(ctx.logger)
1125
- }, result = printError(error, ctx, logger, {
1126
- showCodeFrame: false,
1127
- ...options
1128
- });
1124
+ };
1129
1125
  return {
1130
- nearest: result?.nearest,
1126
+ nearest: printError(error, ctx, logger, {
1127
+ showCodeFrame: false,
1128
+ ...options
1129
+ })?.nearest,
1131
1130
  output
1132
1131
  };
1133
1132
  }
@@ -1175,19 +1174,17 @@ function printErrorInner(error, project, options) {
1175
1174
  const stacks = options.parseErrorStacktrace(e), nearest = error instanceof TypeCheckError ? error.stacks[0] : stacks.find((stack) => {
1176
1175
  // we are checking that this module was processed by us at one point
1177
1176
  try {
1178
- const environments = [...Object.values(project._vite?.environments || {}), ...Object.values(project.browser?.vite.environments || {})], hasResult = environments.some((environment) => {
1179
- const modules = environment.moduleGraph.getModulesByFile(stack.file);
1180
- return [...modules?.values() || []].some((module) => !!module.transformResult);
1181
- });
1182
- return hasResult && existsSync(stack.file);
1177
+ return [...Object.values(project._vite?.environments || {}), ...Object.values(project.browser?.vite.environments || {})].some((environment) => {
1178
+ return [...environment.moduleGraph.getModulesByFile(stack.file)?.values() || []].some((module) => !!module.transformResult);
1179
+ }) && existsSync(stack.file);
1183
1180
  } catch {
1184
1181
  return false;
1185
1182
  }
1186
1183
  });
1187
1184
  if (type) printErrorType(type, project.vitest);
1188
1185
  if (printErrorMessage(e, logger), options.screenshotPaths?.length) {
1189
- const length = options.screenshotPaths.length;
1190
- if (logger.error(`\nFailure screenshot${length > 1 ? "s" : ""}:`), logger.error(options.screenshotPaths.map((p) => ` - ${c.dim(relative(process.cwd(), p))}`).join("\n")), !e.diff) logger.error();
1186
+ const uniqueScreenshots = Array.from(new Set(options.screenshotPaths)), length = uniqueScreenshots.length;
1187
+ if (logger.error(`\nFailure screenshot${length > 1 ? "s" : ""}:`), logger.error(uniqueScreenshots.map((p) => ` - ${c.dim(relative(process.cwd(), p))}`).join("\n")), !e.diff) logger.error();
1191
1188
  }
1192
1189
  if (e.codeFrame) logger.error(`${e.codeFrame}\n`);
1193
1190
  if ("__vitest_rollup_error__" in e) {
@@ -1426,7 +1423,7 @@ const BUILT_IN_TYPES = [
1426
1423
  "warning"
1427
1424
  ];
1428
1425
  function getTitle(type) {
1429
- return BUILT_IN_TYPES.includes(type) ? void 0 : type;
1426
+ if (!BUILT_IN_TYPES.includes(type)) return type;
1430
1427
  }
1431
1428
  function getType(type) {
1432
1429
  return BUILT_IN_TYPES.includes(type) ? type : "notice";
@@ -1453,8 +1450,7 @@ function escapeProperty(s) {
1453
1450
  class HangingProcessReporter {
1454
1451
  whyRunning;
1455
1452
  onInit() {
1456
- const _require = createRequire(import.meta.url);
1457
- this.whyRunning = _require("why-is-node-running");
1453
+ this.whyRunning = createRequire(import.meta.url)("why-is-node-running");
1458
1454
  }
1459
1455
  onProcessTimeout() {
1460
1456
  this.whyRunning?.();
@@ -1614,8 +1610,7 @@ class JUnitReporter {
1614
1610
  this.reportFile = resolve(this.ctx.config.root, outputFile);
1615
1611
  const outputDirectory = dirname(this.reportFile);
1616
1612
  if (!existsSync(outputDirectory)) await promises.mkdir(outputDirectory, { recursive: true });
1617
- const fileFd = await promises.open(this.reportFile, "w+");
1618
- this.fileFd = fileFd, this.baseLog = async (text) => {
1613
+ this.fileFd = await promises.open(this.reportFile, "w+"), this.baseLog = async (text) => {
1619
1614
  if (!this.fileFd) this.fileFd = await promises.open(this.reportFile, "w+");
1620
1615
  await promises.writeFile(this.fileFd, `${text}\n`);
1621
1616
  };
@@ -1778,7 +1773,7 @@ class TapReporter {
1778
1773
  this.logger.log(`# ${type}: ${message}`);
1779
1774
  }), this.logger.unindent();
1780
1775
  if (task.result?.state === "fail" && task.result.errors) this.logger.indent(), task.result.errors.forEach((error) => {
1781
- const stacks = task.file.pool === "browser" ? project.browser?.parseErrorStacktrace(error) || [] : parseErrorStacktrace(error, { frameFilter: this.ctx.config.onStackTrace }), stack = stacks[0];
1776
+ const stack = (task.file.pool === "browser" ? project.browser?.parseErrorStacktrace(error) || [] : parseErrorStacktrace(error, { frameFilter: this.ctx.config.onStackTrace }))[0];
1782
1777
  if (this.logger.log("---"), this.logger.log("error:"), this.logger.indent(), this.logErrorDetails(error), this.logger.unindent(), stack) this.logger.log(`at: ${yamlString(`${stack.file}:${stack.line}:${stack.column}`)}`);
1783
1778
  if (error.showDiff) this.logger.log(`actual: ${yamlString(error.actual)}`), this.logger.log(`expected: ${yamlString(error.expected)}`);
1784
1779
  }), this.logger.log("..."), this.logger.unindent();