@akshatmittal/invoker 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -196,16 +196,14 @@ retries.
196
196
  ## Notify Slack
197
197
 
198
198
  Invoker's optional Slack reporter posts one `Invoker Report` parent message per
199
- Vitest run. It places additional Workflow cards in the message thread so every
200
- Task table remains within Slack's row and character limits. Each card includes
201
- aggregate results, Workflow metadata, and a table of Task counts and durations.
202
- A shared footer contains the elapsed span from the first Case start to the final
203
- Case completion, a localized timestamp, and the optional run link. Final
204
- failures are posted in the same thread with one reply per failed Task in each
205
- Workflow. Unhandled run errors are reported once. Delivery failures are
206
- isolated to the affected reply. Ambiguous transport failures are not retried;
207
- an explicit Slack rate-limit rejection is reattempted only after its required
208
- delay.
199
+ Vitest run containing every Workflow card. Each card includes aggregate results,
200
+ Workflow metadata, and a table of Task counts and durations. A shared footer
201
+ contains the elapsed span from the first Case start to the final Case completion,
202
+ a localized timestamp, and the optional run link. Final failures, successful
203
+ retry details, skipped Case reasons, and unhandled run errors are posted in the
204
+ same thread. Delivery failures are isolated to the affected reply. Ambiguous
205
+ transport failures are not retried; an explicit Slack rate-limit rejection is
206
+ reattempted only after its required delay.
209
207
 
210
208
  ```ts
211
209
  import { slackReporter } from "@akshatmittal/invoker/slack";
package/dist/slack.mjs CHANGED
@@ -49,7 +49,8 @@ function collectWorkflowReports(modules) {
49
49
  skipped: 0,
50
50
  incomplete: 0,
51
51
  failures: [],
52
- retries: []
52
+ retries: [],
53
+ skips: []
53
54
  };
54
55
  workflow.tasks.set(taskSuite, task);
55
56
  }
@@ -78,28 +79,37 @@ function collectWorkflowReports(modules) {
78
79
  matrix: invoker.matrix,
79
80
  messages: result.errors.map(errorMessage)
80
81
  });
82
+ else if (result.state === "skipped") task.skips.push({
83
+ task: task.name,
84
+ caseName: testCase.name,
85
+ matrix: invoker.matrix,
86
+ reason: result.note || "No reason provided"
87
+ });
81
88
  }
82
89
  return [...workflows.values()].map((workflow) => {
83
90
  const failures = [];
84
91
  const retries = [];
92
+ const skips = [];
85
93
  addErrors(failures, workflow.suite.errors());
86
94
  addErrors(failures, workflow.module.errors());
87
95
  const collectedTasks = [...workflow.tasks.values()];
88
96
  for (const task of collectedTasks) {
89
97
  failures.push(...task.failures);
90
98
  retries.push(...task.retries);
99
+ skips.push(...task.skips);
91
100
  addErrors(failures, task.suite.errors(), task.name);
92
101
  }
93
102
  const { startedAt, endedAt } = timeSpan(collectedTasks);
94
103
  return {
95
104
  name: workflow.name,
96
105
  metadata: workflow.metadata,
97
- tasks: collectedTasks.map(({ suite: _suite, failures: _failures, retries: _retries, startedAt, endedAt, ...task }) => ({
106
+ tasks: collectedTasks.map(({ suite: _suite, failures: _failures, retries: _retries, skips: _skips, startedAt, endedAt, ...task }) => ({
98
107
  ...task,
99
108
  duration: startedAt === void 0 || endedAt === void 0 ? 0 : endedAt - startedAt
100
109
  })),
101
110
  failures: deduplicateFailures(failures),
102
111
  retries,
112
+ skips,
103
113
  startedAt,
104
114
  endedAt
105
115
  };
@@ -252,6 +262,49 @@ function retryMessages(report) {
252
262
  });
253
263
  });
254
264
  }
265
+ function skipMessages(report) {
266
+ return [...Map.groupBy(report.skips, (skip) => skip.task)].flatMap(([task, skips]) => {
267
+ const title = escapeSlack(truncate(task, NAME_CHARACTER_LIMIT));
268
+ const workflow = `*Workflow:* ${escapeSlack(truncate(report.name, NAME_CHARACTER_LIMIT))}`;
269
+ const metadata = metadataText(report.metadata);
270
+ const context = metadata ? `${workflow} • ${metadata}` : workflow;
271
+ return chunk(skips.map((skip) => {
272
+ const matrix = `\nMatrix: ${escapeSlack(JSON.stringify(skip.matrix))}`;
273
+ return `*${escapeSlack(skip.caseName)}*${matrix}\nReason: ${escapeSlack(skip.reason)}`;
274
+ }), SECTION_CHARACTER_LIMIT).map((details, index, messages) => {
275
+ const part = messages.length > 1 ? ` (${index + 1}/${messages.length})` : "";
276
+ return {
277
+ text: `${truncate(report.name, NAME_CHARACTER_LIMIT)} › ${truncate(task, NAME_CHARACTER_LIMIT)} — ${skips.length} skipped${part}`,
278
+ attachments: [{
279
+ color: "warning",
280
+ blocks: [
281
+ {
282
+ type: "section",
283
+ text: {
284
+ type: "mrkdwn",
285
+ text: `🟡 *${title} — ${skips.length} skipped${part}*`
286
+ }
287
+ },
288
+ {
289
+ type: "context",
290
+ elements: [{
291
+ type: "mrkdwn",
292
+ text: context
293
+ }]
294
+ },
295
+ {
296
+ type: "section",
297
+ text: {
298
+ type: "mrkdwn",
299
+ text: details
300
+ }
301
+ }
302
+ ]
303
+ }]
304
+ };
305
+ });
306
+ });
307
+ }
255
308
  function unhandledErrorMessages(errors) {
256
309
  const messages = [...new Set(errors.map(errorMessage))];
257
310
  return chunk(messages.map((message) => `• ${escapeSlack(message)}`), SECTION_CHARACTER_LIMIT).map((details, index, chunks) => {
@@ -457,6 +510,7 @@ function slackReporter(options) {
457
510
  const replies = [
458
511
  ...reports.flatMap(failureMessages),
459
512
  ...reports.flatMap(retryMessages),
513
+ ...reports.flatMap(skipMessages),
460
514
  ...unhandledErrorMessages(unhandledErrors)
461
515
  ];
462
516
  if (replies.length > 0 && !parentTimestamp) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akshatmittal/invoker",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Typed matrix-driven regression workflows for Vitest.",
5
5
  "keywords": [
6
6
  "matrix",