@pasosdejesus/m 0.24.0 → 0.26.0

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 (169) hide show
  1. package/dist/CHANGELOG.md +75 -1
  2. package/dist/base-model/baseline.generated.d.ts +48 -0
  3. package/dist/base-model/baseline.generated.d.ts.map +1 -0
  4. package/dist/base-model/baseline.generated.js +930 -0
  5. package/dist/base-model/baseline.generated.js.map +1 -0
  6. package/dist/base-model/check.d.ts +6 -0
  7. package/dist/base-model/check.d.ts.map +1 -0
  8. package/dist/base-model/check.js +195 -0
  9. package/dist/base-model/check.js.map +1 -0
  10. package/dist/base-model/generate.d.ts +42 -0
  11. package/dist/base-model/generate.d.ts.map +1 -0
  12. package/dist/base-model/generate.js +241 -0
  13. package/dist/base-model/generate.js.map +1 -0
  14. package/dist/base-model/guidelines.d.ts +13 -0
  15. package/dist/base-model/guidelines.d.ts.map +1 -0
  16. package/dist/base-model/guidelines.js +61 -0
  17. package/dist/base-model/guidelines.js.map +1 -0
  18. package/dist/base-model/index.d.ts +22 -0
  19. package/dist/base-model/index.d.ts.map +1 -0
  20. package/dist/base-model/index.js +26 -0
  21. package/dist/base-model/index.js.map +1 -0
  22. package/dist/base-model/parse-structure.d.ts +4 -0
  23. package/dist/base-model/parse-structure.d.ts.map +1 -0
  24. package/dist/base-model/parse-structure.js +170 -0
  25. package/dist/base-model/parse-structure.js.map +1 -0
  26. package/dist/base-model/queries.d.ts +34 -0
  27. package/dist/base-model/queries.d.ts.map +1 -0
  28. package/dist/base-model/queries.js +118 -0
  29. package/dist/base-model/queries.js.map +1 -0
  30. package/dist/base-model/references/learn-tg.d.ts +21 -0
  31. package/dist/base-model/references/learn-tg.d.ts.map +1 -0
  32. package/dist/base-model/references/learn-tg.js +65 -0
  33. package/dist/base-model/references/learn-tg.js.map +1 -0
  34. package/dist/base-model/references/msip.d.ts +29 -0
  35. package/dist/base-model/references/msip.d.ts.map +1 -0
  36. package/dist/base-model/references/msip.js +33 -0
  37. package/dist/base-model/references/msip.js.map +1 -0
  38. package/dist/base-model/types.d.ts +207 -0
  39. package/dist/base-model/types.d.ts.map +1 -0
  40. package/dist/base-model/types.js +10 -0
  41. package/dist/base-model/types.js.map +1 -0
  42. package/dist/base-model/version.d.ts +19 -0
  43. package/dist/base-model/version.d.ts.map +1 -0
  44. package/dist/base-model/version.js +26 -0
  45. package/dist/base-model/version.js.map +1 -0
  46. package/dist/base-model/wallet-link.d.ts +69 -0
  47. package/dist/base-model/wallet-link.d.ts.map +1 -0
  48. package/dist/base-model/wallet-link.js +220 -0
  49. package/dist/base-model/wallet-link.js.map +1 -0
  50. package/dist/base-model/wallet-link.test.d.ts +2 -0
  51. package/dist/base-model/wallet-link.test.d.ts.map +1 -0
  52. package/dist/base-model/wallet-link.test.js +147 -0
  53. package/dist/base-model/wallet-link.test.js.map +1 -0
  54. package/dist/e2e/full-wallet.d.ts +19 -0
  55. package/dist/e2e/full-wallet.d.ts.map +1 -1
  56. package/dist/e2e/full-wallet.js +12 -4
  57. package/dist/e2e/full-wallet.js.map +1 -1
  58. package/dist/e2e/full-wallet.test.js +26 -0
  59. package/dist/e2e/full-wallet.test.js.map +1 -1
  60. package/dist/e2e/in-app-wallet.d.ts +23 -0
  61. package/dist/e2e/in-app-wallet.d.ts.map +1 -0
  62. package/dist/e2e/in-app-wallet.js +40 -0
  63. package/dist/e2e/in-app-wallet.js.map +1 -0
  64. package/dist/e2e/in-app-wallet.test.d.ts +2 -0
  65. package/dist/e2e/in-app-wallet.test.d.ts.map +1 -0
  66. package/dist/e2e/in-app-wallet.test.js +52 -0
  67. package/dist/e2e/in-app-wallet.test.js.map +1 -0
  68. package/dist/e2e/index.d.ts +5 -1
  69. package/dist/e2e/index.d.ts.map +1 -1
  70. package/dist/e2e/index.js +2 -0
  71. package/dist/e2e/index.js.map +1 -1
  72. package/dist/e2e/warmup.d.ts +38 -0
  73. package/dist/e2e/warmup.d.ts.map +1 -0
  74. package/dist/e2e/warmup.js +84 -0
  75. package/dist/e2e/warmup.js.map +1 -0
  76. package/dist/e2e/warmup.test.d.ts +2 -0
  77. package/dist/e2e/warmup.test.d.ts.map +1 -0
  78. package/dist/e2e/warmup.test.js +67 -0
  79. package/dist/e2e/warmup.test.js.map +1 -0
  80. package/dist/i18n/locales/cli.d.ts.map +1 -1
  81. package/dist/i18n/locales/cli.js +10 -0
  82. package/dist/i18n/locales/cli.js.map +1 -1
  83. package/dist/m.js +19 -1
  84. package/dist/m.js.map +1 -1
  85. package/dist/tasks/base-model.d.ts +4 -0
  86. package/dist/tasks/base-model.d.ts.map +1 -0
  87. package/dist/tasks/base-model.js +260 -0
  88. package/dist/tasks/base-model.js.map +1 -0
  89. package/dist/tasks/db.d.ts.map +1 -1
  90. package/dist/tasks/db.js +27 -0
  91. package/dist/tasks/db.js.map +1 -1
  92. package/dist/tasks/e2e-summary.d.ts +13 -0
  93. package/dist/tasks/e2e-summary.d.ts.map +1 -0
  94. package/dist/tasks/e2e-summary.js +117 -0
  95. package/dist/tasks/e2e-summary.js.map +1 -0
  96. package/dist/tasks/e2e.d.ts +29 -0
  97. package/dist/tasks/e2e.d.ts.map +1 -1
  98. package/dist/tasks/e2e.js +130 -36
  99. package/dist/tasks/e2e.js.map +1 -1
  100. package/dist/tasks/e2e.test.d.ts +2 -0
  101. package/dist/tasks/e2e.test.d.ts.map +1 -0
  102. package/dist/tasks/e2e.test.js +108 -0
  103. package/dist/tasks/e2e.test.js.map +1 -0
  104. package/dist/tasks/warmup.d.ts +4 -0
  105. package/dist/tasks/warmup.d.ts.map +1 -0
  106. package/dist/tasks/warmup.js +67 -0
  107. package/dist/tasks/warmup.js.map +1 -0
  108. package/dist/tasks/warmup.test.d.ts +2 -0
  109. package/dist/tasks/warmup.test.d.ts.map +1 -0
  110. package/dist/tasks/warmup.test.js +40 -0
  111. package/dist/tasks/warmup.test.js.map +1 -0
  112. package/dist/templates/apps/nextjs/package.json.hbs +1 -1
  113. package/dist/test-utils/console.d.ts +37 -0
  114. package/dist/test-utils/console.d.ts.map +1 -0
  115. package/dist/test-utils/console.js +52 -0
  116. package/dist/test-utils/console.js.map +1 -0
  117. package/dist/test-utils/console.test.d.ts +2 -0
  118. package/dist/test-utils/console.test.d.ts.map +1 -0
  119. package/dist/test-utils/console.test.js +57 -0
  120. package/dist/test-utils/console.test.js.map +1 -0
  121. package/dist/test-utils/index.d.ts +1 -0
  122. package/dist/test-utils/index.d.ts.map +1 -1
  123. package/dist/test-utils/index.js +1 -0
  124. package/dist/test-utils/index.js.map +1 -1
  125. package/dist/test-utils/kysely-mocks.d.ts +163 -33
  126. package/dist/test-utils/kysely-mocks.d.ts.map +1 -1
  127. package/dist/test-utils/kysely-mocks.js +147 -18
  128. package/dist/test-utils/kysely-mocks.js.map +1 -1
  129. package/dist/test-utils/kysely-mocks.test.d.ts +2 -0
  130. package/dist/test-utils/kysely-mocks.test.d.ts.map +1 -0
  131. package/dist/test-utils/kysely-mocks.test.js +94 -0
  132. package/dist/test-utils/kysely-mocks.test.js.map +1 -0
  133. package/dist/wallet/next/components/InAppWalletSetup.d.ts +11 -0
  134. package/dist/wallet/next/components/InAppWalletSetup.d.ts.map +1 -0
  135. package/dist/wallet/next/components/InAppWalletSetup.js +55 -0
  136. package/dist/wallet/next/components/InAppWalletSetup.js.map +1 -0
  137. package/dist/wallet/next/components/InAppWalletUnlock.d.ts +9 -0
  138. package/dist/wallet/next/components/InAppWalletUnlock.d.ts.map +1 -0
  139. package/dist/wallet/next/components/InAppWalletUnlock.js +29 -0
  140. package/dist/wallet/next/components/InAppWalletUnlock.js.map +1 -0
  141. package/dist/wallet/next/components.test.d.ts +2 -0
  142. package/dist/wallet/next/components.test.d.ts.map +1 -0
  143. package/dist/wallet/next/components.test.js +122 -0
  144. package/dist/wallet/next/components.test.js.map +1 -0
  145. package/dist/wallet/next/i18n.d.ts +63 -0
  146. package/dist/wallet/next/i18n.d.ts.map +1 -0
  147. package/dist/wallet/next/i18n.js +64 -0
  148. package/dist/wallet/next/i18n.js.map +1 -0
  149. package/dist/wallet/next/index.d.ts +7 -0
  150. package/dist/wallet/next/index.d.ts.map +1 -0
  151. package/dist/wallet/next/index.js +12 -0
  152. package/dist/wallet/next/index.js.map +1 -0
  153. package/dist/wallet/next/namespaces.d.ts +17 -0
  154. package/dist/wallet/next/namespaces.d.ts.map +1 -0
  155. package/dist/wallet/next/namespaces.js +17 -0
  156. package/dist/wallet/next/namespaces.js.map +1 -0
  157. package/dist/wallet/next/useInAppWallet.d.ts +55 -0
  158. package/dist/wallet/next/useInAppWallet.d.ts.map +1 -0
  159. package/dist/wallet/next/useInAppWallet.js +261 -0
  160. package/dist/wallet/next/useInAppWallet.js.map +1 -0
  161. package/dist/wallet/next/useInAppWallet.test.d.ts +2 -0
  162. package/dist/wallet/next/useInAppWallet.test.d.ts.map +1 -0
  163. package/dist/wallet/next/useInAppWallet.test.js +261 -0
  164. package/dist/wallet/next/useInAppWallet.test.js.map +1 -0
  165. package/package.json +9 -1
  166. package/src/e2e/README.md +58 -0
  167. package/src/tasks/README.md +1 -0
  168. package/src/test-utils/README.md +28 -0
  169. package/src/wallet/README.md +25 -2
