@appthrust/kest 0.6.0 → 0.7.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.
@@ -60,6 +60,34 @@ test("Example: applies ConfigMap using YAML, file import, and object literal", a
60
60
  // 4. Namespace
61
61
  });
62
62
 
63
+ test("Example: diff demo - ConfigMap data mismatch (expected to fail)", async (s) => {
64
+ s.given("a new namespace exists");
65
+ const ns = await s.newNamespace();
66
+
67
+ s.when("I apply a ConfigMap with actual data");
68
+ await ns.apply<ConfigMap>({
69
+ apiVersion: "v1",
70
+ kind: "ConfigMap",
71
+ metadata: { name: "diff-demo" },
72
+ data: { mode: "actual-value", env: "production" },
73
+ });
74
+
75
+ s.then("asserting with different expected data should produce a diff");
76
+ await ns.assert<ConfigMap>({
77
+ apiVersion: "v1",
78
+ kind: "ConfigMap",
79
+ name: "diff-demo",
80
+ test() {
81
+ expect(this).toMatchObject({
82
+ data: {
83
+ mode: "expected-value",
84
+ env: "staging",
85
+ },
86
+ });
87
+ },
88
+ });
89
+ });
90
+
63
91
  test("Example: asserts a non-existent ConfigMap (expected to fail)", async (s) => {
64
92
  s.given("a new namespace exists");
65
93
  const ns = await s.newNamespace();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appthrust/kest",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Kubernetes E2E testing framework designed for humans and AI alike",
5
5
  "type": "module",
6
6
  "module": "ts/index.ts",
@@ -53,6 +53,7 @@ type CommandEvent =
53
53
 
54
54
  type RetryEvent =
55
55
  | BaseEvent<"RetryStart", Record<string, never>>
56
+ | BaseEvent<"RetryAttempt", { readonly attempt: number }>
56
57
  | BaseEvent<
57
58
  "RetryEnd",
58
59
  | {
@@ -7,6 +7,7 @@ import type {
7
7
  Report,
8
8
  Scenario,
9
9
  } from "../model";
10
+ import { stripAnsi } from "../strip-ansi";
10
11
 
11
12
  const bddKeywordByKind = {
12
13
  BDDGiven: "given",
@@ -89,6 +90,9 @@ function handleNonBDDEvent(state: ParseState, event: Event): void {
89
90
  case "RetryEnd":
90
91
  handleRetryEnd(state, event);
91
92
  return;
93
+ case "RetryAttempt":
94
+ handleRetryAttempt(state);
95
+ return;
92
96
  case "RetryStart":
93
97
  return;
94
98
  default:
@@ -158,7 +162,9 @@ function applyRegularActionEnd(
158
162
  currentAction.error = {
159
163
  message: {
160
164
  text: event.data.error.message,
161
- language: isDiffLike(event.data.error.message) ? "diff" : "text",
165
+ language: isDiffLike(stripAnsi(event.data.error.message))
166
+ ? "diff"
167
+ : "text",
162
168
  },
163
169
  };
164
170
  }
@@ -263,6 +269,16 @@ function handleCleanupActionEnd(
263
269
  return true;
264
270
  }
265
271
 
272
+ function handleRetryAttempt(state: ParseState): void {
273
+ if (state.inCleanup) {
274
+ return;
275
+ }
276
+ if (!state.currentAction) {
277
+ return;
278
+ }
279
+ state.currentAction.commands = [];
280
+ }
281
+
266
282
  function handleRetryEnd(
267
283
  state: ParseState,
268
284
  event: Extract<Event, { kind: "RetryEnd" }>
@@ -342,7 +358,7 @@ function bddFromEvent(event: Event): BDDSection | undefined {
342
358
  return { keyword, description: event.data.description, actions: [] };
343
359
  }
344
360
 
345
- function isDiffLike(message: string): boolean {
361
+ export function isDiffLike(message: string): boolean {
346
362
  const lines = message.split(/\r?\n/);
347
363
  let sawPlus = false;
348
364
  let sawMinus = false;
@@ -1,6 +1,7 @@
1
1
  import { codeToANSIForcedColors } from "../../shiki";
2
2
  import type { MarkdownReporterOptions } from "../index";
3
3
  import type { Action, Report } from "../model";
4
+ import { stripAnsi } from "../strip-ansi";
4
5
 
5
6
  const markdownLang = "markdown";
6
7
  const markdownTheme = "catppuccin-mocha";
@@ -83,15 +84,6 @@ async function highlightMarkdown(
83
84
  }
84
85
  }
85
86
 
86
- function stripAnsi(input: string): string {
87
- // Prefer Bun's built-in ANSI stripper when available.
88
- if (typeof Bun !== "undefined" && typeof Bun.stripANSI === "function") {
89
- return Bun.stripANSI(input);
90
- }
91
- // biome-ignore lint/suspicious/noControlCharactersInRegex: intended
92
- return input.replace(/\u001b\[[0-9;]*m/g, "");
93
- }
94
-
95
87
  function trimFinalNewline(input: string): string {
96
88
  return input.replace(/\n$/, "");
97
89
  }
@@ -0,0 +1,8 @@
1
+ export function stripAnsi(input: string): string {
2
+ // Prefer Bun's built-in ANSI stripper when available.
3
+ if (typeof Bun !== "undefined" && typeof Bun.stripANSI === "function") {
4
+ return Bun.stripANSI(input);
5
+ }
6
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: intended
7
+ return input.replace(/\u001b\[[0-9;]*m/g, "");
8
+ }
package/ts/retry.ts CHANGED
@@ -77,6 +77,7 @@ export async function retryUntil<T>(
77
77
  }
78
78
 
79
79
  retries += 1;
80
+ recorder?.record("RetryAttempt", { attempt: retries });
80
81
 
81
82
  try {
82
83
  const value = await fn();