@cdktn/vitest 0.0.0 → 0.1.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.
- package/LICENSE +21 -0
- package/NOTICE +21 -0
- package/README.md +118 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/matcher/index.d.ts +2 -0
- package/lib/matcher/index.js +2 -0
- package/lib/matcher/matcher.d.ts +15 -0
- package/lib/matcher/matcher.js +50 -0
- package/lib/matcher/matcher.types.d.ts +29 -0
- package/lib/matcher/matcher.types.js +1 -0
- package/lib/matcher/matcher.utils.d.ts +18 -0
- package/lib/matcher/matcher.utils.js +32 -0
- package/package.json +53 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 cdktn-io
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
@cdktn/vitest
|
|
2
|
+
Copyright (c) 2026 cdktn-io
|
|
3
|
+
|
|
4
|
+
This product includes software designed by, and adapts the public API of, the
|
|
5
|
+
following MIT-licensed projects:
|
|
6
|
+
|
|
7
|
+
- cdktn-vitest (https://www.npmjs.com/package/cdktn-vitest)
|
|
8
|
+
Copyright (c) Aníbal Jorquera <ajorquera.cornejo@gmail.com>
|
|
9
|
+
The single-export `setupVitest()` API and the Vitest `passEvaluation`
|
|
10
|
+
predicate mirror this package's design. This is a clean reimplementation in
|
|
11
|
+
TypeScript; no compiled artifacts from the original are distributed here.
|
|
12
|
+
|
|
13
|
+
- cdktf-vitest (https://www.npmjs.com/package/cdktf-vitest)
|
|
14
|
+
Copyright (c) Daniel Grefberg <hello@danielgrefberg.com>
|
|
15
|
+
The original (now deprecated) Vitest matchers adapter for HashiCorp's CDKTF,
|
|
16
|
+
from which the cdktn variant was derived.
|
|
17
|
+
|
|
18
|
+
The matcher *logic* (resource/data-source/provider assertions, Terraform
|
|
19
|
+
validation) is provided by CDK Terrain (cdktn) core via its exported
|
|
20
|
+
`testingMatchers`. This package is a thin Vitest adapter over that logic,
|
|
21
|
+
mirroring cdktn core's built-in Jest adapter (`setupJest()`).
|
package/README.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# @cdktn/vitest
|
|
2
|
+
|
|
3
|
+
Vitest matchers for [CDK Terrain (cdktn)](https://cdktn.io).
|
|
4
|
+
|
|
5
|
+
`cdktn` ships [Jest matchers](https://cdktn.io/docs/test/unit-tests#write-assertions)
|
|
6
|
+
out of the box but no Vitest adapter. This package fills that gap: it registers
|
|
7
|
+
the same assertion logic cdktn core exposes (`testingMatchers`) onto Vitest's
|
|
8
|
+
`expect`, mirroring cdktn's built-in Jest adapter (`setupJest()`).
|
|
9
|
+
|
|
10
|
+
It is the org-owned, provenance-signed successor to the third-party
|
|
11
|
+
`cdktn-vitest` package — same public API (`setupVitest()`), published under the
|
|
12
|
+
`@cdktn` scope.
|
|
13
|
+
|
|
14
|
+
> **Long-term direction:** the goal is to fold a Vitest adapter directly into
|
|
15
|
+
> cdktn core as `cdktn/lib/testing/adapters/vitest` (mirroring the Jest adapter)
|
|
16
|
+
> and deprecate this standalone package. Tracking issue:
|
|
17
|
+
> [open-constructs/cdk-terrain#289](https://github.com/open-constructs/cdk-terrain/issues/289).
|
|
18
|
+
> Until core ships that, `@cdktn/vitest` is the supported path.
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pnpm add -D @cdktn/vitest
|
|
24
|
+
# or: npm install -D @cdktn/vitest
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`cdktn` and `vitest` are peer dependencies:
|
|
28
|
+
|
|
29
|
+
- `cdktn >= 0.23.0`
|
|
30
|
+
- `vitest >= 2.1.0`
|
|
31
|
+
|
|
32
|
+
## Setup
|
|
33
|
+
|
|
34
|
+
### 1. Register the matchers
|
|
35
|
+
|
|
36
|
+
Create a Vitest setup file that calls `setupVitest()`:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// vitest.setup.ts
|
|
40
|
+
import { setupVitest } from "@cdktn/vitest";
|
|
41
|
+
|
|
42
|
+
setupVitest();
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Wire it into your Vitest config
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
// vitest.config.ts
|
|
49
|
+
import { defineConfig } from "vitest/config";
|
|
50
|
+
|
|
51
|
+
export default defineConfig({
|
|
52
|
+
test: {
|
|
53
|
+
setupFiles: ["./vitest.setup.ts"],
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 3. Enable the matcher types
|
|
59
|
+
|
|
60
|
+
Add the package to your `tsconfig.json` so the matchers are typed on `expect`:
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"compilerOptions": {
|
|
65
|
+
"types": ["@cdktn/vitest"]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Available matchers
|
|
71
|
+
|
|
72
|
+
| Matcher | Asserts that the synthesized stack… |
|
|
73
|
+
| --- | --- |
|
|
74
|
+
| `toHaveResource(resource)` | contains a resource of the given type |
|
|
75
|
+
| `toHaveResourceWithProperties(resource, props)` | contains a matching resource with the given properties |
|
|
76
|
+
| `toHaveDataSource(dataSource)` | contains a data source of the given type |
|
|
77
|
+
| `toHaveDataSourceWithProperties(dataSource, props)` | contains a matching data source with the given properties |
|
|
78
|
+
| `toHaveProvider(provider)` | configures the given provider |
|
|
79
|
+
| `toHaveProviderWithProperties(provider, props)` | configures the given provider with the given properties |
|
|
80
|
+
| `toBeValidTerraform()` | passes `terraform validate` (requires the `terraform` CLI) |
|
|
81
|
+
| `toPlanSuccessfully()` | passes `terraform plan` (requires the `terraform` CLI) |
|
|
82
|
+
|
|
83
|
+
Property matchers use subset (`objectContaining`) semantics — the resource may
|
|
84
|
+
have additional properties beyond those asserted.
|
|
85
|
+
|
|
86
|
+
## Example
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { describe, expect, it } from "vitest";
|
|
90
|
+
import { Testing } from "cdktn";
|
|
91
|
+
import { MyStack } from "./my-stack";
|
|
92
|
+
|
|
93
|
+
describe("MyStack", () => {
|
|
94
|
+
it("creates the bucket with the right name", () => {
|
|
95
|
+
const synthesized = Testing.synth(new MyStack(Testing.app(), "test"));
|
|
96
|
+
|
|
97
|
+
expect(synthesized).toHaveResourceWithProperties(S3Bucket, {
|
|
98
|
+
bucket: "my-bucket",
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
> `toBeValidTerraform()` / `toPlanSuccessfully()` operate on a synthesized
|
|
105
|
+
> output **directory** (containing `manifest.json`) and shell out to the
|
|
106
|
+
> `terraform` CLI, so they require Terraform to be installed.
|
|
107
|
+
|
|
108
|
+
## Credits
|
|
109
|
+
|
|
110
|
+
This is a clean-room TypeScript reimplementation that mirrors the public API of
|
|
111
|
+
the MIT-licensed [`cdktn-vitest`](https://www.npmjs.com/package/cdktn-vitest) by
|
|
112
|
+
Aníbal Jorquera, itself derived from
|
|
113
|
+
[`cdktf-vitest`](https://www.npmjs.com/package/cdktf-vitest) by Daniel Grefberg.
|
|
114
|
+
See [`NOTICE`](./NOTICE).
|
|
115
|
+
|
|
116
|
+
## License
|
|
117
|
+
|
|
118
|
+
[MIT](./LICENSE)
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./matcher/index.js";
|
package/lib/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./matcher/index.js";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register the cdktn Vitest matchers on the global `expect`.
|
|
3
|
+
*
|
|
4
|
+
* Call this once from a Vitest setup file:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* // vitest.setup.ts
|
|
8
|
+
* import { setupVitest } from "@cdktn/vitest";
|
|
9
|
+
* setupVitest();
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* The matchers delegate to cdktn core's `testingMatchers`, the same logic the
|
|
13
|
+
* built-in Jest adapter uses, wired to a Vitest `passEvaluation`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const setupVitest: () => void;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { testingMatchers } from "cdktn";
|
|
2
|
+
import { expect } from "vitest";
|
|
3
|
+
import { parseResult, passEvaluation } from "./matcher.utils.js";
|
|
4
|
+
/**
|
|
5
|
+
* Register the cdktn Vitest matchers on the global `expect`.
|
|
6
|
+
*
|
|
7
|
+
* Call this once from a Vitest setup file:
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* // vitest.setup.ts
|
|
11
|
+
* import { setupVitest } from "@cdktn/vitest";
|
|
12
|
+
* setupVitest();
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* The matchers delegate to cdktn core's `testingMatchers`, the same logic the
|
|
16
|
+
* built-in Jest adapter uses, wired to a Vitest `passEvaluation`.
|
|
17
|
+
*/
|
|
18
|
+
export const setupVitest = () => {
|
|
19
|
+
// Build the property-aware matchers once with our Vitest predicate, then
|
|
20
|
+
// reuse them across every matcher invocation.
|
|
21
|
+
const toHaveResourceWithProperties = testingMatchers.getToHaveResourceWithProperties(passEvaluation);
|
|
22
|
+
const toHaveDataSourceWithProperties = testingMatchers.getToHaveDataSourceWithProperties(passEvaluation);
|
|
23
|
+
const toHaveProviderWithProperties = testingMatchers.getToHaveProviderWithProperties(passEvaluation);
|
|
24
|
+
expect.extend({
|
|
25
|
+
toHaveResource(received, resource) {
|
|
26
|
+
return parseResult(toHaveResourceWithProperties(received, resource, {}));
|
|
27
|
+
},
|
|
28
|
+
toHaveResourceWithProperties(received, resource, properties) {
|
|
29
|
+
return parseResult(toHaveResourceWithProperties(received, resource, properties));
|
|
30
|
+
},
|
|
31
|
+
toHaveDataSource(received, dataSourceConstructor) {
|
|
32
|
+
return parseResult(toHaveDataSourceWithProperties(received, dataSourceConstructor, {}));
|
|
33
|
+
},
|
|
34
|
+
toHaveDataSourceWithProperties(received, dataSourceConstructor, properties) {
|
|
35
|
+
return parseResult(toHaveDataSourceWithProperties(received, dataSourceConstructor, properties));
|
|
36
|
+
},
|
|
37
|
+
toHaveProvider(received, providerConstructor) {
|
|
38
|
+
return parseResult(toHaveProviderWithProperties(received, providerConstructor, {}));
|
|
39
|
+
},
|
|
40
|
+
toHaveProviderWithProperties(received, providerConstructor, properties) {
|
|
41
|
+
return parseResult(toHaveProviderWithProperties(received, providerConstructor, properties));
|
|
42
|
+
},
|
|
43
|
+
toBeValidTerraform(received) {
|
|
44
|
+
return parseResult(testingMatchers.toBeValidTerraform(received));
|
|
45
|
+
},
|
|
46
|
+
toPlanSuccessfully(received) {
|
|
47
|
+
return parseResult(testingMatchers.toPlanSuccessfully(received));
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import "vitest";
|
|
2
|
+
import type { testingMatchers } from "cdktn";
|
|
3
|
+
type TerraformConstructor = testingMatchers.TerraformConstructor;
|
|
4
|
+
/**
|
|
5
|
+
* Ambient typing for the cdktn matchers registered by {@link setupVitest}.
|
|
6
|
+
*
|
|
7
|
+
* Consumers opt in by adding this package to their tsconfig:
|
|
8
|
+
*
|
|
9
|
+
* ```json
|
|
10
|
+
* { "compilerOptions": { "types": ["@cdktn/vitest"] } }
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export interface CdktnVitestMatchers<R = unknown> {
|
|
14
|
+
toHaveResource(resource: TerraformConstructor): R;
|
|
15
|
+
toHaveResourceWithProperties(resource: TerraformConstructor, properties: Record<string, any>): R;
|
|
16
|
+
toHaveDataSource(dataSourceConstructor: TerraformConstructor): R;
|
|
17
|
+
toHaveDataSourceWithProperties(dataSourceConstructor: TerraformConstructor, properties: Record<string, any>): R;
|
|
18
|
+
toHaveProvider(providerConstructor: TerraformConstructor): R;
|
|
19
|
+
toHaveProviderWithProperties(providerConstructor: TerraformConstructor, properties: Record<string, any>): R;
|
|
20
|
+
toBeValidTerraform(): R;
|
|
21
|
+
toPlanSuccessfully(): R;
|
|
22
|
+
}
|
|
23
|
+
declare module "vitest" {
|
|
24
|
+
interface Assertion<T = any> extends CdktnVitestMatchers<T> {
|
|
25
|
+
}
|
|
26
|
+
interface AsymmetricMatchersContaining extends CdktnVitestMatchers {
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "vitest";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { testingMatchers } from "cdktn";
|
|
2
|
+
/**
|
|
3
|
+
* Predicate handed to cdktn's core matchers to decide whether a collection of
|
|
4
|
+
* synthesized items contains one matching the asserted properties.
|
|
5
|
+
*
|
|
6
|
+
* This mirrors the role of the Jest adapter's predicate in cdktn core, but is
|
|
7
|
+
* built on Vitest's asymmetric matchers. An empty property set degrades to a
|
|
8
|
+
* pure existence check.
|
|
9
|
+
*/
|
|
10
|
+
export declare const passEvaluation: (items: any, assertedProperties: Record<string, any>) => boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Translate cdktn's `AssertionReturn` ({ message, pass }) into the shape Vitest
|
|
13
|
+
* expects a matcher to return (message as a thunk).
|
|
14
|
+
*/
|
|
15
|
+
export declare const parseResult: (result: testingMatchers.AssertionReturn) => {
|
|
16
|
+
message: () => string;
|
|
17
|
+
pass: boolean;
|
|
18
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { expect } from "vitest";
|
|
2
|
+
/**
|
|
3
|
+
* Predicate handed to cdktn's core matchers to decide whether a collection of
|
|
4
|
+
* synthesized items contains one matching the asserted properties.
|
|
5
|
+
*
|
|
6
|
+
* This mirrors the role of the Jest adapter's predicate in cdktn core, but is
|
|
7
|
+
* built on Vitest's asymmetric matchers. An empty property set degrades to a
|
|
8
|
+
* pure existence check.
|
|
9
|
+
*/
|
|
10
|
+
export const passEvaluation = (items, assertedProperties) => {
|
|
11
|
+
if (Object.entries(assertedProperties).length === 0) {
|
|
12
|
+
return items.length > 0;
|
|
13
|
+
}
|
|
14
|
+
// `expect().toEqual()` throws on mismatch; we translate that into a boolean.
|
|
15
|
+
// This is more robust across Vitest versions than poking at the asymmetric
|
|
16
|
+
// matcher's semi-internal `asymmetricMatch()` method.
|
|
17
|
+
try {
|
|
18
|
+
expect(items).toEqual(expect.arrayContaining([expect.objectContaining(assertedProperties)]));
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Translate cdktn's `AssertionReturn` ({ message, pass }) into the shape Vitest
|
|
27
|
+
* expects a matcher to return (message as a thunk).
|
|
28
|
+
*/
|
|
29
|
+
export const parseResult = (result) => ({
|
|
30
|
+
message: () => result.message,
|
|
31
|
+
pass: result.pass,
|
|
32
|
+
});
|
package/package.json
CHANGED
|
@@ -1,9 +1,59 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdktn/vitest",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Vitest matchers for CDK Terrain (cdktn)",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./lib/index.d.ts",
|
|
10
|
+
"default": "./lib/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"main": "./lib/index.js",
|
|
14
|
+
"types": "./lib/index.d.ts",
|
|
15
|
+
"files": [
|
|
16
|
+
"lib",
|
|
17
|
+
"NOTICE"
|
|
18
|
+
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"cdktn",
|
|
21
|
+
"cdk-terrain",
|
|
22
|
+
"vitest",
|
|
23
|
+
"terraform",
|
|
24
|
+
"opentofu",
|
|
25
|
+
"testing",
|
|
26
|
+
"matchers"
|
|
27
|
+
],
|
|
28
|
+
"homepage": "https://github.com/cdktn-io/cdktn-vitest#readme",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/cdktn-io/cdktn-vitest.git"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/cdktn-io/cdktn-vitest/issues"
|
|
35
|
+
},
|
|
36
|
+
"packageManager": "pnpm@11.9.0",
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc",
|
|
39
|
+
"test": "vitest run",
|
|
40
|
+
"lint": "biome check .",
|
|
41
|
+
"format": "biome format --write .",
|
|
42
|
+
"prepublishOnly": "pnpm build"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"cdktn": ">= 0.23.0",
|
|
46
|
+
"vitest": ">= 2.1.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@biomejs/biome": "2.4.2",
|
|
50
|
+
"cdktn": "^0.23.3",
|
|
51
|
+
"constructs": "^10.4.2",
|
|
52
|
+
"typescript": "^5.9.2",
|
|
53
|
+
"vitest": "^4.0.0"
|
|
54
|
+
},
|
|
6
55
|
"publishConfig": {
|
|
7
|
-
"access": "public"
|
|
56
|
+
"access": "public",
|
|
57
|
+
"provenance": true
|
|
8
58
|
}
|
|
9
59
|
}
|