@@ -1,2 +1,31 @@
1
+ /** Stable, machine-readable prefix consumed by `test:e2e:summary` (P4). */
2
+ export declare const RESULT_PREFIX = "[e2e-result] ";
3
+ export type E2eResult = 'ok' | 'fail' | 'skip';
4
+ /** One spec result line; `<file>` is the spec file name (e.g. `donate.spec.mjs`). */
5
+ export declare function resultLine(file: string, result: E2eResult): string;
6
+ /**
7
+ * Classifies a spec by exit code, and marks a successful spec that printed `[SKIP]`
8
+ * as skipped. A non-zero exit always wins (a spec that failed is not a skip).
9
+ */
10
+ export declare function classifyResult(status: number | null, output: string): E2eResult;
11
+ export interface RetryPlan {
12
+ retries: number;
13
+ retryDelayMs: number;
14
+ specDelayMs: number;
15
+ /** Injectable sleep (tests). */
16
+ sleep?: (ms: number) => Promise<void>;
17
+ onRetry?: (attempt: number, failedFiles: string[]) => void;
18
+ }
19
+ /**
20
+ * Runs every spec once, then re-runs each failed spec on its own up to `retries`
21
+ * times. Returns the final per-spec result and the attempt count. Extracted from
22
+ * `runE2e` so the retry policy is unit-testable without spawning processes.
23
+ */
24
+ export declare function runSpecsWithRetry<S extends {
25
+ file: string;
26
+ }>(specs: S[], runOne: (spec: S, attempt: number) => Promise<E2eResult>, plan: RetryPlan): Promise<{
27
+ results: Map<string, E2eResult>;
28
+ attempts: Map<string, number>;
29
+ }>;
1
30
  export declare function runE2e(testPattern?: string, args?: string[]): Promise<void>;
2
31
  //# sourceMappingURL=e2e.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"e2e.d.ts","sourceRoot":"","sources":["../../src/tasks/e2e.ts"],"names":[],"mappings":"AA2CA,wBAAsB,MAAM,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,iBAwGrE"}
