@appthrust/kest 0.3.1 → 0.3.2
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
|
@@ -254,8 +254,8 @@ await ns.label({
|
|
|
254
254
|
kind: "ConfigMap",
|
|
255
255
|
name: "my-config",
|
|
256
256
|
labels: {
|
|
257
|
-
env: "production",
|
|
258
|
-
deprecated: null,
|
|
257
|
+
env: "production", // add a label
|
|
258
|
+
deprecated: null, // remove a label
|
|
259
259
|
},
|
|
260
260
|
});
|
|
261
261
|
```
|
|
@@ -310,33 +310,51 @@ test("ConfigMap lifecycle", async (s) => {
|
|
|
310
310
|
|
|
311
311
|
### Markdown Test Reports
|
|
312
312
|
|
|
313
|
-
When a test fails (or when `KEST_SHOW_REPORT=1` is set), Kest generates a detailed Markdown report showing every action, the exact `kubectl` commands executed, stdout/stderr output, and cleanup results. This provides full transparency into what happened during the test, making troubleshooting straightforward -- for both humans and AI assistants.
|
|
313
|
+
When a test fails (or when `KEST_SHOW_REPORT=1` is set), Kest generates a detailed Markdown report showing every action, the exact `kubectl` commands executed (including stdin manifests), stdout/stderr output, and cleanup results. This provides full transparency into what happened during the test, making troubleshooting straightforward -- for both humans and AI assistants.
|
|
314
314
|
|
|
315
|
-
|
|
315
|
+
````markdown
|
|
316
316
|
# ConfigMap lifecycle
|
|
317
317
|
|
|
318
318
|
## Scenario Overview
|
|
319
319
|
|
|
320
|
-
| # | Action
|
|
321
|
-
| --- |
|
|
322
|
-
| 1 |
|
|
323
|
-
| 2 | Apply
|
|
324
|
-
| 3 | Assert
|
|
320
|
+
| # | Action | Status |
|
|
321
|
+
| --- | ------------------------------ | ------ |
|
|
322
|
+
| 1 | Apply Namespace `kest-9hdhj` | ✅ |
|
|
323
|
+
| 2 | Apply `ConfigMap` "my-config" | ✅ |
|
|
324
|
+
| 3 | Assert `ConfigMap` "my-config" | ✅ |
|
|
325
325
|
|
|
326
326
|
## Scenario Details
|
|
327
327
|
|
|
328
328
|
### Given: a namespace exists
|
|
329
329
|
|
|
330
|
-
|
|
330
|
+
**✅ Apply Namespace `kest-9hdhj`**
|
|
331
|
+
|
|
332
|
+
```shell
|
|
333
|
+
kubectl apply -f - <<EOF
|
|
334
|
+
apiVersion: v1
|
|
335
|
+
kind: Namespace
|
|
336
|
+
metadata:
|
|
337
|
+
name: kest-9hdhj
|
|
338
|
+
EOF
|
|
339
|
+
```
|
|
340
|
+
|
|
331
341
|
...
|
|
332
342
|
|
|
333
343
|
### Cleanup
|
|
334
344
|
|
|
335
|
-
| # | Action
|
|
336
|
-
| --- |
|
|
337
|
-
| 1 | Delete
|
|
338
|
-
| 2 | Delete
|
|
345
|
+
| # | Action | Status |
|
|
346
|
+
| --- | ------------------------------ | ------ |
|
|
347
|
+
| 1 | Delete `ConfigMap` "my-config" | ✅ |
|
|
348
|
+
| 2 | Delete Namespace `kest-9hdhj` | ✅ |
|
|
349
|
+
|
|
350
|
+
```shellsession
|
|
351
|
+
$ kubectl delete ConfigMap/my-config -n kest-9hdhj
|
|
352
|
+
configmap "my-config" deleted
|
|
353
|
+
|
|
354
|
+
$ kubectl delete namespace/kest-9hdhj
|
|
355
|
+
namespace "kest-9hdhj" deleted
|
|
339
356
|
```
|
|
357
|
+
````
|
|
340
358
|
|
|
341
359
|
## Getting Started
|
|
342
360
|
|
|
@@ -410,21 +428,21 @@ Entry point for defining a test scenario. The callback receives a `Scenario` obj
|
|
|
410
428
|
|
|
411
429
|
The top-level API surface available in every test callback.
|
|
412
430
|
|
|
413
|
-
| Method | Description
|
|
414
|
-
| ----------------------------------------------------------------------- |
|
|
415
|
-
| `apply(manifest, options?)` | Apply a Kubernetes manifest and register cleanup
|
|
416
|
-
| `create(manifest, options?)` | Create a Kubernetes resource and register cleanup
|
|
417
|
-
| `applyStatus(manifest, options?)` | Apply a status subresource (server-side apply)
|
|
418
|
-
| `delete(resource, options?)` | Delete a resource by API version, kind, and name
|
|
419
|
-
| `label(input, options?)` | Add, update, or remove labels on a resource
|
|
420
|
-
| `get(resource, options?)` | Fetch a resource by API version, kind, and name
|
|
421
|
-
| `assert(resource, options?)` | Fetch a resource and run assertions with retries
|
|
422
|
-
| `assertAbsence(resource, options?)` | Assert that a resource does not exist
|
|
423
|
-
| `assertList(resource, options?)` | Fetch a list of resources and run assertions
|
|
431
|
+
| Method | Description |
|
|
432
|
+
| ----------------------------------------------------------------------- | ----------------------------------------------------------- |
|
|
433
|
+
| `apply(manifest, options?)` | Apply a Kubernetes manifest and register cleanup |
|
|
434
|
+
| `create(manifest, options?)` | Create a Kubernetes resource and register cleanup |
|
|
435
|
+
| `applyStatus(manifest, options?)` | Apply a status subresource (server-side apply) |
|
|
436
|
+
| `delete(resource, options?)` | Delete a resource by API version, kind, and name |
|
|
437
|
+
| `label(input, options?)` | Add, update, or remove labels on a resource |
|
|
438
|
+
| `get(resource, options?)` | Fetch a resource by API version, kind, and name |
|
|
439
|
+
| `assert(resource, options?)` | Fetch a resource and run assertions with retries |
|
|
440
|
+
| `assertAbsence(resource, options?)` | Assert that a resource does not exist |
|
|
441
|
+
| `assertList(resource, options?)` | Fetch a list of resources and run assertions |
|
|
424
442
|
| `newNamespace(name?, options?)` | Create an ephemeral namespace (supports `{ generateName }`) |
|
|
425
|
-
| `exec(input, options?)` | Execute shell commands with optional revert
|
|
426
|
-
| `useCluster(ref)` | Create a cluster-bound API surface
|
|
427
|
-
| `given(desc)` / `when(desc)` / `then(desc)` / `and(desc)` / `but(desc)` | BDD annotations for reporting
|
|
443
|
+
| `exec(input, options?)` | Execute shell commands with optional revert |
|
|
444
|
+
| `useCluster(ref)` | Create a cluster-bound API surface |
|
|
445
|
+
| `given(desc)` / `when(desc)` / `then(desc)` / `and(desc)` / `but(desc)` | BDD annotations for reporting |
|
|
428
446
|
|
|
429
447
|
### Namespace / Cluster
|
|
430
448
|
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { create } from "./create";
|
|
2
2
|
import type { MutateDef } from "./types";
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -9,19 +9,19 @@ import type { MutateDef } from "./types";
|
|
|
9
9
|
* - `{ generateName: string }` -- use the string as a prefix followed by
|
|
10
10
|
* random characters (e.g. `{ generateName: "foo-" }` → `"foo-d7kpn"`).
|
|
11
11
|
*/
|
|
12
|
-
export type
|
|
12
|
+
export type CreateNamespaceInput =
|
|
13
13
|
| undefined
|
|
14
14
|
| string
|
|
15
15
|
| { readonly generateName: string };
|
|
16
16
|
|
|
17
|
-
export const
|
|
17
|
+
export const createNamespace = {
|
|
18
18
|
type: "mutate",
|
|
19
|
-
name: "
|
|
19
|
+
name: "CreateNamespace",
|
|
20
20
|
mutate:
|
|
21
21
|
({ kubectl }) =>
|
|
22
22
|
async (input) => {
|
|
23
23
|
const name = resolveNamespaceName(input);
|
|
24
|
-
const { revert } = await
|
|
24
|
+
const { revert } = await create.mutate({ kubectl })({
|
|
25
25
|
apiVersion: "v1",
|
|
26
26
|
kind: "Namespace",
|
|
27
27
|
metadata: {
|
|
@@ -32,16 +32,16 @@ export const applyNamespace = {
|
|
|
32
32
|
},
|
|
33
33
|
describe: (input) => {
|
|
34
34
|
if (input === undefined) {
|
|
35
|
-
return "
|
|
35
|
+
return "Create `Namespace` with auto-generated name";
|
|
36
36
|
}
|
|
37
37
|
if (typeof input === "string") {
|
|
38
|
-
return `
|
|
38
|
+
return `Create \`Namespace\` "${input}"`;
|
|
39
39
|
}
|
|
40
|
-
return `
|
|
40
|
+
return `Create \`Namespace\` with prefix "${input.generateName}"`;
|
|
41
41
|
},
|
|
42
|
-
} satisfies MutateDef<
|
|
42
|
+
} satisfies MutateDef<CreateNamespaceInput, string>;
|
|
43
43
|
|
|
44
|
-
function resolveNamespaceName(input:
|
|
44
|
+
function resolveNamespaceName(input: CreateNamespaceInput): string {
|
|
45
45
|
if (input === undefined) {
|
|
46
46
|
return `kest-${randomConsonantDigits(5)}`;
|
|
47
47
|
}
|
package/ts/scenario/index.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { apply } from "../actions/apply";
|
|
2
|
-
import {
|
|
3
|
-
type ApplyNamespaceInput,
|
|
4
|
-
applyNamespace,
|
|
5
|
-
} from "../actions/apply-namespace";
|
|
6
2
|
import { applyStatus } from "../actions/apply-status";
|
|
7
3
|
import { assert } from "../actions/assert";
|
|
8
4
|
import { assertAbsence } from "../actions/assert-absence";
|
|
9
5
|
import { assertList } from "../actions/assert-list";
|
|
10
6
|
import { create } from "../actions/create";
|
|
7
|
+
import {
|
|
8
|
+
type CreateNamespaceInput,
|
|
9
|
+
createNamespace,
|
|
10
|
+
} from "../actions/create-namespace";
|
|
11
11
|
import { deleteResource } from "../actions/delete";
|
|
12
12
|
import { exec } from "../actions/exec";
|
|
13
13
|
import { get } from "../actions/get";
|
|
@@ -187,10 +187,10 @@ const createQueryFn =
|
|
|
187
187
|
const createNewNamespaceFn =
|
|
188
188
|
(scenarioDeps: CreateScenarioOptions) =>
|
|
189
189
|
async (
|
|
190
|
-
name?:
|
|
190
|
+
name?: CreateNamespaceInput,
|
|
191
191
|
options?: undefined | ActionOptions
|
|
192
192
|
): Promise<Namespace> => {
|
|
193
|
-
const namespaceName = await createMutateFn(scenarioDeps,
|
|
193
|
+
const namespaceName = await createMutateFn(scenarioDeps, createNamespace)(
|
|
194
194
|
name,
|
|
195
195
|
options
|
|
196
196
|
);
|