1
+ {"version":3,"file":"e2e.d.ts","sourceRoot":"","sources":["../../src/tasks/e2e.ts"],"names":[],"mappings":"AAiDA,2EAA2E;AAC3E,eAAO,MAAM,aAAa,kBAAkB,CAAA;AAC5C,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAA;AAE9C,qFAAqF;AACrF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,MAAM,CAElE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAG/E;AA+BD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,gCAAgC;IAChC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;CAC3D;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAChE,KAAK,EAAE,CAAC,EAAE,EACV,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,EACxD,IAAI,EAAE,SAAS,GACd,OAAO,CAAC;IAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC,CA4B7E;AAED,wBAAsB,MAAM,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,iBAoHrE"}
package/dist/tasks/e2e.js CHANGED
@@ -1,5 +1,10 @@
1
1
  // test:e2e — Run E2E tests with Puppeteer + SIWE on OpenBSD/adJ
2
- import { spawnSync } from 'child_process';
2
+ //
3
+ // P3 (m/REQ/49): `--retry <N>` re-runs each failed spec on its own, and every
4
+ // spec/attempt emits one stable machine-readable line (`[e2e-result] <file> <r>`)
5
+ // that `test:e2e:summary` (P4) consumes. The full stream is also saved to
6
+ // `E2E_LOG_DIR` (default /tmp).
7
+ import { spawn } from 'child_process';
3
8
  import * as fs from 'fs';
4
9
  import * as path from 'path';
5
10
  import { globSync } from 'glob';
@@ -16,9 +21,13 @@ const t = createTranslator(detectLocale(), {
16
21
  'e2e.no_specs': 'No spec files found in {{0}} matching: {{1}}',
17
22
  'e2e.found': 'Found {{0}} spec(s)',
18
23
  'e2e.running': '▶ {{0}}',
24
+ 'e2e.retry_attempt': '▶ {{0}} (attempt {{1}})',
25
+ 'e2e.retry_start': 'Retrying {{0}} spec(s) — attempt {{1}}/{{2}}',
19
26
  'e2e.failed': ' ✗ {{0}} failed (exit {{1}})',
20
27
  'e2e.all_passed': 'All {{0}} spec(s) passed.',
21
28
  'e2e.partial': '{{0}}/{{1}} spec(s) failed.',
29
+ 'e2e.still_failing': 'Still failing after {{0}} retry(ies): {{1}}',
30
+ 'e2e.log_saved': 'Log saved to {{0}}',
22
31
  },
23
32
  es: {
24
33
  'e2e.no_dir': 'No se encontró directorio e2e/. Esperado: e2e/specs/ o e2e/smoke/',
@@ -27,11 +36,34 @@ const t = createTranslator(detectLocale(), {
27
36
  'e2e.no_specs': 'No se encontraron archivos spec en {{0}} coincidiendo con: {{1}}',
28
37
  'e2e.found': '{{0}} spec(s) encontrado(s)',
29
38
  'e2e.running': '▶ {{0}}',
39
+ 'e2e.retry_attempt': '▶ {{0}} (intento {{1}})',
40
+ 'e2e.retry_start': 'Reintentando {{0}} spec(s) — intento {{1}}/{{2}}',
30
41
  'e2e.failed': ' ✗ {{0}} falló (exit {{1}})',
31
42
  'e2e.all_passed': 'Todos los {{0}} spec(s) pasaron.',
32
43
  'e2e.partial': '{{0}}/{{1}} spec(s) fallaron.',
44
+ 'e2e.still_failing': 'Siguen fallando tras {{0}} reintento(s): {{1}}',
45
+ 'e2e.log_saved': 'Log guardado en {{0}}',
33
46
  },
34
47
  }, commonCli);
48
+ /** Stable, machine-readable prefix consumed by `test:e2e:summary` (P4). */
49
+ export const RESULT_PREFIX = '[e2e-result] ';
50
+ /** One spec result line; `<file>` is the spec file name (e.g. `donate.spec.mjs`). */
51
+ export function resultLine(file, result) {
52
+ return `${RESULT_PREFIX}${file} ${result}`;
53
+ }
54
+ /**
55
+ * Classifies a spec by exit code, and marks a successful spec that printed `[SKIP]`
56
+ * as skipped. A non-zero exit always wins (a spec that failed is not a skip).
57
+ */
58
+ export function classifyResult(status, output) {
59
+ if (status !== 0)
60
+ return 'fail';
61
+ return /\[SKIP\]/.test(output) ? 'skip' : 'ok';
62
+ }
63
+ function getFlag(args, name) {
64
+ const idx = args.indexOf(name);
65
+ return idx >= 0 && idx + 1 < args.length ? args[idx + 1] : null;
66
+ }
35
67
  function findSpecs(subDir, pattern, e2eDir) {
36
68
  const specDir = path.join(e2eDir, subDir);
37
69
  if (!fs.existsSync(specDir))
@@ -39,6 +71,57 @@ function findSpecs(subDir, pattern, e2eDir) {
39
71
  const files = globSync(pattern, { cwd: specDir });
40
72
  return files.map(f => ({ file: f, dir: specDir }));
41
73
  }
74
+ /** Runs one spec, streaming and capturing its output. */
75
+ function runSpec(specPath, env) {
76
+ return new Promise((resolve, reject) => {
77
+ const child = spawn(process.execPath, [specPath], { cwd: process.cwd(), env });
78
+ let output = '';
79
+ const onData = (chunk) => {
80
+ const text = chunk.toString();
81
+ output += text;
82
+ process.stdout.write(text);
83
+ };
84
+ child.stdout.on('data', onData);
85
+ child.stderr.on('data', onData);
86
+ child.on('error', reject);
87
+ child.on('close', (code) => resolve({ status: code ?? 1, output }));
88
+ });
89
+ }
90
+ /**
91
+ * Runs every spec once, then re-runs each failed spec on its own up to `retries`
92
+ * times. Returns the final per-spec result and the attempt count. Extracted from
93
+ * `runE2e` so the retry policy is unit-testable without spawning processes.
94
+ */
95
+ export async function runSpecsWithRetry(specs, runOne, plan) {
96
+ const sleep = plan.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
97
+ const results = new Map();
98
+ const attempts = new Map();
99
+ for (let i = 0; i < specs.length; i++) {
100
+ const spec = specs[i];
101
+ results.set(spec.file, await runOne(spec, 1));
102
+ attempts.set(spec.file, 1);
103
+ if (plan.specDelayMs > 0 && i < specs.length - 1)
104
+ await sleep(plan.specDelayMs);
105
+ }
106
+ let failed = specs.filter((s) => results.get(s.file) === 'fail');
107
+ for (let attempt = 1; attempt <= plan.retries && failed.length > 0; attempt++) {
108
+ plan.onRetry?.(attempt, failed.map((s) => s.file));
109
+ if (plan.retryDelayMs > 0)
110
+ await sleep(plan.retryDelayMs);
111
+ const still = [];
112
+ for (const spec of failed) {
113
+ const result = await runOne(spec, attempt + 1);
114
+ results.set(spec.file, result);
115
+ attempts.set(spec.file, attempt + 1);
116
+ if (result === 'fail')
117
+ still.push(spec);
118
+ if (plan.specDelayMs > 0)
119
+ await sleep(plan.specDelayMs);
120
+ }
121
+ failed = still;
122
+ }
123
+ return { results, attempts };
124
+ }
42
125
  export async function runE2e(testPattern, args = []) {
43
126
  const cwd = process.cwd();
44
127
  // If testPattern looks like a flag, move it to args
@@ -48,6 +131,9 @@ export async function runE2e(testPattern, args = []) {
48
131
  }
49
132
  const smokeOnly = args.includes('--smoke');
50
133
  const grepFilter = args.includes('--grep') ? args[args.indexOf('--grep') + 1] : null;
134
+ const retries = Math.max(0, parseInt(getFlag(args, '--retry') ?? process.env.E2E_RETRIES ?? '0', 10) || 0);
135
+ const retryDelay = Math.max(0, parseInt(getFlag(args, '--retry-delay') ?? '15000', 10) || 0);
136
+ const logDir = process.env.E2E_LOG_DIR || '/tmp';
51
137
  // 1. Detect e2e directory
52
138
  const e2eDir = path.join(cwd, 'e2e');
53
139
  if (!fs.existsSync(e2eDir)) {
@@ -66,7 +152,6 @@ export async function runE2e(testPattern, args = []) {
66
152
  }
67
153
  // 3. Find specs — search in both specs/ and smoke/ when no flag specified
68
154
  let specFiles = [];
69
- // If pattern doesn't contain glob chars and isn't a full filename, wrap with *...*
70
155
  let pattern = testPattern || '**/*.spec.mjs';
71
156
  if (testPattern && !testPattern.includes('*') && !testPattern.endsWith('.spec.mjs')) {
72
157
  pattern = `*${testPattern}*.spec.mjs`;
@@ -75,7 +160,6 @@ export async function runE2e(testPattern, args = []) {
75
160
  specFiles = findSpecs('smoke', pattern, e2eDir);
76
161
  }
77
162
  else {
78
- // Try specs/ first, then smoke/
79
163
  specFiles = findSpecs('specs', pattern, e2eDir);
80
164
  if (specFiles.length === 0) {
81
165
  specFiles = findSpecs('smoke', pattern, e2eDir);
@@ -84,7 +168,6 @@ export async function runE2e(testPattern, args = []) {
84
168
  }
85
169
  }
86
170
  }
87
- // Apply grep filter
88
171
  if (grepFilter && specFiles.length > 0) {
89
172
  specFiles = specFiles.filter(s => s.file.includes(grepFilter));
90
173
  }
@@ -94,43 +177,54 @@ export async function runE2e(testPattern, args = []) {
94
177
  process.exit(0);
95
178
  }
96
179
  info(t("e2e.found", String(specFiles.length)));
97
- // 4. Run each spec
98
- let failures = 0;
180
+ // 4. Log file (best effort) for `test:e2e:summary`.
181
+ const stamp = new Date().toISOString().replace(/[:.]/g, '-');
182
+ const logFile = path.join(logDir, `e2e-${stamp}.log`);
183
+ let log = null;
184
+ try {
185
+ log = fs.createWriteStream(logFile);
186
+ info(t("e2e.log_saved", logFile));
187
+ }
188
+ catch {
189
+ log = null;
190
+ }
99
191
  const specDelay = parseInt(process.env.E2E_SPEC_DELAY_MS || '1500', 10);
100
- for (let i = 0; i < specFiles.length; i++) {
101
- const { file, dir } = specFiles[i];
102
- const specPath = path.join(dir, file);
103
- info(`\n▶ ${path.relative(e2eDir, specPath)}`);
104
- const env = { ...process.env };
192
+ // Every spec RUN (including retries) gets a fresh WALLET_INDEX so a retry does
193
+ // not hammer the site's per-wallet rate limit.
194
+ let walletRun = 0;
195
+ const runOne = async (spec, attempt) => {
196
+ const specPath = path.join(spec.dir, spec.file);
197
+ const rel = path.relative(e2eDir, specPath);
198
+ const env = { ...process.env, WALLET_INDEX: String(walletRun++) };
105
199
  if (chromePath)
106
200
  env.CHROME_PATH = chromePath;
107
- // Rotación de billeteras entre specs (REQ/35): cada spec usa un índice
108
- // distinto de TEST_PRIVATE_KEYS para no martillar el rate-limit del sitio
109
- // con la misma billetera. initTestEnv elige account = wallets[idx % len].
110
- env.WALLET_INDEX = String(i);
111
- const res = spawnSync('node', [specPath], {
112
- stdio: 'inherit',
113
- env,
114
- cwd,
115
- });
116
- if (res.status !== 0) {
117
- failures++;
118
- problem(t("e2e.failed", file, String(res.status)));
119
- }
120
- // Pausa configurable entre specs: el dev site limita requests por wallet
121
- // (429); dar aire entre specs reduce la flakiness de la suite.
122
- if (specDelay > 0 && i < specFiles.length - 1) {
123
- await new Promise((r) => setTimeout(r, specDelay));
124
- }
125
- }
126
- // 5. Summary
127
- if (failures === 0) {
128
- success("\n" + t("e2e.all_passed", String(specFiles.length)));
201
+ info('\n' + (attempt > 1 ? t("e2e.retry_attempt", rel, String(attempt)) : t("e2e.running", rel)));
202
+ const { status, output } = await runSpec(specPath, env);
203
+ const result = classifyResult(status, output);
204
+ const line = resultLine(spec.file, result);
205
+ console.log(line);
206
+ if (result === 'fail')
207
+ problem(t("e2e.failed", spec.file, String(status)));
208
+ log?.write(`▶ ${rel}\n${output}\n${line}\n`);
209
+ return result;
210
+ };
211
+ // 5. Run pass 1 and the retries.
212
+ const { results } = await runSpecsWithRetry(specFiles, runOne, {
213
+ retries,
214
+ retryDelayMs: retryDelay,
215
+ specDelayMs: specDelay,
216
+ onRetry: (attempt, files) => info('\n' + t("e2e.retry_start", String(files.length), String(attempt), String(retries))),
217
+ });
218
+ log?.end();
219
+ // 7. Summary. A spec is green only by exit code.
220
+ const failures = specFiles.filter((s) => results.get(s.file) === 'fail');
221
+ if (failures.length === 0) {
222
+ success('\n' + t("e2e.all_passed", String(specFiles.length)));
129
223
  }
130
224
  else {
131
- problem("\n" + t("e2e.partial", String(failures), String(specFiles.length)));
225
+ problem('\n' + t("e2e.partial", String(failures.length), String(specFiles.length)));
226
+ problem(t("e2e.still_failing", String(retries), failures.map((s) => s.file).join(', ')));
132
227
  }
133
- // process.exit() is mandatory in m CLI commands
134
- process.exit(failures > 0 ? 1 : 0);
228
+ process.exit(failures.length > 0 ? 1 : 0);
135
229
  }
136
230
  //# sourceMappingURL=e2e.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"e2e.js","sourceRoot":"","sources":["../../src/tasks/e2e.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AACxB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAA;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,SAAS,MAAM,uBAAuB,CAAC;AAE9C,MAAM,CAAC,GAAG,gBAAgB,CAAC,YAAY,EAAE,EAAE;IACzC,EAAE,EAAE;QACF,YAAY,EAAE,6DAA6D;QAC3E,eAAe,EAAE,iFAAiF;QAClG,cAAc,EAAE,uGAAuG;QACvH,cAAc,EAAE,8CAA8C;QAC9D,WAAW,EAAE,qBAAqB;QAClC,aAAa,EAAE,SAAS;QACxB,YAAY,EAAE,+BAA+B;QAC7C,gBAAgB,EAAE,2BAA2B;QAC7C,aAAa,EAAE,6BAA6B;KAC7C;IACD,EAAE,EAAE;QACF,YAAY,EAAE,mEAAmE;QACjF,eAAe,EAAE,oGAAoG;QACrH,cAAc,EAAE,uGAAuG;QACvH,cAAc,EAAE,kEAAkE;QAClF,WAAW,EAAE,6BAA6B;QAC1C,aAAa,EAAE,SAAS;QACxB,YAAY,EAAE,8BAA8B;QAC5C,gBAAgB,EAAE,kCAAkC;QACpD,aAAa,EAAE,+BAA+B;KAC/C;CACF,EAAE,SAAS,CAAC,CAAC;AAEd,SAAS,SAAS,CAAC,MAAc,EAAE,OAAe,EAAE,MAAc;IAChE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACzC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAA;IACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAA;IACjD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,CAAA;AACpD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,WAAoB,EAAE,OAAiB,EAAE;IACpE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IAEzB,oDAAoD;IACpD,IAAI,WAAW,IAAI,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;QACzB,WAAW,GAAG,SAAS,CAAA;IACzB,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;IAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAEpF,0BAA0B;IAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IACpC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAA;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,wCAAwC;IACxC,IAAI,UAAU,GAAkB,IAAI,CAAA;IACpC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,IAAI,CAAC;YACH,UAAU,GAAG,UAAU,EAAE,CAAA;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAA;QAC1B,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,IAAI,SAAS,GAAyC,EAAE,CAAA;IACxD,mFAAmF;IACnF,IAAI,OAAO,GAAG,WAAW,IAAI,eAAe,CAAA;IAC5C,IAAI,WAAW,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACpF,OAAO,GAAG,IAAI,WAAW,YAAY,CAAA;IACvC,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACd,SAAS,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;IACjD,CAAC;SAAM,CAAC;QACN,gCAAgC;QAChC,SAAS,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;QAC/C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,SAAS,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;YAC/C,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAA;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED,oBAAoB;IACpB,IAAI,UAAU,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvC,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAA;IAChE,CAAC;IAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,2BAA2B,CAAA;QACnE,IAAI,CAAC,CAAC,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;QACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IAE9C,mBAAmB;IACnB,IAAI,QAAQ,GAAG,CAAC,CAAA;IAChB,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,MAAM,EAAE,EAAE,CAAC,CAAA;IACvE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QACrC,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAA;QAE9C,MAAM,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;QAC9B,IAAI,UAAU;YAAE,GAAG,CAAC,WAAW,GAAG,UAAU,CAAA;QAC5C,uEAAuE;QACvE,0EAA0E;QAC1E,0EAA0E;QAC1E,GAAG,CAAC,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;QAE5B,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE;YACxC,KAAK,EAAE,SAAS;YAChB,GAAG;YACH,GAAG;SACJ,CAAC,CAAA;QAEF,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrB,QAAQ,EAAE,CAAA;YACV,OAAO,CAAC,CAAC,CAAC,YAAY,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QACpD,CAAC;QACD,yEAAyE;QACzE,+DAA+D;QAC/D,IAAI,SAAS,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAA;QACpD,CAAC;IACH,CAAC;IAED,aAAa;IACb,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,gBAAgB,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IAC/D,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IAC9E,CAAC;IAED,gDAAgD;IAChD,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AACpC,CAAC"}
1
+ {"version":3,"file":"e2e.js","sourceRoot":"","sources":["../../src/tasks/e2e.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,EAAE;AACF,8EAA8E;AAC9E,kFAAkF;AAClF,0EAA0E;AAC1E,gCAAgC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AACrC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AACxB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAA;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,SAAS,MAAM,uBAAuB,CAAC;AAE9C,MAAM,CAAC,GAAG,gBAAgB,CAAC,YAAY,EAAE,EAAE;IACzC,EAAE,EAAE;QACF,YAAY,EAAE,6DAA6D;QAC3E,eAAe,EAAE,iFAAiF;QAClG,cAAc,EAAE,uGAAuG;QACvH,cAAc,EAAE,8CAA8C;QAC9D,WAAW,EAAE,qBAAqB;QAClC,aAAa,EAAE,SAAS;QACxB,mBAAmB,EAAE,yBAAyB;QAC9C,iBAAiB,EAAE,8CAA8C;QACjE,YAAY,EAAE,+BAA+B;QAC7C,gBAAgB,EAAE,2BAA2B;QAC7C,aAAa,EAAE,6BAA6B;QAC5C,mBAAmB,EAAE,6CAA6C;QAClE,eAAe,EAAE,oBAAoB;KACtC;IACD,EAAE,EAAE;QACF,YAAY,EAAE,mEAAmE;QACjF,eAAe,EAAE,oGAAoG;QACrH,cAAc,EAAE,uGAAuG;QACvH,cAAc,EAAE,kEAAkE;QAClF,WAAW,EAAE,6BAA6B;QAC1C,aAAa,EAAE,SAAS;QACxB,mBAAmB,EAAE,yBAAyB;QAC9C,iBAAiB,EAAE,kDAAkD;QACrE,YAAY,EAAE,8BAA8B;QAC5C,gBAAgB,EAAE,kCAAkC;QACpD,aAAa,EAAE,+BAA+B;QAC9C,mBAAmB,EAAE,gDAAgD;QACrE,eAAe,EAAE,uBAAuB;KACzC;CACF,EAAE,SAAS,CAAC,CAAC;AAEd,2EAA2E;AAC3E,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAA;AAG5C,qFAAqF;AACrF,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,MAAiB;IACxD,OAAO,GAAG,aAAa,GAAG,IAAI,IAAI,MAAM,EAAE,CAAA;AAC5C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,MAAqB,EAAE,MAAc;IAClE,IAAI,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAA;IAC/B,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA;AAChD,CAAC;AAED,SAAS,OAAO,CAAC,IAAc,EAAE,IAAY;IAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9B,OAAO,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AACjE,CAAC;AAED,SAAS,SAAS,CAAC,MAAc,EAAE,OAAe,EAAE,MAAc;IAChE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACzC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAA;IACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAA;IACjD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,CAAA;AACpD,CAAC;AAED,yDAAyD;AACzD,SAAS,OAAO,CAAC,QAAgB,EAAE,GAAsB;IACvD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,CAAC,CAAA;QAC9E,IAAI,MAAM,GAAG,EAAE,CAAA;QACf,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,EAAE;YAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAA;YAC7B,MAAM,IAAI,IAAI,CAAA;YACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC5B,CAAC,CAAA;QACD,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC/B,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC/B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QACzB,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;IACrE,CAAC,CAAC,CAAA;AACJ,CAAC;AAWD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAU,EACV,MAAwD,EACxD,IAAe;IAEf,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;IACzF,MAAM,OAAO,GAAG,IAAI,GAAG,EAAqB,CAAA;IAC5C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAA;IAE1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QACrB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;QAC7C,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;QAC1B,IAAI,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IACjF,CAAC;IAED,IAAI,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,CAAA;IAChE,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;QAC9E,IAAI,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;QAClD,IAAI,IAAI,CAAC,YAAY,GAAG,CAAC;YAAE,MAAM,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QACzD,MAAM,KAAK,GAAQ,EAAE,CAAA;QACrB,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,CAAC,CAAC,CAAA;YAC9C,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;YAC9B,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,CAAC,CAAC,CAAA;YACpC,IAAI,MAAM,KAAK,MAAM;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACvC,IAAI,IAAI,CAAC,WAAW,GAAG,CAAC;gBAAE,MAAM,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QACzD,CAAC;QACD,MAAM,GAAG,KAAK,CAAA;IAChB,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAA;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,WAAoB,EAAE,OAAiB,EAAE;IACpE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IAEzB,oDAAoD;IACpD,IAAI,WAAW,IAAI,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;QACzB,WAAW,GAAG,SAAS,CAAA;IACzB,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;IAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IACpF,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAC1G,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,eAAe,CAAC,IAAI,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAC5F,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,MAAM,CAAA;IAEhD,0BAA0B;IAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IACpC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAA;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,wCAAwC;IACxC,IAAI,UAAU,GAAkB,IAAI,CAAA;IACpC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,IAAI,CAAC;YACH,UAAU,GAAG,UAAU,EAAE,CAAA;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAA;QAC1B,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,IAAI,SAAS,GAAyC,EAAE,CAAA;IACxD,IAAI,OAAO,GAAG,WAAW,IAAI,eAAe,CAAA;IAC5C,IAAI,WAAW,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACpF,OAAO,GAAG,IAAI,WAAW,YAAY,CAAA;IACvC,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACd,SAAS,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;IACjD,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;QAC/C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,SAAS,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;YAC/C,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAA;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,UAAU,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvC,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAA;IAChE,CAAC;IAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,2BAA2B,CAAA;QACnE,IAAI,CAAC,CAAC,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;QACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IAE9C,oDAAoD;IACpD,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;IAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC,CAAA;IACrD,IAAI,GAAG,GAA0B,IAAI,CAAA;IACrC,IAAI,CAAC;QACH,GAAG,GAAG,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAA;QACnC,IAAI,CAAC,CAAC,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAA;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,GAAG,IAAI,CAAA;IACZ,CAAC;IAED,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,MAAM,EAAE,EAAE,CAAC,CAAA;IACvE,+EAA+E;IAC/E,+CAA+C;IAC/C,IAAI,SAAS,GAAG,CAAC,CAAA;IAEjB,MAAM,MAAM,GAAG,KAAK,EAAE,IAAmC,EAAE,OAAe,EAAsB,EAAE;QAChG,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QAC3C,MAAM,GAAG,GAAsB,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,YAAY,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,CAAA;QACpF,IAAI,UAAU;YAAE,GAAG,CAAC,WAAW,GAAG,UAAU,CAAA;QAE5C,IAAI,CAAC,IAAI,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,mBAAmB,EAAE,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;QACjG,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;QACvD,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC7C,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QAC1C,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACjB,IAAI,MAAM,KAAK,MAAM;YAAE,OAAO,CAAC,CAAC,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QAC1E,GAAG,EAAE,KAAK,CAAC,KAAK,GAAG,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,CAAA;QAC5C,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;IAED,iCAAiC;IACjC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE;QAC7D,OAAO;QACP,YAAY,EAAE,UAAU;QACxB,WAAW,EAAE,SAAS;QACtB,OAAO,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAC1B,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,iBAAiB,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;KAC5F,CAAC,CAAA;IAEF,GAAG,EAAE,GAAG,EAAE,CAAA;IAEV,iDAAiD;IACjD,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,CAAA;IACxE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,gBAAgB,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IAC/D,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QACnF,OAAO,CAAC,CAAC,CAAC,mBAAmB,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC1F,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAC3C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=e2e.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2e.test.d.ts","sourceRoot":"","sources":["../../src/tasks/e2e.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,108 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { classifyResult, resultLine, runSpecsWithRetry } from './e2e.js';
3
+ import { parseE2eLog, renderE2eSummary } from './e2e-summary.js';
4
+ // P3/P4 (m/REQ/49): the runner emits a stable `[e2e-result] <file> <r>` line and
5
+ // `test:e2e:summary` consumes it (last attempt wins).
6
+ describe('classifyResult / resultLine', () => {
7
+ it('reports fail by exit code (even if it also printed [SKIP])', () => {
8
+ expect(classifyResult(1, 'anything')).toBe('fail');
9
+ expect(classifyResult(2, '[SKIP] x')).toBe('fail');
10
+ });
11
+ it('reports skip for a green spec that printed [SKIP]', () => {
12
+ expect(classifyResult(0, 'ran\n[SKIP] needs Chrome')).toBe('skip');
13
+ });
14
+ it('reports ok for a plain green spec', () => {
15
+ expect(classifyResult(0, '[OK] fine')).toBe('ok');
16
+ });
17
+ it('formats the machine-readable line', () => {
18
+ expect(resultLine('donate.spec.mjs', 'ok')).toBe('[e2e-result] donate.spec.mjs ok');
19
+ });
20
+ });
21
+ describe('parseE2eLog', () => {
22
+ it('reads the machine format and keeps the last result per spec', () => {
23
+ const log = [
24
+ '▶ specs/a.spec.mjs',
25
+ '[e2e-result] a.spec.mjs fail',
26
+ '▶ specs/b.spec.mjs',
27
+ '[e2e-result] b.spec.mjs ok',
28
+ '[e2e-retry] ▶ specs/a.spec.mjs (intento 1)',
29
+ '[e2e-result] a.spec.mjs ok',
30
+ ].join('\n');
31
+ const status = parseE2eLog(log);
32
+ expect(status.get('a.spec.mjs')).toBe('ok');
33
+ expect(status.get('b.spec.mjs')).toBe('ok');
34
+ });
35
+ it('falls back to the human format when there are no [e2e-result] lines', () => {
36
+ const log = [
37
+ '▶ specs/a.spec.mjs',
38
+ '[OK] fine',
39
+ '✅ 0 failures',
40
+ '▶ specs/b.spec.mjs',
41
+ '❌ 1 failures',
42
+ '▶ specs/c.spec.mjs',
43
+ 'started and never finished',
44
+ ].join('\n');
45
+ const status = parseE2eLog(log);
46
+ expect(status.get('a.spec.mjs')).toBe('ok');
47
+ expect(status.get('b.spec.mjs')).toBe('fail');
48
+ expect(status.get('c.spec.mjs')).toBe('?');
49
+ });
50
+ });
51
+ describe('renderE2eSummary', () => {
52
+ it('marks the specs whose state differs between runs', () => {
53
+ const site = parseE2eLog('[e2e-result] a.spec.mjs fail\n[e2e-result] b.spec.mjs ok');
54
+ const local = parseE2eLog('[e2e-result] a.spec.mjs ok\n[e2e-result] b.spec.mjs ok');
55
+ const out = renderE2eSummary([
56
+ { file: '/tmp/site.log', status: site },
57
+ { file: '/tmp/local.log', status: local },
58
+ ]);
59
+ expect(out).toContain('a.spec.mjs');
60
+ expect(out).toContain('<-- difiere');
61
+ expect(out).toContain('1 con estado distinto');
62
+ // b didn't differ, so its row must not carry the marker.
63
+ const bLine = out.split('\n').find((l) => l.startsWith('b.spec.mjs')) ?? '';
64
+ expect(bLine).not.toContain('<-- difiere');
65
+ });
66
+ });
67
+ describe('runSpecsWithRetry (P3)', () => {
68
+ it('retries a failing spec until it passes', async () => {
69
+ const calls = [];
70
+ const runOne = async (spec, attempt) => {
71
+ calls.push(`${spec.file}#${attempt}`);
72
+ return attempt >= 2 ? 'ok' : 'fail';
73
+ };
74
+ const { results, attempts } = await runSpecsWithRetry([{ file: 'a.spec.mjs' }], runOne, {
75
+ retries: 2, retryDelayMs: 0, specDelayMs: 0,
76
+ });
77
+ expect(results.get('a.spec.mjs')).toBe('ok');
78
+ expect(attempts.get('a.spec.mjs')).toBe(2);
79
+ expect(calls).toEqual(['a.spec.mjs#1', 'a.spec.mjs#2']);
80
+ });
81
+ it('stops after N retries and reports fail', async () => {
82
+ let n = 0;
83
+ const runOne = async () => { n += 1; return 'fail'; };
84
+ const { results, attempts } = await runSpecsWithRetry([{ file: 'a.spec.mjs' }], runOne, {
85
+ retries: 2, retryDelayMs: 0, specDelayMs: 0,
86
+ });
87
+ expect(results.get('a.spec.mjs')).toBe('fail');
88
+ expect(attempts.get('a.spec.mjs')).toBe(3); // 1 + 2 retries
89
+ expect(n).toBe(3);
90
+ });
91
+ it('does not retry when retries=0', async () => {
92
+ let n = 0;
93
+ const runOne = async () => { n += 1; return 'fail'; };
94
+ const { attempts } = await runSpecsWithRetry([{ file: 'a.spec.mjs' }], runOne, {
95
+ retries: 0, retryDelayMs: 0, specDelayMs: 0,
96
+ });
97
+ expect(attempts.get('a.spec.mjs')).toBe(1);
98
+ expect(n).toBe(1);
99
+ });
100
+ it('leaves a green spec untouched', async () => {
101
+ const runOne = async () => 'ok';
102
+ const { attempts } = await runSpecsWithRetry([{ file: 'a.spec.mjs' }], runOne, {
103
+ retries: 3, retryDelayMs: 0, specDelayMs: 0,
104
+ });
105
+ expect(attempts.get('a.spec.mjs')).toBe(1);
106
+ });
107
+ });
108
+ //# sourceMappingURL=e2e.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2e.test.js","sourceRoot":"","sources":["../../src/tasks/e2e.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /** Reads the route list from `e2e/warmup-paths.json` or `package.json:e2e.warmupPaths`. */
2
+ export declare function resolveWarmupPaths(cwd: string): string[] | null;
3
+ export declare function runWarmup(args: string[]): Promise<void>;
4
+ //# sourceMappingURL=warmup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warmup.d.ts","sourceRoot":"","sources":["../../src/tasks/warmup.ts"],"names":[],"mappings":"AAqBA,2FAA2F;AAC3F,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAsB/D;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB7D"}
@@ -0,0 +1,67 @@
1
+ // warmup — calienta un sitio (Next.js compila rutas bajo demanda) (m/REQ/49 P5).
2
+ //
3
+ // La lista de rutas vive en el consumidor: `e2e/warmup-paths.json` o
4
+ // `package.json:e2e.warmupPaths`. El sitio base sale de `SITE_URL`.
5
+ import * as fs from 'fs';
6
+ import * as path from 'path';
7
+ import { warmup } from '../e2e/warmup.js';
8
+ import { problem, info, success } from '../util/colors.js';
9
+ import { createTranslator } from '../i18n/createTranslator.js';
10
+ import { detectLocale } from '../util/locale.js';
11
+ import commonCli from '../i18n/common-cli.js';
12
+ const t = createTranslator(detectLocale(), {
13
+ en: {
14
+ 'warmup.no_paths': 'No warmup paths found. Create e2e/warmup-paths.json or set package.json:e2e.warmupPaths.',
15
+ },
16
+ es: {
17
+ 'warmup.no_paths': 'No se encontraron rutas de warmup. Crea e2e/warmup-paths.json o define package.json:e2e.warmupPaths.',
18
+ },
19
+ }, commonCli);
20
+ /** Reads the route list from `e2e/warmup-paths.json` or `package.json:e2e.warmupPaths`. */
21
+ export function resolveWarmupPaths(cwd) {
22
+ const jsonPath = path.join(cwd, 'e2e', 'warmup-paths.json');
23
+ if (fs.existsSync(jsonPath)) {
24
+ try {
25
+ const data = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
26
+ const paths = Array.isArray(data) ? data : data?.paths;
27
+ if (Array.isArray(paths))
28
+ return paths.filter((p) => typeof p === 'string');
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ const pkgPath = path.join(cwd, 'package.json');
35
+ if (fs.existsSync(pkgPath)) {
36
+ try {
37
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
38
+ const paths = pkg?.e2e?.warmupPaths;
39
+ if (Array.isArray(paths))
40
+ return paths.filter((p) => typeof p === 'string');
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
46
+ return null;
47
+ }
48
+ export async function runWarmup(args) {
49
+ const cwd = process.cwd();
50
+ const filter = args.find((a) => !a.startsWith('--'));
51
+ const sequential = args.includes('--sequential');
52
+ const paths = resolveWarmupPaths(cwd);
53
+ if (!paths || paths.length === 0) {
54
+ problem(t('warmup.no_paths'));
55
+ process.exit(1);
56
+ }
57
+ const baseUrl = process.env.SITE_URL || 'http://localhost:4000';
58
+ info(`SITE_URL=${baseUrl}${sequential ? ' (secuencial)' : ''}`);
59
+ const outcome = await warmup(baseUrl, {
60
+ paths,
61
+ filter,
62
+ mode: sequential ? 'sequential' : 'two-pass',
63
+ });
64
+ success(`Warmup: ${outcome.results.length} ruta(s), ${outcome.slow.length} lenta(s), ${outcome.errors} error(es).`);
65
+ process.exit(0);
66
+ }
67
+ //# sourceMappingURL=warmup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warmup.js","sourceRoot":"","sources":["../../src/tasks/warmup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=warmup.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warmup.test.d.ts","sourceRoot":"","sources":["../../src/tasks/warmup.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,40 @@
1
+ import { afterEach, describe, expect, it } from 'vitest';
2
+ import * as fs from 'fs';
3
+ import * as os from 'os';
4
+ import * as path from 'path';
5
+ import { resolveWarmupPaths } from './warmup.js';
6
+ // P5 (m/REQ/49): the route list lives in the consumer.
7
+ let dirs = [];
8
+ function tmpProject() {
9
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'm-warmup-'));
10
+ dirs.push(dir);
11
+ return dir;
12
+ }
13
+ afterEach(() => {
14
+ for (const dir of dirs)
15
+ fs.rmSync(dir, { recursive: true, force: true });
16
+ dirs = [];
17
+ });
18
+ describe('resolveWarmupPaths (P5)', () => {
19
+ it('reads e2e/warmup-paths.json (array form)', () => {
20
+ const dir = tmpProject();
21
+ fs.mkdirSync(path.join(dir, 'e2e'), { recursive: true });
22
+ fs.writeFileSync(path.join(dir, 'e2e', 'warmup-paths.json'), JSON.stringify(['/en', '/api/a']));
23
+ expect(resolveWarmupPaths(dir)).toEqual(['/en', '/api/a']);
24
+ });
25
+ it('reads e2e/warmup-paths.json (object form) and drops non-strings', () => {
26
+ const dir = tmpProject();
27
+ fs.mkdirSync(path.join(dir, 'e2e'), { recursive: true });
28
+ fs.writeFileSync(path.join(dir, 'e2e', 'warmup-paths.json'), JSON.stringify({ paths: ['/en', 1, '/api/a'] }));
29
+ expect(resolveWarmupPaths(dir)).toEqual(['/en', '/api/a']);
30
+ });
31
+ it('falls back to package.json:e2e.warmupPaths', () => {
32
+ const dir = tmpProject();
33
+ fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({ e2e: { warmupPaths: ['/x'] } }));
34
+ expect(resolveWarmupPaths(dir)).toEqual(['/x']);
35
+ });
36
+ it('returns null when nothing is configured', () => {
37
+ expect(resolveWarmupPaths(tmpProject())).toBeNull();
38
+ });
39
+ });
40
+ //# sourceMappingURL=warmup.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warmup.test.js","sourceRoot":"","sources":["../../src/tasks/warmup.test.ts"],"names":[],"mappings":"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"}
@@ -16,7 +16,7 @@
16
16
  "author": "",
17
17
  "license": "ISC",
18
18
  "dependencies": {
19
- "@pasosdejesus/m": "gitlab:pasosdejesus/m",
19
+ "@pasosdejesus/m": "^{{m_version}}",
20
20
  "dotenv": "^17.4.2",
21
21
  "kysely-postgres-js": "3.0.0",
22
22
  "next": "^16.0.0",
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Console noise silencing for tests
3
+ *
4
+ * "Y todo lo que hagáis, hacedlo de corazón, como para el Señor y no para los hombres" (Colosenses 3:23)
5
+ *
6
+ * P5/U2 of `m/REQ/49`: many consumers wrap `console` to hide expected noise
7
+ * (retry attempts, aborted navigations, warnings from a mocked dependency).
8
+ * This graduates the pattern from learn.tg's `vitest.setup.ts` (`NOISY_PATTERNS`)
9
+ * so consumers can drop their local wrapper.
10
+ */
11
+ /** Console methods wrapped by `silenceConsole`. */
12
+ export type SilencedConsoleMethod = 'log' | 'warn' | 'error' | 'info' | 'debug';
13
+ export interface SilenceConsoleOpts {
14
+ /** Methods to wrap (default `log`, `warn`, `error`). */
15
+ methods?: SilencedConsoleMethod[];
16
+ /** Console object to wrap (default `globalThis.console`; injectable for tests). */
17
+ console?: Console;
18
+ }
19
+ export interface SilenceConsoleHandle {
20
+ /** Restores the original methods. */
21
+ restore: () => void;
22
+ /** The argument lists that were suppressed (useful for assertions). */
23
+ suppressed: unknown[][];
24
+ }
25
+ /**
26
+ * Wraps the console methods so a call whose args contain any of `patterns`
27
+ * (substring match on string args) is suppressed; the rest passes through to the
28
+ * original method.
29
+ *
30
+ * ```typescript
31
+ * const silence = silenceConsole(['[retry]', 'AbortError'])
32
+ * // ... exercise the code ...
33
+ * silence.restore()
34
+ * ```
35
+ */
36
+ export declare function silenceConsole(patterns: string[], opts?: SilenceConsoleOpts): SilenceConsoleHandle;
37
+ //# sourceMappingURL=console.d.ts.map