diff --git a/.release-please-manifest.json b/.release-please-manifest.json index a8e9def46..ea3e5f89f 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -9,7 +9,10 @@ "packages/case-plugin-base": "0.29.1", "packages/case-plugin-dsl-types": "0.29.1", "packages/case-entities": "0.29.1", - "packages/contract-case-jest": "0.29.1", + "packages/contract-case-dsl-js-internals": "0.29.1", + "packages/contract-case-dsl-js": "0.29.1", + "packages/contract-case-dsl-js-jest": "0.29.1", + "packages/contract-case-dsl-js-vitest": "0.29.1", "packages/documentation": "0.29.1", ".": "0.29.1", "packages/contract-case-cli": "0.29.1", diff --git a/README.md b/README.md index 7898099c4..b34f0d666 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Feedback on the ContractCase API / DSL and (especially) naming conventions very welcome. However, the following caveats should be kept in mind: 1. ContractCase doesn't currently support merging of contracts. This means that each contract must be defined in one test file (per contract). -1. ContractCase currently is only compatible with Jest (js/ts) and JUnit (java). +1. ContractCase currently is only compatible with Jest and Vitest (js/ts) and JUnit (java). 1. ContractCase currently only has minimal broker support. It supports the Pact broker, although the Pact broker isn't able to render ContractCase contracts in the UI. diff --git a/package-lock.json b/package-lock.json index 2fbf3a802..effc874ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "packages/*" ], "dependencies": { - "@nx/nx-linux-arm64-gnu": "22.7.5" + "nx": "^22.5.2" }, "devDependencies": { "@contract-case/eslint-config-case-maintainer": "0.29.1", @@ -3222,8 +3222,20 @@ "resolved": "packages/contract-case-cli", "link": true }, + "node_modules/@contract-case/contract-case-dsl-js": { + "resolved": "packages/contract-case-dsl-js", + "link": true + }, + "node_modules/@contract-case/contract-case-dsl-js-internals": { + "resolved": "packages/contract-case-dsl-js-internals", + "link": true + }, + "node_modules/@contract-case/contract-case-dsl-js-vitest": { + "resolved": "packages/contract-case-dsl-js-vitest", + "link": true + }, "node_modules/@contract-case/contract-case-jest": { - "resolved": "packages/contract-case-jest", + "resolved": "packages/contract-case-dsl-js-jest", "link": true }, "node_modules/@contract-case/definition-generator": { @@ -5647,7 +5659,6 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", - "dev": true, "license": "MIT", "dependencies": { "@emnapi/wasi-threads": "1.1.0", @@ -5658,7 +5669,6 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", - "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.4.0" @@ -5668,7 +5678,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", - "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.4.0" @@ -5679,6 +5688,448 @@ "dev": true, "license": "MIT" }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", @@ -6762,7 +7213,6 @@ }, "node_modules/@jest/diff-sequences": { "version": "30.0.1", - "devOptional": true, "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -8194,7 +8644,6 @@ "version": "0.2.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz", "integrity": "sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==", - "dev": true, "license": "MIT", "dependencies": { "@emnapi/core": "^1.1.0", @@ -8917,7 +9366,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -9638,6 +10086,7 @@ "version": "0.11.0", "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=14" } @@ -9747,6 +10196,356 @@ "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==", "license": "BSD-3-Clause" }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "license": "MIT" @@ -11103,7 +11902,6 @@ "version": "0.9.0", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", - "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.4.0" @@ -11176,6 +11974,17 @@ "@types/node": "*" } }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, "node_modules/@types/commonmark": { "version": "0.27.10", "resolved": "https://registry.npmjs.org/@types/commonmark/-/commonmark-0.27.10.tgz", @@ -11400,6 +12209,13 @@ "@types/ms": "*" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/eslint": { "version": "9.6.1", "license": "MIT", @@ -11417,7 +12233,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.8", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "license": "MIT" }, "node_modules/@types/estree-jsx": { @@ -12419,6 +13237,121 @@ "d3-transition": "^3.0.1" } }, + "node_modules/@vitest/expect": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.6.tgz", + "integrity": "sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.6.tgz", + "integrity": "sha512-EZOrpDbkKotFAP7wPAQV1UIyoGOk4oX7ynWhBhLB7v+meMHbQhU16oPpIYGTTe4oFlhpryGpgpcZP/sin3hYuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.6", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.6.tgz", + "integrity": "sha512-lb7XXXzmm2h2ASzFnRvQpDo6onT1NmMJA3tkGTWiBFtRJ9lxGY3d3mm/Apt36gej2bkkOVLL/yTOtufDaFa/jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.6.tgz", + "integrity": "sha512-HYcoSj1w5tcgUnzoF0HcyaAQjpA1gj9ftUJ7iSJSuipc02jW9gKkigwZbjFldAfYHA1fa8UZVRftdMY5msWM9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.6", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.6.tgz", + "integrity": "sha512-H+ZjNTWGpObenh0YnlBctAPnJSI20P81PL8BPzWpx54YXLLTm8hEsWawtcYLMrwvpK48hGxLLbCS+1KRXhsKhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.6", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.6.tgz", + "integrity": "sha512-oq6BbH68WzcWmwtBrU9nqLeaXTR4XwJF7FSLkKEZo4i6eoXcrxjcwSuTvWBIRUTC6VC72nXYunzqgZA+IKdtxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.6.tgz", + "integrity": "sha512-lI23nIs4bnT3T8NIoh+vFaz5s2/DdP0Jgt2jxwgWljvwn82cLJtyi/If+fjFyoLMGIOz0U/fKvWE0d4jsNQEfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.6", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "license": "MIT", @@ -12599,14 +13532,12 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true, "license": "BSD-2-Clause" }, "node_modules/@zkochan/js-yaml": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.7.tgz", "integrity": "sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -12619,7 +13550,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, "license": "Python-2.0" }, "node_modules/abbrev": { @@ -12851,7 +13781,6 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -13089,6 +14018,16 @@ "node": ">=12.0.0" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/astring": { "version": "1.9.0", "license": "MIT", @@ -13399,7 +14338,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -13526,7 +14464,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, "license": "MIT", "dependencies": { "buffer": "^5.5.0", @@ -13804,7 +14741,6 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, "funding": [ { "type": "github", @@ -13868,6 +14804,16 @@ "node": ">=6.0.0" } }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/cacache": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.3.tgz", @@ -14097,6 +15043,23 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/chalk": { "version": "5.4.1", "license": "MIT", @@ -14153,6 +15116,16 @@ "dev": true, "license": "MIT" }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, "node_modules/cheerio": { "version": "1.0.0-rc.12", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", @@ -14316,7 +15289,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, "license": "MIT", "dependencies": { "restore-cursor": "^3.1.0" @@ -14389,7 +15361,6 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -16380,6 +17351,16 @@ } } }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/deep-extend": { "version": "0.6.0", "license": "MIT", @@ -16426,7 +17407,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, "license": "MIT", "dependencies": { "clone": "^1.0.2" @@ -16439,7 +17419,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8" @@ -16740,7 +17719,6 @@ "version": "16.4.7", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -16753,7 +17731,6 @@ "version": "12.0.3", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.3.tgz", "integrity": "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "dotenv": "^16.4.5" @@ -16793,7 +17770,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ejs/-/ejs-5.0.1.tgz", "integrity": "sha512-COqBPFMxuPTPspXl2DkVYaDS3HtrD1GpzOGkNTJ1IYkifq/r9h8SVEFrjA3D9/VJGOEoMQcrlhpntcSUrM8k6A==", - "dev": true, "license": "Apache-2.0", "bin": { "ejs": "bin/cli.js" @@ -16870,7 +17846,6 @@ "version": "1.4.5", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "dev": true, "license": "MIT", "dependencies": { "once": "^1.4.0" @@ -16893,7 +17868,6 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1" @@ -17130,6 +18104,48 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, "node_modules/escalade": { "version": "3.2.0", "license": "MIT", @@ -17870,6 +18886,16 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/exponential-backoff": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", @@ -18204,7 +19230,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, "license": "MIT", "dependencies": { "escape-string-regexp": "^1.0.5" @@ -18220,7 +19245,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" @@ -18606,7 +19630,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, "license": "MIT" }, "node_modules/fs-extra": { @@ -19977,7 +21000,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, "funding": [ { "type": "github", @@ -20595,7 +21617,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -20824,7 +21845,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -23094,7 +24114,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true, "license": "MIT" }, "node_modules/jsonfile": { @@ -23611,7 +24630,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", - "dev": true, "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -23767,7 +24785,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, "license": "MIT", "dependencies": { "chalk": "^4.1.0", @@ -23784,7 +24801,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -23800,7 +24816,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -23817,7 +24832,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -23863,6 +24877,13 @@ "loose-envify": "cli.js" } }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lower-case": { "version": "2.0.2", "license": "MIT", @@ -27226,7 +28247,6 @@ "version": "22.7.5", "resolved": "https://registry.npmjs.org/nx/-/nx-22.7.5.tgz", "integrity": "sha512-zoxsJabb33jl1QYnalDn0bicryrEBgSzdKp90d7VGGv/jDgzKrcLg/hw2ZxeYiOjWPIT/o8QNT9G9vTs4dv3AQ==", - "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -27374,7 +28394,6 @@ "version": "1.4.5", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.5.tgz", "integrity": "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==", - "dev": true, "license": "MIT", "dependencies": { "@emnapi/wasi-threads": "1.0.4", @@ -27385,7 +28404,6 @@ "version": "1.4.5", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.5.tgz", "integrity": "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==", - "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.4.0" @@ -27395,7 +28413,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz", "integrity": "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==", - "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.4.0" @@ -27408,7 +28425,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -27422,7 +28438,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -27436,7 +28451,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -27450,7 +28464,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -27464,7 +28477,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -27478,7 +28490,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -27492,7 +28503,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -27503,7 +28513,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -27513,7 +28522,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -27529,14 +28537,12 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, "license": "Python-2.0" }, "node_modules/nx/node_modules/axios": { "version": "1.16.0", "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.0.tgz", "integrity": "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==", - "dev": true, "license": "MIT", "dependencies": { "follow-redirects": "^1.16.0", @@ -27548,7 +28554,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.3.tgz", "integrity": "sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==", - "dev": true, "license": "MIT", "engines": { "node": "20 || >=22" @@ -27558,7 +28563,6 @@ "version": "5.0.6", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -27571,7 +28575,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -27588,7 +28591,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8" @@ -27598,7 +28600,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" @@ -27608,7 +28609,6 @@ "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -27618,7 +28618,6 @@ "version": "10.2.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "brace-expansion": "^5.0.5" @@ -27634,7 +28633,6 @@ "version": "7.7.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -27647,7 +28645,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -27657,7 +28654,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -27670,7 +28666,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -27688,7 +28683,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, "license": "MIT", "dependencies": { "cliui": "^8.0.1", @@ -27881,7 +28875,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", - "dev": true, "license": "MIT", "dependencies": { "bl": "^4.0.3", @@ -27904,7 +28897,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -27920,7 +28912,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -27937,7 +28928,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -28603,6 +29593,23 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, "node_modules/picocolors": { "version": "1.1.1", "license": "ISC" @@ -31595,7 +32602,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -31618,7 +32624,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, "license": "MIT", "dependencies": { "onetime": "^5.1.0", @@ -31677,6 +32682,51 @@ "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", "license": "Unlicense" }, + "node_modules/rollup": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.2", + "@rollup/rollup-android-arm64": "4.62.2", + "@rollup/rollup-darwin-arm64": "4.62.2", + "@rollup/rollup-darwin-x64": "4.62.2", + "@rollup/rollup-freebsd-arm64": "4.62.2", + "@rollup/rollup-freebsd-x64": "4.62.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", + "@rollup/rollup-linux-arm64-gnu": "4.62.2", + "@rollup/rollup-linux-arm64-musl": "4.62.2", + "@rollup/rollup-linux-loong64-gnu": "4.62.2", + "@rollup/rollup-linux-loong64-musl": "4.62.2", + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", + "@rollup/rollup-linux-ppc64-musl": "4.62.2", + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", + "@rollup/rollup-linux-riscv64-musl": "4.62.2", + "@rollup/rollup-linux-s390x-gnu": "4.62.2", + "@rollup/rollup-linux-x64-gnu": "4.62.2", + "@rollup/rollup-linux-x64-musl": "4.62.2", + "@rollup/rollup-openbsd-x64": "4.62.2", + "@rollup/rollup-openharmony-arm64": "4.62.2", + "@rollup/rollup-win32-arm64-msvc": "4.62.2", + "@rollup/rollup-win32-ia32-msvc": "4.62.2", + "@rollup/rollup-win32-x64-gnu": "4.62.2", + "@rollup/rollup-win32-x64-msvc": "4.62.2", + "fsevents": "~2.3.2" + } + }, "node_modules/roughjs": { "version": "4.6.6", "license": "MIT", @@ -32346,6 +33396,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/signal-exit": { "version": "3.0.7", "license": "ISC" @@ -32456,7 +33513,6 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz", "integrity": "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">= 18" @@ -32756,6 +33812,13 @@ "node": ">=8" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.1", "license": "MIT", @@ -33063,6 +34126,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, "node_modules/strip-outer": { "version": "1.0.1", "license": "MIT", @@ -33292,7 +34375,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, "license": "MIT", "dependencies": { "bl": "^4.0.3", @@ -33558,6 +34640,13 @@ "version": "1.0.3", "license": "MIT" }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, "node_modules/tinyexec": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.3.tgz", @@ -33622,12 +34711,31 @@ "node": "^18.0.0 || >=20.0.0" } }, - "node_modules/tmp": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.6.tgz", - "integrity": "sha512-5sJPdPjfI5Kx+qbrDesxkglRBxW//g7hCsqspEjwkewGvBMGIKMOTKzLt1hFVJzyadba3lDUN20O9qhvbQUSTA==", + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", "dev": true, "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "license": "MIT", "engines": { "node": ">=14.14" } @@ -33686,7 +34794,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, "license": "MIT", "bin": { "tree-kill": "cli.js" @@ -33895,7 +35002,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, "license": "MIT", "dependencies": { "json5": "^2.2.2", @@ -33910,7 +35016,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -34772,6 +35877,287 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/vite": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.5.tgz", + "integrity": "sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite-node/node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vite/node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/vitest": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.6.tgz", + "integrity": "sha512-xejya+bT/j/+R/AGa1XOfRxLmNUlLtlwjRsFUILF+xHfzElmGcmFydy2gqqIrd62ptIEfwVMofd19uNWD9L7Nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.6", + "@vitest/mocker": "3.2.6", + "@vitest/pretty-format": "^3.2.6", + "@vitest/runner": "3.2.6", + "@vitest/snapshot": "3.2.6", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.6", + "@vitest/ui": "3.2.6", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest/node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vitest/node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/walk-up-path": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-4.0.0.tgz", @@ -34814,7 +36200,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, "license": "MIT", "dependencies": { "defaults": "^1.0.3" @@ -35350,6 +36735,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wide-align": { "version": "1.1.5", "dev": true, @@ -35631,7 +37033,6 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -36347,8 +37748,8 @@ "node": ">=20" } }, - "packages/contract-case-jest": { - "name": "@contract-case/contract-case-jest", + "packages/contract-case-dsl-js": { + "name": "@contract-case/contract-case-dsl-js", "version": "0.29.1", "license": "BSD-3-Clause", "dependencies": { @@ -36358,14 +37759,105 @@ "@contract-case/case-entities-internal": "0.29.1", "@contract-case/case-plugin-base": "0.29.1", "@contract-case/case-plugin-dsl-types": "0.29.1", + "@contract-case/contract-case-dsl-js-internals": "0.29.1" + }, + "devDependencies": { + "@contract-case/eslint-config-case-maintainer": "0.29.1", + "eslint": "^9.39.1", + "prettier": "3.6.2", + "rimraf": "^6.1.2", + "typescript": "5.9.3" + }, + "engines": { + "node": ">=14.21.2" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/TimothyJones" + } + }, + "packages/contract-case-dsl-js-internals": { + "name": "@contract-case/contract-case-dsl-js-internals", + "version": "0.29.1", + "license": "BSD-3-Clause", + "dependencies": { + "@contract-case/case-connector": "0.29.1", + "chalk": "^4.1.2" + }, + "devDependencies": { + "@contract-case/eslint-config-case-maintainer": "0.29.1", + "eslint": "^9.39.1", + "prettier": "3.6.2", + "rimraf": "^6.1.2", + "typescript": "5.9.3" + }, + "engines": { + "node": ">=14.21.2" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/TimothyJones" + } + }, + "packages/contract-case-dsl-js-internals/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "packages/contract-case-dsl-js-internals/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "packages/contract-case-dsl-js-internals/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/contract-case-dsl-js-jest": { + "name": "@contract-case/contract-case-jest", + "version": "0.29.1", + "license": "BSD-3-Clause", + "dependencies": { "@contract-case/cli": "0.29.1", - "chalk": "^4.1.2", + "@contract-case/contract-case-dsl-js": "0.29.1", "ts-node": "^10.9.1" }, "bin": { "ContractCase": "dist/bin/ContractCase.mjs" }, "devDependencies": { + "@contract-case/case-definition-dsl": "0.29.1", + "@contract-case/case-entities-internal": "0.29.1", + "@contract-case/case-plugin-base": "0.29.1", "@contract-case/cli": "0.29.1", "@contract-case/eslint-config-case-maintainer": "0.29.1", "@grpc/grpc-js": "^1.13.5", @@ -36398,41 +37890,92 @@ "jest": "^29.4.3 | ^30.0.0" } }, - "packages/contract-case-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "license": "MIT", + "packages/contract-case-dsl-js-vitest": { + "name": "@contract-case/contract-case-dsl-js-vitest", + "version": "0.29.1", + "license": "BSD-3-Clause", "dependencies": { - "color-convert": "^2.0.1" + "@contract-case/contract-case-dsl-js": "0.29.1" + }, + "devDependencies": { + "@contract-case/eslint-config-case-maintainer": "0.29.1", + "@grpc/grpc-js": "^1.13.3", + "@grpc/proto-loader": "^0.8.0", + "@types/body-parser": "^1.19.2", + "@types/express": "^4.17.14", + "axios": "^1.13.5", + "body-parser": "^2.2.0", + "cross-env": "^10.1.0", + "eslint": "^9.39.1", + "express": "^4.20.0", + "prettier": "3.6.2", + "pretty-format": "^30.2.0", + "protobufjs": "^7.5.4", + "rimraf": "^6.1.2", + "typescript": "5.9.3", + "vitest": "^3.2.1" }, "engines": { - "node": ">=8" + "node": ">=14.21.2" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "individual", + "url": "https://github.com/sponsors/TimothyJones" + }, + "peerDependencies": { + "vitest": "^1.0.0 || ^2.0.0 || ^3.0.0" } }, - "packages/contract-case-jest/node_modules/chalk": { - "version": "4.1.2", - "license": "MIT", + "packages/contract-case-jest": { + "name": "@contract-case/contract-case-jest", + "version": "0.29.1", + "extraneous": true, + "license": "BSD-3-Clause", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@contract-case/case-connector": "0.29.1", + "@contract-case/case-core-plugin-http-dsl": "0.29.1", + "@contract-case/case-definition-dsl": "0.29.1", + "@contract-case/case-entities-internal": "0.29.1", + "@contract-case/case-plugin-base": "0.29.1", + "@contract-case/case-plugin-dsl-types": "0.29.1", + "@contract-case/cli": "0.29.1", + "chalk": "^4.1.2", + "ts-node": "^10.9.1" + }, + "bin": { + "ContractCase": "dist/bin/ContractCase.mjs" + }, + "devDependencies": { + "@contract-case/cli": "0.29.1", + "@contract-case/eslint-config-case-maintainer": "0.29.1", + "@grpc/grpc-js": "^1.13.5", + "@grpc/proto-loader": "^0.8.0", + "@types/body-parser": "^1.19.2", + "@types/express": "^4.17.14", + "@types/jest": "^30.0.0", + "axios": "^1.15.2", + "body-parser": "^2.2.0", + "cross-env": "^10.1.0", + "eslint": "^9.39.1", + "express": "^4.20.0", + "jest": "^30.2.0", + "prettier": "3.6.2", + "pretty-format": "^30.2.0", + "protobufjs": "^7.6.3", + "rimraf": "^6.1.2", + "ts-jest": "^29.4.5", + "ts-node": "^10.9.2", + "typescript": "5.9.3" }, "engines": { - "node": ">=10" + "node": ">=14.21.2" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "packages/contract-case-jest/node_modules/supports-color": { - "version": "7.2.0", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" + "type": "individual", + "url": "https://github.com/sponsors/TimothyJones" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "jest": "^29.4.3 | ^30.0.0" } }, "packages/documentation": { diff --git a/package.json b/package.json index 242d99a5c..c20bc5858 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,9 @@ "packages/*" ], "version": "0.29.1", + "overrides": { + "tmp": "^0.2.7" + }, "devDependencies": { "@contract-case/eslint-config-case-maintainer": "0.29.1", "example-extractor": "^0.0.4", @@ -33,5 +36,8 @@ "test": "lerna run test", "test:verify": "lerna run test:verify", "coverage": "lcov-result-merger 'packages/*/*/lcov.info' combined-coverage.info --prepend-source-files" + }, + "dependencies": { + "nx": "^22.5.2" } } diff --git a/packages/contract-case-jest/eslint.config.mjs b/packages/contract-case-dsl-js-internals/eslint.config.mjs similarity index 100% rename from packages/contract-case-jest/eslint.config.mjs rename to packages/contract-case-dsl-js-internals/eslint.config.mjs diff --git a/packages/contract-case-dsl-js-internals/package.json b/packages/contract-case-dsl-js-internals/package.json new file mode 100644 index 000000000..7c01e3727 --- /dev/null +++ b/packages/contract-case-dsl-js-internals/package.json @@ -0,0 +1,61 @@ +{ + "name": "@contract-case/contract-case-dsl-js-internals", + "version": "0.29.1", + "description": "Internal JavaScript/TypeScript connector code for ContractCase test framework bindings", + "keywords": [ + "testing", + "api", + "pact", + "contracttesting", + "contract-testing", + "contractcase" + ], + "author": "Timothy Jones (https://github.com/TimothyJones)", + "homepage": "https://case.contract-testing.io", + "license": "BSD-3-Clause", + "main": "./dist/src/index.js", + "types": "./dist/src/index.d.ts", + "directories": { + "src": "src", + "dist": "dist" + }, + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/case-contract-testing/case.git" + }, + "scripts": { + "build": "rimraf dist && tsc --project tsconfig.build.json", + "lint": "eslint", + "lint:fix": "eslint --fix", + "format:base": "prettier --parser typescript \"{src,bin}/*.ts\"", + "format:check": "npm run format:base -- --list-different", + "format:fix": "npm run format:base -- --write " + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/TimothyJones" + }, + "engines": { + "node": ">=14.21.2" + }, + "bugs": { + "url": "https://github.com/case-contract-testing/case/issues" + }, + "devDependencies": { + "@contract-case/eslint-config-case-maintainer": "0.29.1", + "eslint": "^9.39.1", + "prettier": "3.6.2", + "rimraf": "^6.1.2", + "typescript": "5.9.3" + }, + "dependencies": { + "@contract-case/case-connector": "0.29.1", + "chalk": "^4.1.2" + } +} diff --git a/packages/contract-case-jest/src/connectors/case-boundary/index.ts b/packages/contract-case-dsl-js-internals/src/connectors/case-boundary/index.ts similarity index 100% rename from packages/contract-case-jest/src/connectors/case-boundary/index.ts rename to packages/contract-case-dsl-js-internals/src/connectors/case-boundary/index.ts diff --git a/packages/contract-case-jest/src/connectors/case-boundary/mappers/boundaryResultToJs.ts b/packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/boundaryResultToJs.ts similarity index 100% rename from packages/contract-case-jest/src/connectors/case-boundary/mappers/boundaryResultToJs.ts rename to packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/boundaryResultToJs.ts diff --git a/packages/contract-case-jest/src/connectors/case-boundary/mappers/config/config.ts b/packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/config/config.ts similarity index 100% rename from packages/contract-case-jest/src/connectors/case-boundary/mappers/config/config.ts rename to packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/config/config.ts diff --git a/packages/contract-case-jest/src/connectors/case-boundary/mappers/config/index.ts b/packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/config/index.ts similarity index 100% rename from packages/contract-case-jest/src/connectors/case-boundary/mappers/config/index.ts rename to packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/config/index.ts diff --git a/packages/contract-case-jest/src/connectors/case-boundary/mappers/config/state/MappedStateHandler.ts b/packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/config/state/MappedStateHandler.ts similarity index 100% rename from packages/contract-case-jest/src/connectors/case-boundary/mappers/config/state/MappedStateHandler.ts rename to packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/config/state/MappedStateHandler.ts diff --git a/packages/contract-case-jest/src/connectors/case-boundary/mappers/config/state/state.ts b/packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/config/state/state.ts similarity index 100% rename from packages/contract-case-jest/src/connectors/case-boundary/mappers/config/state/state.ts rename to packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/config/state/state.ts diff --git a/packages/contract-case-jest/src/connectors/case-boundary/mappers/config/triggers.ts b/packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/config/triggers.ts similarity index 100% rename from packages/contract-case-jest/src/connectors/case-boundary/mappers/config/triggers.ts rename to packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/config/triggers.ts diff --git a/packages/contract-case-jest/src/connectors/case-boundary/mappers/index.ts b/packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/index.ts similarity index 100% rename from packages/contract-case-jest/src/connectors/case-boundary/mappers/index.ts rename to packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/index.ts diff --git a/packages/contract-case-jest/src/connectors/case-boundary/mappers/invokeableFunction.ts b/packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/invokeableFunction.ts similarity index 100% rename from packages/contract-case-jest/src/connectors/case-boundary/mappers/invokeableFunction.ts rename to packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/invokeableFunction.ts diff --git a/packages/contract-case-jest/src/connectors/case-boundary/mappers/jsErrorToBoundary.ts b/packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/jsErrorToBoundary.ts similarity index 97% rename from packages/contract-case-jest/src/connectors/case-boundary/mappers/jsErrorToBoundary.ts rename to packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/jsErrorToBoundary.ts index 6f4c3a03a..4ec59eecc 100644 --- a/packages/contract-case-jest/src/connectors/case-boundary/mappers/jsErrorToBoundary.ts +++ b/packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/jsErrorToBoundary.ts @@ -1,5 +1,5 @@ import { BoundaryFailure } from '@contract-case/case-connector/cjs'; -import { ContractCaseConfigurationError } from '../../../entities'; +import { ContractCaseConfigurationError } from '../../../entities/index.js'; export const makeBoundaryFailure = (error: Error): BoundaryFailure => new BoundaryFailure( diff --git a/packages/contract-case-jest/src/connectors/case-boundary/mappers/verificationHandles.ts b/packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/verificationHandles.ts similarity index 86% rename from packages/contract-case-jest/src/connectors/case-boundary/mappers/verificationHandles.ts rename to packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/verificationHandles.ts index 8334ecabc..116a08648 100644 --- a/packages/contract-case-jest/src/connectors/case-boundary/mappers/verificationHandles.ts +++ b/packages/contract-case-dsl-js-internals/src/connectors/case-boundary/mappers/verificationHandles.ts @@ -1,10 +1,10 @@ -import { BoundaryResult } from '@contract-case/case-connector'; -import { mapSuccessWithAny } from './boundaryResultToJs'; +import { BoundaryResult } from '@contract-case/case-connector/cjs'; +import { mapSuccessWithAny } from './boundaryResultToJs.js'; import { ContractCaseCoreError, VerificationHandle, VerificationTestHandle, -} from '../../../entities'; +} from '../../../entities/index.js'; const TEST_HANDLE_EXPECTED_FIELDS = { filePath: 'string', @@ -26,7 +26,7 @@ const isVerificationTestHandle = ( if (typeof handle !== 'object' || handle == null) { throw new ContractCaseCoreError( `Bug: The verification test handle array had a non-object or null. Full item: ${handle}`, - 'contract-case-jest', + 'contract-case-dsl-js-internals', ); } Object.entries(TEST_HANDLE_EXPECTED_FIELDS).forEach( @@ -34,7 +34,7 @@ const isVerificationTestHandle = ( if (!(expectedKey in handle)) { throw new ContractCaseCoreError( `Bug: One of the verification handles didn't include a key for '${expectedKey}'. Full object: ${handle}`, - 'contract-case-jest', + 'contract-case-dsl-js-internals', ); } if ( @@ -43,7 +43,7 @@ const isVerificationTestHandle = ( ) { throw new ContractCaseCoreError( `Bug: One of the verification handles had the wrong type for key '${expectedKey}'. Expected ${expectedValue} Full object: ${handle}`, - 'contract-case-jest', + 'contract-case-dsl-js-internals', ); } }, @@ -57,7 +57,7 @@ const checkContractVerificationHandle = ( if (typeof handle !== 'object' || handle == null) { throw new ContractCaseCoreError( `Bug: The contract verification handle array had a non-object or null. Full item: ${handle}`, - 'contract-case-jest', + 'contract-case-dsl-js-internals', ); } Object.entries(CONTRACT_HANDLE_EXPECTED_FIELDS).forEach( @@ -65,7 +65,7 @@ const checkContractVerificationHandle = ( if (!(expectedKey in handle)) { throw new ContractCaseCoreError( `Bug: One of the verification handles didn't include a key for '${expectedKey}'. Full object: ${handle}`, - 'contract-case-jest', + 'contract-case-dsl-js-internals', ); } if ( @@ -74,7 +74,7 @@ const checkContractVerificationHandle = ( ) { throw new ContractCaseCoreError( `Bug: One of the verification handles had the wrong type for key '${expectedKey}'. Expected ${expectedValue} Full object: ${handle}`, - 'contract-case-jest', + 'contract-case-dsl-js-internals', ); } }, @@ -82,7 +82,7 @@ const checkContractVerificationHandle = ( if (!('testHandles' in handle && Array.isArray(handle.testHandles))) { throw new ContractCaseCoreError( `Bug: One of the verification handles didn't include a key for 'testHandles' or it wasn't an array. Full object: ${JSON.stringify(handle)}`, - 'contract-case-jest', + 'contract-case-dsl-js-internals', ); } return handle.testHandles.every(isVerificationTestHandle); @@ -95,7 +95,7 @@ export const mapContractVerificationHandles = ( if (!Array.isArray(array)) { throw new ContractCaseCoreError( "Bug: The result from the contract verification call wasn't an array", - 'contract-case-jest', + 'contract-case-dsl-js-internals', ); } diff --git a/packages/contract-case-jest/src/connectors/defaultTestPrinter.ts b/packages/contract-case-dsl-js-internals/src/connectors/defaultTestPrinter.ts similarity index 100% rename from packages/contract-case-jest/src/connectors/defaultTestPrinter.ts rename to packages/contract-case-dsl-js-internals/src/connectors/defaultTestPrinter.ts diff --git a/packages/contract-case-jest/src/connectors/handler.ts b/packages/contract-case-dsl-js-internals/src/connectors/handler.ts similarity index 100% rename from packages/contract-case-jest/src/connectors/handler.ts rename to packages/contract-case-dsl-js-internals/src/connectors/handler.ts diff --git a/packages/contract-case-jest/src/entities/config.ts b/packages/contract-case-dsl-js-internals/src/entities/config.ts similarity index 100% rename from packages/contract-case-jest/src/entities/config.ts rename to packages/contract-case-dsl-js-internals/src/entities/config.ts diff --git a/packages/contract-case-jest/src/entities/errors/ContractCaseConfigurationError.ts b/packages/contract-case-dsl-js-internals/src/entities/errors/ContractCaseConfigurationError.ts similarity index 100% rename from packages/contract-case-jest/src/entities/errors/ContractCaseConfigurationError.ts rename to packages/contract-case-dsl-js-internals/src/entities/errors/ContractCaseConfigurationError.ts diff --git a/packages/contract-case-jest/src/entities/errors/ContractCaseCoreError.ts b/packages/contract-case-dsl-js-internals/src/entities/errors/ContractCaseCoreError.ts similarity index 100% rename from packages/contract-case-jest/src/entities/errors/ContractCaseCoreError.ts rename to packages/contract-case-dsl-js-internals/src/entities/errors/ContractCaseCoreError.ts diff --git a/packages/contract-case-jest/src/entities/errors/ContractCaseExpectationsNotMet.ts b/packages/contract-case-dsl-js-internals/src/entities/errors/ContractCaseExpectationsNotMet.ts similarity index 100% rename from packages/contract-case-jest/src/entities/errors/ContractCaseExpectationsNotMet.ts rename to packages/contract-case-dsl-js-internals/src/entities/errors/ContractCaseExpectationsNotMet.ts diff --git a/packages/contract-case-jest/src/entities/errors/index.ts b/packages/contract-case-dsl-js-internals/src/entities/errors/index.ts similarity index 100% rename from packages/contract-case-jest/src/entities/errors/index.ts rename to packages/contract-case-dsl-js-internals/src/entities/errors/index.ts diff --git a/packages/contract-case-jest/src/entities/index.ts b/packages/contract-case-dsl-js-internals/src/entities/index.ts similarity index 100% rename from packages/contract-case-jest/src/entities/index.ts rename to packages/contract-case-dsl-js-internals/src/entities/index.ts diff --git a/packages/contract-case-jest/src/entities/types.triggers.ts b/packages/contract-case-dsl-js-internals/src/entities/types.triggers.ts similarity index 100% rename from packages/contract-case-jest/src/entities/types.triggers.ts rename to packages/contract-case-dsl-js-internals/src/entities/types.triggers.ts diff --git a/packages/contract-case-jest/src/entities/types.ts b/packages/contract-case-dsl-js-internals/src/entities/types.ts similarity index 100% rename from packages/contract-case-jest/src/entities/types.ts rename to packages/contract-case-dsl-js-internals/src/entities/types.ts diff --git a/packages/contract-case-jest/src/entities/versionString.ts b/packages/contract-case-dsl-js-internals/src/entities/versionString.ts similarity index 100% rename from packages/contract-case-jest/src/entities/versionString.ts rename to packages/contract-case-dsl-js-internals/src/entities/versionString.ts diff --git a/packages/contract-case-dsl-js-internals/src/index.ts b/packages/contract-case-dsl-js-internals/src/index.ts new file mode 100644 index 000000000..5aa62f56e --- /dev/null +++ b/packages/contract-case-dsl-js-internals/src/index.ts @@ -0,0 +1,30 @@ +/*! + * ContractCase Connector JS - Internal connector code for ContractCase test framework bindings + * Copyright(c) 2022-2024 Timothy Jones (TLJ) + * BSD-3-Clause license + */ + +// Internal boundary mappers +export { + mapSuccess, + mapSuccessWithAny, + mapFailureToJsError, +} from './connectors/case-boundary/mappers/boundaryResultToJs.js'; +export { makeBoundaryFailure } from './connectors/case-boundary/mappers/jsErrorToBoundary.js'; +export { mapInvokeableFunction } from './connectors/case-boundary/mappers/invokeableFunction.js'; +export { mapContractVerificationHandles } from './connectors/case-boundary/mappers/verificationHandles.js'; +export { + mapConfig, + mapSuccessConfig, + mapFailingConfig, +} from './connectors/case-boundary/mappers/config/config.js'; + +// Internal printer and error handler +export { + defaultPrinter, + crashPrinter, +} from './connectors/defaultTestPrinter.js'; +export { errorHandler, errorReporter } from './connectors/handler.js'; + +// Entity types (shared between internal and user-facing code) +export * from './entities/index.js'; diff --git a/packages/contract-case-dsl-js-internals/tsconfig.build.json b/packages/contract-case-dsl-js-internals/tsconfig.build.json new file mode 100644 index 000000000..501bccfb0 --- /dev/null +++ b/packages/contract-case-dsl-js-internals/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "extends": "@contract-case/case-maintainer-config/tsconfig.json", + "compilerOptions": { + "outDir": "dist/", + "module": "nodenext", + "moduleResolution": "nodenext" + }, + "include": ["src/**/*.ts"], + "exclude": [ + "src/**/*.spec.ts", + "src/**/*.spec.verify.ts", + "src/**/*.spec-dont-run.ts", + "dist/**/*.js", + "coverage" + ] +} diff --git a/packages/contract-case-dsl-js-internals/tsconfig.json b/packages/contract-case-dsl-js-internals/tsconfig.json new file mode 100644 index 000000000..c404360df --- /dev/null +++ b/packages/contract-case-dsl-js-internals/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@contract-case/case-maintainer-config/tsconfig.json", + "compilerOptions": { + "outDir": "dist/" + }, + "exclude": ["jest.config.ts", "dist/**/*.js", "coverage"] +} diff --git a/packages/contract-case-jest/.gitignore b/packages/contract-case-dsl-js-jest/.gitignore similarity index 100% rename from packages/contract-case-jest/.gitignore rename to packages/contract-case-dsl-js-jest/.gitignore diff --git a/packages/contract-case-jest/.npmignore b/packages/contract-case-dsl-js-jest/.npmignore similarity index 100% rename from packages/contract-case-jest/.npmignore rename to packages/contract-case-dsl-js-jest/.npmignore diff --git a/packages/contract-case-jest/.prettierrc b/packages/contract-case-dsl-js-jest/.prettierrc similarity index 100% rename from packages/contract-case-jest/.prettierrc rename to packages/contract-case-dsl-js-jest/.prettierrc diff --git a/packages/contract-case-jest/CHANGELOG.md b/packages/contract-case-dsl-js-jest/CHANGELOG.md similarity index 100% rename from packages/contract-case-jest/CHANGELOG.md rename to packages/contract-case-dsl-js-jest/CHANGELOG.md diff --git a/packages/contract-case-jest/LICENSE b/packages/contract-case-dsl-js-jest/LICENSE similarity index 100% rename from packages/contract-case-jest/LICENSE rename to packages/contract-case-dsl-js-jest/LICENSE diff --git a/packages/contract-case-jest/README.md b/packages/contract-case-dsl-js-jest/README.md similarity index 100% rename from packages/contract-case-jest/README.md rename to packages/contract-case-dsl-js-jest/README.md diff --git a/packages/contract-case-jest/bin/ContractCase.mts b/packages/contract-case-dsl-js-jest/bin/ContractCase.mts similarity index 100% rename from packages/contract-case-jest/bin/ContractCase.mts rename to packages/contract-case-dsl-js-jest/bin/ContractCase.mts diff --git a/packages/contract-case-jest/case-contracts/function-definer/function-execution-983746399493aa57d57a95eb0e3cb9e5ee0961a5faf76a046e0ac190f65d52eb.case.json b/packages/contract-case-dsl-js-jest/case-contracts/function-definer/function-execution-983746399493aa57d57a95eb0e3cb9e5ee0961a5faf76a046e0ac190f65d52eb.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/function-definer/function-execution-983746399493aa57d57a95eb0e3cb9e5ee0961a5faf76a046e0ac190f65d52eb.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/function-definer/function-execution-983746399493aa57d57a95eb0e3cb9e5ee0961a5faf76a046e0ac190f65d52eb.case.json diff --git a/packages/contract-case-jest/case-contracts/function-definer/function-execution-c44cdd64be41f16b7493b8a0cc1b54353b1f0b7fc89cd5c61d02e1bbf04b53e5.case.json b/packages/contract-case-dsl-js-jest/case-contracts/function-definer/function-execution-c44cdd64be41f16b7493b8a0cc1b54353b1f0b7fc89cd5c61d02e1bbf04b53e5.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/function-definer/function-execution-c44cdd64be41f16b7493b8a0cc1b54353b1f0b7fc89cd5c61d02e1bbf04b53e5.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/function-definer/function-execution-c44cdd64be41f16b7493b8a0cc1b54353b1f0b7fc89cd5c61d02e1bbf04b53e5.case.json diff --git a/packages/contract-case-jest/case-contracts/function-definer/function-execution-cfed1150d2468d80dca8de428e0e7fdf0348ba863b68283216b5b4447270159c.case.json b/packages/contract-case-dsl-js-jest/case-contracts/function-definer/function-execution-cfed1150d2468d80dca8de428e0e7fdf0348ba863b68283216b5b4447270159c.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/function-definer/function-execution-cfed1150d2468d80dca8de428e0e7fdf0348ba863b68283216b5b4447270159c.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/function-definer/function-execution-cfed1150d2468d80dca8de428e0e7fdf0348ba863b68283216b5b4447270159c.case.json diff --git a/packages/contract-case-jest/case-contracts/function-definer/function-execution-main.case.json b/packages/contract-case-dsl-js-jest/case-contracts/function-definer/function-execution-main.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/function-definer/function-execution-main.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/function-definer/function-execution-main.case.json diff --git a/packages/contract-case-jest/case-contracts/function-execution/function-caller-400944f70534f3dc241d3fe8330b7ec76bbc6b3a53b11d8ebd6a5a6a95146d8f.case.json b/packages/contract-case-dsl-js-jest/case-contracts/function-execution/function-caller-400944f70534f3dc241d3fe8330b7ec76bbc6b3a53b11d8ebd6a5a6a95146d8f.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/function-execution/function-caller-400944f70534f3dc241d3fe8330b7ec76bbc6b3a53b11d8ebd6a5a6a95146d8f.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/function-execution/function-caller-400944f70534f3dc241d3fe8330b7ec76bbc6b3a53b11d8ebd6a5a6a95146d8f.case.json diff --git a/packages/contract-case-jest/case-contracts/function-execution/function-caller-9a3b12842c78ea708b13ce276d6e32df8a3126bc5a93f198521c81c70b8bb2e9.case.json b/packages/contract-case-dsl-js-jest/case-contracts/function-execution/function-caller-9a3b12842c78ea708b13ce276d6e32df8a3126bc5a93f198521c81c70b8bb2e9.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/function-execution/function-caller-9a3b12842c78ea708b13ce276d6e32df8a3126bc5a93f198521c81c70b8bb2e9.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/function-execution/function-caller-9a3b12842c78ea708b13ce276d6e32df8a3126bc5a93f198521c81c70b8bb2e9.case.json diff --git a/packages/contract-case-jest/case-contracts/function-execution/function-caller-bcac4a1c1076fb91328174d3918337af1b4d3722b34773eea9a358900c387530.case.json b/packages/contract-case-dsl-js-jest/case-contracts/function-execution/function-caller-bcac4a1c1076fb91328174d3918337af1b4d3722b34773eea9a358900c387530.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/function-execution/function-caller-bcac4a1c1076fb91328174d3918337af1b4d3722b34773eea9a358900c387530.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/function-execution/function-caller-bcac4a1c1076fb91328174d3918337af1b4d3722b34773eea9a358900c387530.case.json diff --git a/packages/contract-case-jest/case-contracts/function-execution/function-caller-main.case.json b/packages/contract-case-dsl-js-jest/case-contracts/function-execution/function-caller-main.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/function-execution/function-caller-main.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/function-execution/function-caller-main.case.json diff --git a/packages/contract-case-jest/case-contracts/http-request-provider/http-request-consumer-47cbaddd42bc03fb9ac1297a63b5ca7dd8009c5d5293a1e6f3ddcc73e29597f3.case.json b/packages/contract-case-dsl-js-jest/case-contracts/http-request-provider/http-request-consumer-47cbaddd42bc03fb9ac1297a63b5ca7dd8009c5d5293a1e6f3ddcc73e29597f3.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/http-request-provider/http-request-consumer-47cbaddd42bc03fb9ac1297a63b5ca7dd8009c5d5293a1e6f3ddcc73e29597f3.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/http-request-provider/http-request-consumer-47cbaddd42bc03fb9ac1297a63b5ca7dd8009c5d5293a1e6f3ddcc73e29597f3.case.json diff --git a/packages/contract-case-jest/case-contracts/http-request-provider/http-request-consumer-55009680a088b269a71b3e86269eef63cb2e2b8328d3a1bbd884f824bac5b912.case.json b/packages/contract-case-dsl-js-jest/case-contracts/http-request-provider/http-request-consumer-55009680a088b269a71b3e86269eef63cb2e2b8328d3a1bbd884f824bac5b912.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/http-request-provider/http-request-consumer-55009680a088b269a71b3e86269eef63cb2e2b8328d3a1bbd884f824bac5b912.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/http-request-provider/http-request-consumer-55009680a088b269a71b3e86269eef63cb2e2b8328d3a1bbd884f824bac5b912.case.json diff --git a/packages/contract-case-jest/case-contracts/http-request-provider/http-request-consumer-63e22c94d86a90f4bc0c73c9205f8fac1683be14132ad849ad4452ca912ebb41.case.json b/packages/contract-case-dsl-js-jest/case-contracts/http-request-provider/http-request-consumer-63e22c94d86a90f4bc0c73c9205f8fac1683be14132ad849ad4452ca912ebb41.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/http-request-provider/http-request-consumer-63e22c94d86a90f4bc0c73c9205f8fac1683be14132ad849ad4452ca912ebb41.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/http-request-provider/http-request-consumer-63e22c94d86a90f4bc0c73c9205f8fac1683be14132ad849ad4452ca912ebb41.case.json diff --git a/packages/contract-case-jest/case-contracts/http-request-provider/http-request-consumer-8e6213abbb7cfc5460d338b160a62fbfcd17c09bdc0eb7b996485ee683132ef4.case.json b/packages/contract-case-dsl-js-jest/case-contracts/http-request-provider/http-request-consumer-8e6213abbb7cfc5460d338b160a62fbfcd17c09bdc0eb7b996485ee683132ef4.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/http-request-provider/http-request-consumer-8e6213abbb7cfc5460d338b160a62fbfcd17c09bdc0eb7b996485ee683132ef4.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/http-request-provider/http-request-consumer-8e6213abbb7cfc5460d338b160a62fbfcd17c09bdc0eb7b996485ee683132ef4.case.json diff --git a/packages/contract-case-jest/case-contracts/http-request-provider/http-request-consumer-main.case.json b/packages/contract-case-dsl-js-jest/case-contracts/http-request-provider/http-request-consumer-main.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/http-request-provider/http-request-consumer-main.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/http-request-provider/http-request-consumer-main.case.json diff --git a/packages/contract-case-jest/case-contracts/http-response-provider/http-response-consumer-74d8aa637e1f5f672b583ba38c86060aa9330e96b5181e17095073afce265011.case.json b/packages/contract-case-dsl-js-jest/case-contracts/http-response-provider/http-response-consumer-74d8aa637e1f5f672b583ba38c86060aa9330e96b5181e17095073afce265011.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/http-response-provider/http-response-consumer-74d8aa637e1f5f672b583ba38c86060aa9330e96b5181e17095073afce265011.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/http-response-provider/http-response-consumer-74d8aa637e1f5f672b583ba38c86060aa9330e96b5181e17095073afce265011.case.json diff --git a/packages/contract-case-jest/case-contracts/http-response-provider/http-response-consumer-7b2e98081dfaa95cf7b8372e3d65d7ebff084bcf83a6c31eb47dfffaaf766b12.case.json b/packages/contract-case-dsl-js-jest/case-contracts/http-response-provider/http-response-consumer-7b2e98081dfaa95cf7b8372e3d65d7ebff084bcf83a6c31eb47dfffaaf766b12.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/http-response-provider/http-response-consumer-7b2e98081dfaa95cf7b8372e3d65d7ebff084bcf83a6c31eb47dfffaaf766b12.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/http-response-provider/http-response-consumer-7b2e98081dfaa95cf7b8372e3d65d7ebff084bcf83a6c31eb47dfffaaf766b12.case.json diff --git a/packages/contract-case-jest/case-contracts/http-response-provider/http-response-consumer-d50e9d50553be5be0206aafc0eeb2268b76883695c4c1db02b3dae0b7011f5cb.case.json b/packages/contract-case-dsl-js-jest/case-contracts/http-response-provider/http-response-consumer-d50e9d50553be5be0206aafc0eeb2268b76883695c4c1db02b3dae0b7011f5cb.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/http-response-provider/http-response-consumer-d50e9d50553be5be0206aafc0eeb2268b76883695c4c1db02b3dae0b7011f5cb.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/http-response-provider/http-response-consumer-d50e9d50553be5be0206aafc0eeb2268b76883695c4c1db02b3dae0b7011f5cb.case.json diff --git a/packages/contract-case-jest/case-contracts/http-response-provider/http-response-consumer-e23af1564cc3ea7fde22b088c783ef4c254e194d61cc0478c7dc0ca5c962d358.case.json b/packages/contract-case-dsl-js-jest/case-contracts/http-response-provider/http-response-consumer-e23af1564cc3ea7fde22b088c783ef4c254e194d61cc0478c7dc0ca5c962d358.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/http-response-provider/http-response-consumer-e23af1564cc3ea7fde22b088c783ef4c254e194d61cc0478c7dc0ca5c962d358.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/http-response-provider/http-response-consumer-e23af1564cc3ea7fde22b088c783ef4c254e194d61cc0478c7dc0ca5c962d358.case.json diff --git a/packages/contract-case-jest/case-contracts/http-response-provider/http-response-consumer-main.case.json b/packages/contract-case-dsl-js-jest/case-contracts/http-response-provider/http-response-consumer-main.case.json similarity index 100% rename from packages/contract-case-jest/case-contracts/http-response-provider/http-response-consumer-main.case.json rename to packages/contract-case-dsl-js-jest/case-contracts/http-response-provider/http-response-consumer-main.case.json diff --git a/packages/contract-case-dsl-js-jest/eslint.config.mjs b/packages/contract-case-dsl-js-jest/eslint.config.mjs new file mode 100644 index 000000000..83c0f6f37 --- /dev/null +++ b/packages/contract-case-dsl-js-jest/eslint.config.mjs @@ -0,0 +1,3 @@ +import lintConfig from '@contract-case/eslint-config-case-maintainer'; + +export default [...lintConfig]; diff --git a/packages/contract-case-jest/jest.config.ts b/packages/contract-case-dsl-js-jest/jest.config.ts similarity index 100% rename from packages/contract-case-jest/jest.config.ts rename to packages/contract-case-dsl-js-jest/jest.config.ts diff --git a/packages/contract-case-jest/package.json b/packages/contract-case-dsl-js-jest/package.json similarity index 92% rename from packages/contract-case-jest/package.json rename to packages/contract-case-dsl-js-jest/package.json index b8e27c5a6..1be5701ff 100644 --- a/packages/contract-case-jest/package.json +++ b/packages/contract-case-dsl-js-jest/package.json @@ -1,7 +1,7 @@ { "name": "@contract-case/contract-case-jest", "version": "0.29.1", - "description": "ContractCase contract testing suite", + "description": "ContractCase contract testing suite for Jest", "keywords": [ "testing", "api", @@ -56,6 +56,9 @@ "url": "https://github.com/case-contract-testing/case/issues" }, "devDependencies": { + "@contract-case/case-definition-dsl": "0.29.1", + "@contract-case/case-entities-internal": "0.29.1", + "@contract-case/case-plugin-base": "0.29.1", "@contract-case/cli": "0.29.1", "@contract-case/eslint-config-case-maintainer": "0.29.1", "@grpc/grpc-js": "^1.13.5", @@ -81,14 +84,8 @@ "jest": "^29.4.3 | ^30.0.0" }, "dependencies": { - "@contract-case/case-connector": "0.29.1", - "@contract-case/case-core-plugin-http-dsl": "0.29.1", - "@contract-case/case-definition-dsl": "0.29.1", - "@contract-case/case-entities-internal": "0.29.1", - "@contract-case/case-plugin-base": "0.29.1", - "@contract-case/case-plugin-dsl-types": "0.29.1", "@contract-case/cli": "0.29.1", - "chalk": "^4.1.2", + "@contract-case/contract-case-dsl-js": "0.29.1", "ts-node": "^10.9.1" } } diff --git a/packages/contract-case-jest/script/download-contracts.sh b/packages/contract-case-dsl-js-jest/script/download-contracts.sh similarity index 100% rename from packages/contract-case-jest/script/download-contracts.sh rename to packages/contract-case-dsl-js-jest/script/download-contracts.sh diff --git a/packages/contract-case-jest/src/__tests__/client/connectors/grpc/clientExample.ts b/packages/contract-case-dsl-js-jest/src/__tests__/client/connectors/grpc/clientExample.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/client/connectors/grpc/clientExample.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/client/connectors/grpc/clientExample.ts diff --git a/packages/contract-case-jest/src/__tests__/client/connectors/http/index.ts b/packages/contract-case-dsl-js-jest/src/__tests__/client/connectors/http/index.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/client/connectors/http/index.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/client/connectors/http/index.ts diff --git a/packages/contract-case-jest/src/__tests__/client/connectors/http/internals/axiosConnector.ts b/packages/contract-case-dsl-js-jest/src/__tests__/client/connectors/http/internals/axiosConnector.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/client/connectors/http/internals/axiosConnector.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/client/connectors/http/internals/axiosConnector.ts diff --git a/packages/contract-case-jest/src/__tests__/client/connectors/http/internals/marshaller.ts b/packages/contract-case-dsl-js-jest/src/__tests__/client/connectors/http/internals/marshaller.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/client/connectors/http/internals/marshaller.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/client/connectors/http/internals/marshaller.ts diff --git a/packages/contract-case-jest/src/__tests__/client/entities/apiErrors.ts b/packages/contract-case-dsl-js-jest/src/__tests__/client/entities/apiErrors.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/client/entities/apiErrors.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/client/entities/apiErrors.ts diff --git a/packages/contract-case-jest/src/__tests__/client/entities/errors.ts b/packages/contract-case-dsl-js-jest/src/__tests__/client/entities/errors.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/client/entities/errors.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/client/entities/errors.ts diff --git a/packages/contract-case-jest/src/__tests__/client/entities/types.ts b/packages/contract-case-dsl-js-jest/src/__tests__/client/entities/types.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/client/entities/types.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/client/entities/types.ts diff --git a/packages/contract-case-jest/src/__tests__/client/http.ts b/packages/contract-case-dsl-js-jest/src/__tests__/client/http.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/client/http.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/client/http.ts diff --git a/packages/contract-case-jest/src/__tests__/documentation/YourApi.ts b/packages/contract-case-dsl-js-jest/src/__tests__/documentation/YourApi.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/documentation/YourApi.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/documentation/YourApi.ts diff --git a/packages/contract-case-jest/src/__tests__/documentation/creating-a-contract.spec-norun.ts b/packages/contract-case-dsl-js-jest/src/__tests__/documentation/creating-a-contract.spec-norun.ts similarity index 95% rename from packages/contract-case-jest/src/__tests__/documentation/creating-a-contract.spec-norun.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/documentation/creating-a-contract.spec-norun.ts index e442b2614..830b4dc9f 100644 --- a/packages/contract-case-jest/src/__tests__/documentation/creating-a-contract.spec-norun.ts +++ b/packages/contract-case-dsl-js-jest/src/__tests__/documentation/creating-a-contract.spec-norun.ts @@ -1,13 +1,12 @@ /* eslint-disable import/no-extraneous-dependencies */ -/* eslint-disable import/order */ /* eslint-disable jest/expect-expect */ -import { willReceiveHttpRequest } from '../../boundaries/index.js'; -// example-extract _creating-a-contract import { + willReceiveHttpRequest, ContractCaseDefiner, defineContract, } from '@contract-case/contract-case-jest'; +// example-extract _creating-a-contract defineContract( { diff --git a/packages/contract-case-jest/src/__tests__/documentation/defining-an-example-states.spec-norun.ts b/packages/contract-case-dsl-js-jest/src/__tests__/documentation/defining-an-example-states.spec-norun.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/documentation/defining-an-example-states.spec-norun.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/documentation/defining-an-example-states.spec-norun.ts diff --git a/packages/contract-case-jest/src/__tests__/documentation/defining-an-example.spec-norun.ts b/packages/contract-case-dsl-js-jest/src/__tests__/documentation/defining-an-example.spec-norun.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/documentation/defining-an-example.spec-norun.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/documentation/defining-an-example.spec-norun.ts diff --git a/packages/contract-case-jest/src/__tests__/documentation/verifying-a-contract.spec-norun.ts b/packages/contract-case-dsl-js-jest/src/__tests__/documentation/verifying-a-contract.spec-norun.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/documentation/verifying-a-contract.spec-norun.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/documentation/verifying-a-contract.spec-norun.ts diff --git a/packages/contract-case-jest/src/__tests__/fixtures/grpcConstants.ts b/packages/contract-case-dsl-js-jest/src/__tests__/fixtures/grpcConstants.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/fixtures/grpcConstants.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/fixtures/grpcConstants.ts diff --git a/packages/contract-case-jest/src/__tests__/fixtures/grpcLoader.ts b/packages/contract-case-dsl-js-jest/src/__tests__/fixtures/grpcLoader.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/fixtures/grpcLoader.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/fixtures/grpcLoader.ts diff --git a/packages/contract-case-jest/src/__tests__/fixtures/grpcTypeResolver.ts b/packages/contract-case-dsl-js-jest/src/__tests__/fixtures/grpcTypeResolver.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/fixtures/grpcTypeResolver.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/fixtures/grpcTypeResolver.ts diff --git a/packages/contract-case-jest/src/__tests__/fixtures/grpc_endpoints.proto b/packages/contract-case-dsl-js-jest/src/__tests__/fixtures/grpc_endpoints.proto similarity index 100% rename from packages/contract-case-jest/src/__tests__/fixtures/grpc_endpoints.proto rename to packages/contract-case-dsl-js-jest/src/__tests__/fixtures/grpc_endpoints.proto diff --git a/packages/contract-case-jest/src/__tests__/server/connectors/grpc/createServer.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/connectors/grpc/createServer.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/connectors/grpc/createServer.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/connectors/grpc/createServer.ts diff --git a/packages/contract-case-jest/src/__tests__/server/connectors/grpc/handlers.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/connectors/grpc/handlers.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/connectors/grpc/handlers.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/connectors/grpc/handlers.ts diff --git a/packages/contract-case-jest/src/__tests__/server/connectors/grpc/start.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/connectors/grpc/start.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/connectors/grpc/start.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/connectors/grpc/start.ts diff --git a/packages/contract-case-jest/src/__tests__/server/connectors/http/handlers.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/connectors/http/handlers.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/connectors/http/handlers.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/connectors/http/handlers.ts diff --git a/packages/contract-case-jest/src/__tests__/server/connectors/http/index.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/connectors/http/index.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/connectors/http/index.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/connectors/http/index.ts diff --git a/packages/contract-case-jest/src/__tests__/server/connectors/http/responder.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/connectors/http/responder.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/connectors/http/responder.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/connectors/http/responder.ts diff --git a/packages/contract-case-jest/src/__tests__/server/connectors/http/routes.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/connectors/http/routes.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/connectors/http/routes.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/connectors/http/routes.ts diff --git a/packages/contract-case-jest/src/__tests__/server/domain/baseService.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/domain/baseService.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/domain/baseService.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/domain/baseService.ts diff --git a/packages/contract-case-jest/src/__tests__/server/domain/healthService.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/domain/healthService.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/domain/healthService.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/domain/healthService.ts diff --git a/packages/contract-case-jest/src/__tests__/server/domain/types.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/domain/types.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/domain/types.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/domain/types.ts diff --git a/packages/contract-case-jest/src/__tests__/server/domain/userService.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/domain/userService.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/domain/userService.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/domain/userService.ts diff --git a/packages/contract-case-jest/src/__tests__/server/domain/users/defaultUserRepository.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/domain/users/defaultUserRepository.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/domain/users/defaultUserRepository.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/domain/users/defaultUserRepository.ts diff --git a/packages/contract-case-jest/src/__tests__/server/entities/UserNotFoundException.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/entities/UserNotFoundException.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/entities/UserNotFoundException.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/entities/UserNotFoundException.ts diff --git a/packages/contract-case-jest/src/__tests__/server/entities/responses.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/entities/responses.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/entities/responses.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/entities/responses.ts diff --git a/packages/contract-case-jest/src/__tests__/server/grpc.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/grpc.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/grpc.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/grpc.ts diff --git a/packages/contract-case-jest/src/__tests__/server/http.ts b/packages/contract-case-dsl-js-jest/src/__tests__/server/http.ts similarity index 100% rename from packages/contract-case-jest/src/__tests__/server/http.ts rename to packages/contract-case-dsl-js-jest/src/__tests__/server/http.ts diff --git a/packages/contract-case-jest/src/boundaries/index.ts b/packages/contract-case-dsl-js-jest/src/boundaries/index.ts similarity index 50% rename from packages/contract-case-jest/src/boundaries/index.ts rename to packages/contract-case-dsl-js-jest/src/boundaries/index.ts index 6f993d4e4..9cdf83a3d 100644 --- a/packages/contract-case-jest/src/boundaries/index.ts +++ b/packages/contract-case-dsl-js-jest/src/boundaries/index.ts @@ -1,2 +1 @@ -export * from './dsl/index.js'; export * from './jest/index.js'; diff --git a/packages/contract-case-jest/src/boundaries/jest/index.ts b/packages/contract-case-dsl-js-jest/src/boundaries/jest/index.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/jest/index.ts rename to packages/contract-case-dsl-js-jest/src/boundaries/jest/index.ts diff --git a/packages/contract-case-jest/src/boundaries/jest/jest.ts b/packages/contract-case-dsl-js-jest/src/boundaries/jest/jest.ts similarity index 95% rename from packages/contract-case-jest/src/boundaries/jest/jest.ts rename to packages/contract-case-dsl-js-jest/src/boundaries/jest/jest.ts index 37f76b6ad..f2b9c25cf 100644 --- a/packages/contract-case-jest/src/boundaries/jest/jest.ts +++ b/packages/contract-case-dsl-js-jest/src/boundaries/jest/jest.ts @@ -1,11 +1,13 @@ /* eslint-disable jest/expect-expect */ /* eslint-disable jest/no-export */ -import { ContractCaseDefiner } from '../../connectors/ContractDefiner.js'; -import { ContractVerifier } from '../../connectors/ContractVerifier.js'; import { + ContractCaseDefiner, + ContractVerifier, +} from '@contract-case/contract-case-dsl-js'; +import type { ContractMetadata, ContractWriteSuccess, -} from '../../entities/index.js'; +} from '@contract-case/contract-case-dsl-js'; import type { ContractCaseJestConfig, ContractCaseJestVerifierConfig, diff --git a/packages/contract-case-jest/src/boundaries/jest/types.ts b/packages/contract-case-dsl-js-jest/src/boundaries/jest/types.ts similarity index 63% rename from packages/contract-case-jest/src/boundaries/jest/types.ts rename to packages/contract-case-dsl-js-jest/src/boundaries/jest/types.ts index c5ae0357b..dfb0da481 100644 --- a/packages/contract-case-jest/src/boundaries/jest/types.ts +++ b/packages/contract-case-dsl-js-jest/src/boundaries/jest/types.ts @@ -1,9 +1,9 @@ -import { ContractCaseDefiner } from '../../connectors/ContractDefiner.js'; -import { ContractVerifier } from '../../connectors/ContractVerifier.js'; -import { +import type { + ContractCaseDefiner, + ContractVerifier, ContractCaseConfig, ContractCaseVerifierConfig, -} from '../../entities/config.js'; +} from '@contract-case/contract-case-dsl-js'; export type ContractCaseJestConfig = ContractCaseConfig; export type ContractCaseJestVerifierConfig = ContractCaseVerifierConfig; diff --git a/packages/contract-case-jest/src/index.function.caller.define.spec.ts b/packages/contract-case-dsl-js-jest/src/index.function.caller.define.spec.ts similarity index 100% rename from packages/contract-case-jest/src/index.function.caller.define.spec.ts rename to packages/contract-case-dsl-js-jest/src/index.function.caller.define.spec.ts diff --git a/packages/contract-case-jest/src/index.function.caller.spec.verify.ts b/packages/contract-case-dsl-js-jest/src/index.function.caller.spec.verify.ts similarity index 100% rename from packages/contract-case-jest/src/index.function.caller.spec.verify.ts rename to packages/contract-case-dsl-js-jest/src/index.function.caller.spec.verify.ts diff --git a/packages/contract-case-jest/src/index.function.implementer.define.spec.ts b/packages/contract-case-dsl-js-jest/src/index.function.implementer.define.spec.ts similarity index 100% rename from packages/contract-case-jest/src/index.function.implementer.define.spec.ts rename to packages/contract-case-dsl-js-jest/src/index.function.implementer.define.spec.ts diff --git a/packages/contract-case-jest/src/index.function.implementer.spec.verify.ts b/packages/contract-case-dsl-js-jest/src/index.function.implementer.spec.verify.ts similarity index 90% rename from packages/contract-case-jest/src/index.function.implementer.spec.verify.ts rename to packages/contract-case-dsl-js-jest/src/index.function.implementer.spec.verify.ts index 3524e7bd3..0ad91da83 100644 --- a/packages/contract-case-jest/src/index.function.implementer.spec.verify.ts +++ b/packages/contract-case-dsl-js-jest/src/index.function.implementer.spec.verify.ts @@ -1,6 +1,5 @@ import { verifyContract } from './boundaries/jest/jest.js'; -import { TriggerGroupMap } from './connectors/TriggerGroup.js'; -import { FunctionExecutorConfig } from './index.js'; +import { TriggerGroupMap, FunctionExecutorConfig } from './index.js'; describe('verification', () => { verifyContract({ diff --git a/packages/contract-case-jest/src/index.grpc.client.define.spec.ts b/packages/contract-case-dsl-js-jest/src/index.grpc.client.define.spec.ts similarity index 100% rename from packages/contract-case-jest/src/index.grpc.client.define.spec.ts rename to packages/contract-case-dsl-js-jest/src/index.grpc.client.define.spec.ts diff --git a/packages/contract-case-jest/src/index.http.client.base.spec.verify.ts b/packages/contract-case-dsl-js-jest/src/index.http.client.base.spec.verify.ts similarity index 97% rename from packages/contract-case-jest/src/index.http.client.base.spec.verify.ts rename to packages/contract-case-dsl-js-jest/src/index.http.client.base.spec.verify.ts index 38a4a0df6..d6029446e 100644 --- a/packages/contract-case-jest/src/index.http.client.base.spec.verify.ts +++ b/packages/contract-case-dsl-js-jest/src/index.http.client.base.spec.verify.ts @@ -5,7 +5,7 @@ import { baseService } from './__tests__/server/domain/baseService.js'; import { Dependencies } from './__tests__/server/domain/types.js'; import { User } from './__tests__/server/entities/responses.js'; import { verifyContract } from './boundaries/jest/jest.js'; -import { StateHandlers } from './entities/types.js'; +import { StateHandlers } from './index.js'; describe('Server verification but with base config', () => { // This test is like the non base one, but with state handlers diff --git a/packages/contract-case-jest/src/index.http.client.define.spec.ts b/packages/contract-case-dsl-js-jest/src/index.http.client.define.spec.ts similarity index 100% rename from packages/contract-case-jest/src/index.http.client.define.spec.ts rename to packages/contract-case-dsl-js-jest/src/index.http.client.define.spec.ts diff --git a/packages/contract-case-jest/src/index.http.client.spec.verify.ts b/packages/contract-case-dsl-js-jest/src/index.http.client.spec.verify.ts similarity index 97% rename from packages/contract-case-jest/src/index.http.client.spec.verify.ts rename to packages/contract-case-dsl-js-jest/src/index.http.client.spec.verify.ts index ac2e9e8b1..9c0c27b77 100644 --- a/packages/contract-case-jest/src/index.http.client.spec.verify.ts +++ b/packages/contract-case-dsl-js-jest/src/index.http.client.spec.verify.ts @@ -5,7 +5,7 @@ import { baseService } from './__tests__/server/domain/baseService.js'; import { Dependencies } from './__tests__/server/domain/types.js'; import { User } from './__tests__/server/entities/responses.js'; import { verifyContract } from './boundaries/jest/jest.js'; -import { StateHandlers } from './entities/types.js'; +import { StateHandlers } from './index.js'; describe('Server verification', () => { // SERVER SETUP BOILERPLATE diff --git a/packages/contract-case-jest/src/index.http.server.define.spec.ts b/packages/contract-case-dsl-js-jest/src/index.http.server.define.spec.ts similarity index 100% rename from packages/contract-case-jest/src/index.http.server.define.spec.ts rename to packages/contract-case-dsl-js-jest/src/index.http.server.define.spec.ts diff --git a/packages/contract-case-jest/src/index.http.server.spec.verify.ts b/packages/contract-case-dsl-js-jest/src/index.http.server.spec.verify.ts similarity index 97% rename from packages/contract-case-jest/src/index.http.server.spec.verify.ts rename to packages/contract-case-dsl-js-jest/src/index.http.server.spec.verify.ts index 33215606c..2304eb156 100644 --- a/packages/contract-case-jest/src/index.http.server.spec.verify.ts +++ b/packages/contract-case-dsl-js-jest/src/index.http.server.spec.verify.ts @@ -2,8 +2,7 @@ import api from './__tests__/client/http.js'; import { UserNotFoundConsumerError } from './__tests__/client/entities/errors.js'; import { ApiError } from './__tests__/client/entities/apiErrors.js'; -import { verifyContract, HttpRequestConfig } from './index.js'; -import { TriggerGroupMap } from './connectors/TriggerGroup.js'; +import { verifyContract, HttpRequestConfig, TriggerGroupMap } from './index.js'; verifyContract({ providerName: 'http request provider', diff --git a/packages/contract-case-jest/src/index.no.interactions.define.spec.ts b/packages/contract-case-dsl-js-jest/src/index.no.interactions.define.spec.ts similarity index 100% rename from packages/contract-case-jest/src/index.no.interactions.define.spec.ts rename to packages/contract-case-dsl-js-jest/src/index.no.interactions.define.spec.ts diff --git a/packages/contract-case-jest/src/index.ts b/packages/contract-case-dsl-js-jest/src/index.ts similarity index 54% rename from packages/contract-case-jest/src/index.ts rename to packages/contract-case-dsl-js-jest/src/index.ts index 55659e50f..4d7ded78b 100644 --- a/packages/contract-case-jest/src/index.ts +++ b/packages/contract-case-dsl-js-jest/src/index.ts @@ -1,4 +1,4 @@ -import { InteractionSetup } from './entities/index.js'; +import type { InteractionSetup } from '@contract-case/contract-case-dsl-js'; /*! * ContractCase Jest DSL @@ -6,11 +6,15 @@ import { InteractionSetup } from './entities/index.js'; * BSD-3-Clause license */ -export { ContractCaseDefiner } from './connectors/ContractDefiner.js'; +// Re-export all shared DSL code +export * from '@contract-case/contract-case-dsl-js'; + +// Re-export jest-specific bindings export * from './boundaries/index.js'; -export * as dsl from './boundaries/dsl/index.js'; -export * as TestEquivalenceMatchers from './boundaries/dsl/Matchers/index.js'; -export * from './entities/types.js'; + +// Namespace re-exports for backward compatibility +export * as dsl from '@contract-case/contract-case-dsl-js'; +export * as TestEquivalenceMatchers from '@contract-case/contract-case-dsl-js'; process.env['CASE_CONNECTOR_CLIENT'] = 'contract-case-jest'; diff --git a/packages/contract-case-jest/src/internals.spec-dont-run.ts b/packages/contract-case-dsl-js-jest/src/internals.spec-dont-run.ts similarity index 100% rename from packages/contract-case-jest/src/internals.spec-dont-run.ts rename to packages/contract-case-dsl-js-jest/src/internals.spec-dont-run.ts diff --git a/packages/contract-case-jest/tsconfig.build.json b/packages/contract-case-dsl-js-jest/tsconfig.build.json similarity index 100% rename from packages/contract-case-jest/tsconfig.build.json rename to packages/contract-case-dsl-js-jest/tsconfig.build.json diff --git a/packages/contract-case-jest/tsconfig.json b/packages/contract-case-dsl-js-jest/tsconfig.json similarity index 100% rename from packages/contract-case-jest/tsconfig.json rename to packages/contract-case-dsl-js-jest/tsconfig.json diff --git a/packages/contract-case-dsl-js-vitest/case-contracts/function-definer/function-execution-c44cdd64be41f16b7493b8a0cc1b54353b1f0b7fc89cd5c61d02e1bbf04b53e5.case.json b/packages/contract-case-dsl-js-vitest/case-contracts/function-definer/function-execution-c44cdd64be41f16b7493b8a0cc1b54353b1f0b7fc89cd5c61d02e1bbf04b53e5.case.json new file mode 100644 index 000000000..3db0b1790 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/case-contracts/function-definer/function-execution-c44cdd64be41f16b7493b8a0cc1b54353b1f0b7fc89cd5c61d02e1bbf04b53e5.case.json @@ -0,0 +1,111 @@ +{ + "contractType": "case::contract", + "description": { + "consumerName": "function execution", + "providerName": "function definer" + }, + "metadata": { + "_case": { + "version": "case-internal-tests", + "hash": "c44cdd64be41f16b7493b8a0cc1b54353b1f0b7fc89cd5c61d02e1bbf04b53e5" + } + }, + "matcherLookup": { + "matcher:An invocation of NO ARG FUNCTION()": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [] + }, + "matcher:returns null": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": null + }, + "matcher:An invocation of HAS ARGS FUNCTION( \"example\", 2 )": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [ + "example", + 2 + ] + }, + "matcher:returns \"example2\"": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": "example2" + } + }, + "examples": [ + { + "states": [], + "mock": { + "_case:mock:type": "_case:MockFunctionCaller", + "_case:run:context:setup": { + "read": { + "type": "_case:MockFunctionExecution", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockFunctionCaller", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "An invocation of NO ARG FUNCTION()", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [] + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns null", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": null + } + }, + "functionName": "NO ARG FUNCTION" + }, + "result": "VERIFIED" + }, + { + "states": [], + "mock": { + "_case:mock:type": "_case:MockFunctionCaller", + "_case:run:context:setup": { + "read": { + "type": "_case:MockFunctionExecution", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockFunctionCaller", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "An invocation of HAS ARGS FUNCTION( \"example\", 2 )", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [ + "example", + 2 + ] + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns \"example2\"", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": "example2" + } + }, + "functionName": "HAS ARGS FUNCTION" + }, + "result": "VERIFIED" + } + ] +} \ No newline at end of file diff --git a/packages/contract-case-dsl-js-vitest/case-contracts/function-definer/function-execution-main.case.json b/packages/contract-case-dsl-js-vitest/case-contracts/function-definer/function-execution-main.case.json new file mode 100644 index 000000000..3db0b1790 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/case-contracts/function-definer/function-execution-main.case.json @@ -0,0 +1,111 @@ +{ + "contractType": "case::contract", + "description": { + "consumerName": "function execution", + "providerName": "function definer" + }, + "metadata": { + "_case": { + "version": "case-internal-tests", + "hash": "c44cdd64be41f16b7493b8a0cc1b54353b1f0b7fc89cd5c61d02e1bbf04b53e5" + } + }, + "matcherLookup": { + "matcher:An invocation of NO ARG FUNCTION()": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [] + }, + "matcher:returns null": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": null + }, + "matcher:An invocation of HAS ARGS FUNCTION( \"example\", 2 )": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [ + "example", + 2 + ] + }, + "matcher:returns \"example2\"": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": "example2" + } + }, + "examples": [ + { + "states": [], + "mock": { + "_case:mock:type": "_case:MockFunctionCaller", + "_case:run:context:setup": { + "read": { + "type": "_case:MockFunctionExecution", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockFunctionCaller", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "An invocation of NO ARG FUNCTION()", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [] + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns null", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": null + } + }, + "functionName": "NO ARG FUNCTION" + }, + "result": "VERIFIED" + }, + { + "states": [], + "mock": { + "_case:mock:type": "_case:MockFunctionCaller", + "_case:run:context:setup": { + "read": { + "type": "_case:MockFunctionExecution", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockFunctionCaller", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "An invocation of HAS ARGS FUNCTION( \"example\", 2 )", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [ + "example", + 2 + ] + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns \"example2\"", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": "example2" + } + }, + "functionName": "HAS ARGS FUNCTION" + }, + "result": "VERIFIED" + } + ] +} \ No newline at end of file diff --git a/packages/contract-case-dsl-js-vitest/case-contracts/function-execution/function-caller-bcac4a1c1076fb91328174d3918337af1b4d3722b34773eea9a358900c387530.case.json b/packages/contract-case-dsl-js-vitest/case-contracts/function-execution/function-caller-bcac4a1c1076fb91328174d3918337af1b4d3722b34773eea9a358900c387530.case.json new file mode 100644 index 000000000..ab20db017 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/case-contracts/function-execution/function-caller-bcac4a1c1076fb91328174d3918337af1b4d3722b34773eea9a358900c387530.case.json @@ -0,0 +1,111 @@ +{ + "contractType": "case::contract", + "description": { + "consumerName": "function caller", + "providerName": "function execution" + }, + "metadata": { + "_case": { + "version": "case-internal-tests", + "hash": "bcac4a1c1076fb91328174d3918337af1b4d3722b34773eea9a358900c387530" + } + }, + "matcherLookup": { + "matcher:returns null": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": null + }, + "matcher:An invocation of zeroArgs()": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [] + }, + "matcher:returns \"example2\"": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": "example2" + }, + "matcher:An invocation of concatenate( \"example\", 2 )": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [ + "example", + 2 + ] + } + }, + "examples": [ + { + "states": [], + "mock": { + "_case:mock:type": "_case:MockFunctionExecution", + "_case:run:context:setup": { + "read": { + "type": "_case:MockFunctionCaller", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockFunctionExecution", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "An invocation of zeroArgs()", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [] + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns null", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": null + } + }, + "functionName": "zeroArgs" + }, + "result": "VERIFIED" + }, + { + "states": [], + "mock": { + "_case:mock:type": "_case:MockFunctionExecution", + "_case:run:context:setup": { + "read": { + "type": "_case:MockFunctionCaller", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockFunctionExecution", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "An invocation of concatenate( \"example\", 2 )", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [ + "example", + 2 + ] + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns \"example2\"", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": "example2" + } + }, + "functionName": "concatenate" + }, + "result": "VERIFIED" + } + ] +} \ No newline at end of file diff --git a/packages/contract-case-dsl-js-vitest/case-contracts/function-execution/function-caller-main.case.json b/packages/contract-case-dsl-js-vitest/case-contracts/function-execution/function-caller-main.case.json new file mode 100644 index 000000000..ab20db017 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/case-contracts/function-execution/function-caller-main.case.json @@ -0,0 +1,111 @@ +{ + "contractType": "case::contract", + "description": { + "consumerName": "function caller", + "providerName": "function execution" + }, + "metadata": { + "_case": { + "version": "case-internal-tests", + "hash": "bcac4a1c1076fb91328174d3918337af1b4d3722b34773eea9a358900c387530" + } + }, + "matcherLookup": { + "matcher:returns null": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": null + }, + "matcher:An invocation of zeroArgs()": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [] + }, + "matcher:returns \"example2\"": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": "example2" + }, + "matcher:An invocation of concatenate( \"example\", 2 )": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [ + "example", + 2 + ] + } + }, + "examples": [ + { + "states": [], + "mock": { + "_case:mock:type": "_case:MockFunctionExecution", + "_case:run:context:setup": { + "read": { + "type": "_case:MockFunctionCaller", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockFunctionExecution", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "An invocation of zeroArgs()", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [] + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns null", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": null + } + }, + "functionName": "zeroArgs" + }, + "result": "VERIFIED" + }, + { + "states": [], + "mock": { + "_case:mock:type": "_case:MockFunctionExecution", + "_case:run:context:setup": { + "read": { + "type": "_case:MockFunctionCaller", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockFunctionExecution", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "An invocation of concatenate( \"example\", 2 )", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionArgumentsMatcher", + "arguments": [ + "example", + 2 + ] + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns \"example2\"", + "_case:matcher:child": { + "_case:matcher:type": "_case:FunctionResultMatcher", + "success": "example2" + } + }, + "functionName": "concatenate" + }, + "result": "VERIFIED" + } + ] +} \ No newline at end of file diff --git a/packages/contract-case-dsl-js-vitest/case-contracts/http-request-provider/http-request-consumer-47cbaddd42bc03fb9ac1297a63b5ca7dd8009c5d5293a1e6f3ddcc73e29597f3.case.json b/packages/contract-case-dsl-js-vitest/case-contracts/http-request-provider/http-request-consumer-47cbaddd42bc03fb9ac1297a63b5ca7dd8009c5d5293a1e6f3ddcc73e29597f3.case.json new file mode 100644 index 000000000..ff3fe6ade --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/case-contracts/http-request-provider/http-request-consumer-47cbaddd42bc03fb9ac1297a63b5ca7dd8009c5d5293a1e6f3ddcc73e29597f3.case.json @@ -0,0 +1,584 @@ +{ + "contractType": "case::contract", + "description": { + "consumerName": "http request consumer", + "providerName": "http request provider" + }, + "metadata": { + "_case": { + "version": "case-internal-tests", + "hash": "47cbaddd42bc03fb9ac1297a63b5ca7dd8009c5d5293a1e6f3ddcc73e29597f3" + } + }, + "matcherLookup": { + "matcher:an http \"GET\" request to \"/health\" with the following headers an object shaped like {accept: \"application/json\"} without a body": { + "method": "GET", + "path": "/health", + "headers": { + "accept": "application/json" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "matcher:returns a (200) response with body an object shaped like {status: \"up\"}": { + "status": 200, + "body": { + "status": "up" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:an http \"GET\" request to \"/health\" without a body": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "matcher:returns a (200) response with body an object shaped like {status: }": { + "status": 200, + "body": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "status": "whatever" + }, + "_case:context:matchBy": "type" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:returns a (httpStatus 4XX | 5XX) response without a body": { + "status": { + "_case:matcher:type": "_case:HttpStatusCode", + "_case:matcher:example": 400, + "_case:matcher:rule": [ + "4XX", + "5XX" + ], + "_case:matcher:resolvesTo": "HttpStatusCode" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:returns a (503) response with body an object shaped like {status: \"down\"}": { + "status": 503, + "body": { + "status": "down" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "variable:default:userId::test[4]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + }, + "matcher:an http \"GET\" request to \"/users\"?id={{userId}} without a body": { + "method": "GET", + "path": "/users", + "query": { + "id": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "matcher:returns a (200) response with body an object shaped like {userId: {{userId}}}": { + "status": 200, + "body": { + "userId": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "variable:default:userId::test[5]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + }, + "matcher:returns a (404) response without a body": { + "status": 404, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "variable:default:userId::test[6]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + }, + "matcher:an http \"GET\" request to \"/users/{{userId}}\" without a body": { + "method": "GET", + "path": { + "_case:matcher:type": "_case:StringPrefix", + "_case:matcher:prefix": "/users/", + "_case:matcher:suffix": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + }, + "_case:matcher:resolvesTo": "string" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "variable:default:userId::test[7]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + }, + "matcher:an http \"GET\" request to \"/users/123\" without a body": { + "method": "GET", + "path": { + "_case:matcher:type": "_case:StringPrefix", + "_case:matcher:prefix": "/users/", + "_case:matcher:suffix": "123", + "_case:matcher:resolvesTo": "string" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "examples": [ + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" with the following headers an object shaped like {accept: \"application/json\"} without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "headers": { + "accept": "application/json" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {status: \"up\"}", + "_case:matcher:child": { + "status": 200, + "body": { + "status": "up" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {status: }", + "_case:matcher:child": { + "status": 200, + "body": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "status": "whatever" + }, + "_case:context:matchBy": "type" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is down" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (httpStatus 4XX | 5XX) response without a body", + "_case:matcher:child": { + "status": { + "_case:matcher:type": "_case:HttpStatusCode", + "_case:matcher:example": 400, + "_case:matcher:rule": [ + "4XX", + "5XX" + ], + "_case:matcher:resolvesTo": "HttpStatusCode" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is down" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (503) response with body an object shaped like {status: \"down\"}", + "_case:matcher:child": { + "status": 503, + "body": { + "status": "down" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "A user exists", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users\"?id={{userId}} without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/users", + "query": { + "id": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {userId: {{userId}}}", + "_case:matcher:child": { + "status": 200, + "body": { + "userId": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "No users exist", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users\"?id={{userId}} without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/users", + "query": { + "id": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (404) response without a body", + "_case:matcher:child": { + "status": 404, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "A user exists", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users/{{userId}}\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": { + "_case:matcher:type": "_case:StringPrefix", + "_case:matcher:prefix": "/users/", + "_case:matcher:suffix": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + }, + "_case:matcher:resolvesTo": "string" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {userId: {{userId}}}", + "_case:matcher:child": { + "status": 200, + "body": { + "userId": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "No users exist", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users/123\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": { + "_case:matcher:type": "_case:StringPrefix", + "_case:matcher:prefix": "/users/", + "_case:matcher:suffix": "123", + "_case:matcher:resolvesTo": "string" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (404) response without a body", + "_case:matcher:child": { + "status": 404, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + } + ] +} \ No newline at end of file diff --git a/packages/contract-case-dsl-js-vitest/case-contracts/http-request-provider/http-request-consumer-main.case.json b/packages/contract-case-dsl-js-vitest/case-contracts/http-request-provider/http-request-consumer-main.case.json new file mode 100644 index 000000000..ff3fe6ade --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/case-contracts/http-request-provider/http-request-consumer-main.case.json @@ -0,0 +1,584 @@ +{ + "contractType": "case::contract", + "description": { + "consumerName": "http request consumer", + "providerName": "http request provider" + }, + "metadata": { + "_case": { + "version": "case-internal-tests", + "hash": "47cbaddd42bc03fb9ac1297a63b5ca7dd8009c5d5293a1e6f3ddcc73e29597f3" + } + }, + "matcherLookup": { + "matcher:an http \"GET\" request to \"/health\" with the following headers an object shaped like {accept: \"application/json\"} without a body": { + "method": "GET", + "path": "/health", + "headers": { + "accept": "application/json" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "matcher:returns a (200) response with body an object shaped like {status: \"up\"}": { + "status": 200, + "body": { + "status": "up" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:an http \"GET\" request to \"/health\" without a body": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "matcher:returns a (200) response with body an object shaped like {status: }": { + "status": 200, + "body": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "status": "whatever" + }, + "_case:context:matchBy": "type" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:returns a (httpStatus 4XX | 5XX) response without a body": { + "status": { + "_case:matcher:type": "_case:HttpStatusCode", + "_case:matcher:example": 400, + "_case:matcher:rule": [ + "4XX", + "5XX" + ], + "_case:matcher:resolvesTo": "HttpStatusCode" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:returns a (503) response with body an object shaped like {status: \"down\"}": { + "status": 503, + "body": { + "status": "down" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "variable:default:userId::test[4]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + }, + "matcher:an http \"GET\" request to \"/users\"?id={{userId}} without a body": { + "method": "GET", + "path": "/users", + "query": { + "id": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "matcher:returns a (200) response with body an object shaped like {userId: {{userId}}}": { + "status": 200, + "body": { + "userId": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "variable:default:userId::test[5]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + }, + "matcher:returns a (404) response without a body": { + "status": 404, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "variable:default:userId::test[6]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + }, + "matcher:an http \"GET\" request to \"/users/{{userId}}\" without a body": { + "method": "GET", + "path": { + "_case:matcher:type": "_case:StringPrefix", + "_case:matcher:prefix": "/users/", + "_case:matcher:suffix": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + }, + "_case:matcher:resolvesTo": "string" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "variable:default:userId::test[7]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + }, + "matcher:an http \"GET\" request to \"/users/123\" without a body": { + "method": "GET", + "path": { + "_case:matcher:type": "_case:StringPrefix", + "_case:matcher:prefix": "/users/", + "_case:matcher:suffix": "123", + "_case:matcher:resolvesTo": "string" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "examples": [ + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" with the following headers an object shaped like {accept: \"application/json\"} without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "headers": { + "accept": "application/json" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {status: \"up\"}", + "_case:matcher:child": { + "status": 200, + "body": { + "status": "up" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {status: }", + "_case:matcher:child": { + "status": 200, + "body": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "status": "whatever" + }, + "_case:context:matchBy": "type" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is down" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (httpStatus 4XX | 5XX) response without a body", + "_case:matcher:child": { + "status": { + "_case:matcher:type": "_case:HttpStatusCode", + "_case:matcher:example": 400, + "_case:matcher:rule": [ + "4XX", + "5XX" + ], + "_case:matcher:resolvesTo": "HttpStatusCode" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is down" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (503) response with body an object shaped like {status: \"down\"}", + "_case:matcher:child": { + "status": 503, + "body": { + "status": "down" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "A user exists", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users\"?id={{userId}} without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/users", + "query": { + "id": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {userId: {{userId}}}", + "_case:matcher:child": { + "status": 200, + "body": { + "userId": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "No users exist", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users\"?id={{userId}} without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/users", + "query": { + "id": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (404) response without a body", + "_case:matcher:child": { + "status": 404, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "A user exists", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users/{{userId}}\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": { + "_case:matcher:type": "_case:StringPrefix", + "_case:matcher:prefix": "/users/", + "_case:matcher:suffix": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + }, + "_case:matcher:resolvesTo": "string" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {userId: {{userId}}}", + "_case:matcher:child": { + "status": 200, + "body": { + "userId": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "No users exist", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + }, + "write": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users/123\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": { + "_case:matcher:type": "_case:StringPrefix", + "_case:matcher:prefix": "/users/", + "_case:matcher:suffix": "123", + "_case:matcher:resolvesTo": "string" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (404) response without a body", + "_case:matcher:child": { + "status": 404, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + } + ] +} \ No newline at end of file diff --git a/packages/contract-case-dsl-js-vitest/case-contracts/http-response-provider/http-response-consumer-74d8aa637e1f5f672b583ba38c86060aa9330e96b5181e17095073afce265011.case.json b/packages/contract-case-dsl-js-vitest/case-contracts/http-response-provider/http-response-consumer-74d8aa637e1f5f672b583ba38c86060aa9330e96b5181e17095073afce265011.case.json new file mode 100644 index 000000000..a7d30d6dc --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/case-contracts/http-response-provider/http-response-consumer-74d8aa637e1f5f672b583ba38c86060aa9330e96b5181e17095073afce265011.case.json @@ -0,0 +1,599 @@ +{ + "contractType": "case::contract", + "description": { + "consumerName": "http response consumer", + "providerName": "http response provider" + }, + "metadata": { + "_case": { + "version": "case-internal-tests", + "hash": "74d8aa637e1f5f672b583ba38c86060aa9330e96b5181e17095073afce265011" + } + }, + "matcherLookup": { + "matcher:returns a (200) response with body an object shaped like {status: \"up\"}": { + "status": 200, + "body": { + "status": "up" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:an http \"GET\" request to \"/health\" with the following headers an object shaped like {accept: \"application/json\"} without a body": { + "method": "GET", + "path": "/health", + "headers": { + "accept": "application/json" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "matcher:returns a (200) response with body an object shaped like {status: }": { + "status": 200, + "body": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "status": "whatever" + }, + "_case:context:matchBy": "type" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:an http \"GET\" request to \"/health\" without a body": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "matcher:returns a (httpStatus 4XX | 5XX) response without a body": { + "status": { + "_case:matcher:type": "_case:HttpStatusCode", + "_case:matcher:example": 400, + "_case:matcher:rule": [ + "4XX", + "5XX" + ], + "_case:matcher:resolvesTo": "HttpStatusCode" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:returns a (503) response with body an object shaped like {status: \"down\"}": { + "status": 503, + "body": { + "status": "down" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "variable:default:userId::test[4]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + }, + "matcher:returns a (200) response with body an object shaped like {userId: {{userId}}}": { + "status": 200, + "body": { + "userId": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:an http \"GET\" request to \"/users\"?id={{userId}} without a body": { + "method": "GET", + "path": "/users", + "query": { + "id": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "variable:default:userId::test[5]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + }, + "matcher:returns a (404) response without a body": { + "status": 404, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "variable:default:userId::test[6]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + }, + "matcher:returns a (200) response with body an object shaped like {userId: {{userId}},name: }": { + "status": 200, + "body": { + "userId": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + }, + "name": { + "_case:matcher:type": "_case:MatchString", + "_case:matcher:example": "john smith", + "_case:matcher:resolvesTo": "string", + "_case:context:matchBy": "type" + } + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:an http \"GET\" request to \"/users/{{userId}}\" without a body": { + "method": "GET", + "path": { + "_case:matcher:type": "_case:StringPrefix", + "_case:matcher:prefix": "/users/", + "_case:matcher:suffix": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + }, + "_case:matcher:resolvesTo": "string" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "variable:default:userId::test[7]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + } + }, + "examples": [ + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" with the following headers an object shaped like {accept: \"application/json\"} without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "headers": { + "accept": "application/json" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {status: \"up\"}", + "_case:matcher:child": { + "status": 200, + "body": { + "status": "up" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {status: }", + "_case:matcher:child": { + "status": 200, + "body": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "status": "whatever" + }, + "_case:context:matchBy": "type" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is down" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (httpStatus 4XX | 5XX) response without a body", + "_case:matcher:child": { + "status": { + "_case:matcher:type": "_case:HttpStatusCode", + "_case:matcher:example": 400, + "_case:matcher:rule": [ + "4XX", + "5XX" + ], + "_case:matcher:resolvesTo": "HttpStatusCode" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is down" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (503) response with body an object shaped like {status: \"down\"}", + "_case:matcher:child": { + "status": 503, + "body": { + "status": "down" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "A user exists", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users\"?id={{userId}} without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/users", + "query": { + "id": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {userId: {{userId}}}", + "_case:matcher:child": { + "status": 200, + "body": { + "userId": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "No users exist", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users\"?id={{userId}} without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/users", + "query": { + "id": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (404) response without a body", + "_case:matcher:child": { + "status": 404, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "A user exists", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users/{{userId}}\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": { + "_case:matcher:type": "_case:StringPrefix", + "_case:matcher:prefix": "/users/", + "_case:matcher:suffix": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + }, + "_case:matcher:resolvesTo": "string" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {userId: {{userId}},name: }", + "_case:matcher:child": { + "status": 200, + "body": { + "userId": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + }, + "name": { + "_case:matcher:type": "_case:MatchString", + "_case:matcher:example": "john smith", + "_case:matcher:resolvesTo": "string", + "_case:context:matchBy": "type" + } + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "No users exist", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users/{{userId}}\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": { + "_case:matcher:type": "_case:StringPrefix", + "_case:matcher:prefix": "/users/", + "_case:matcher:suffix": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + }, + "_case:matcher:resolvesTo": "string" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (404) response without a body", + "_case:matcher:child": { + "status": 404, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + } + ] +} \ No newline at end of file diff --git a/packages/contract-case-dsl-js-vitest/case-contracts/http-response-provider/http-response-consumer-main.case.json b/packages/contract-case-dsl-js-vitest/case-contracts/http-response-provider/http-response-consumer-main.case.json new file mode 100644 index 000000000..a7d30d6dc --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/case-contracts/http-response-provider/http-response-consumer-main.case.json @@ -0,0 +1,599 @@ +{ + "contractType": "case::contract", + "description": { + "consumerName": "http response consumer", + "providerName": "http response provider" + }, + "metadata": { + "_case": { + "version": "case-internal-tests", + "hash": "74d8aa637e1f5f672b583ba38c86060aa9330e96b5181e17095073afce265011" + } + }, + "matcherLookup": { + "matcher:returns a (200) response with body an object shaped like {status: \"up\"}": { + "status": 200, + "body": { + "status": "up" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:an http \"GET\" request to \"/health\" with the following headers an object shaped like {accept: \"application/json\"} without a body": { + "method": "GET", + "path": "/health", + "headers": { + "accept": "application/json" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "matcher:returns a (200) response with body an object shaped like {status: }": { + "status": 200, + "body": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "status": "whatever" + }, + "_case:context:matchBy": "type" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:an http \"GET\" request to \"/health\" without a body": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "matcher:returns a (httpStatus 4XX | 5XX) response without a body": { + "status": { + "_case:matcher:type": "_case:HttpStatusCode", + "_case:matcher:example": 400, + "_case:matcher:rule": [ + "4XX", + "5XX" + ], + "_case:matcher:resolvesTo": "HttpStatusCode" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:returns a (503) response with body an object shaped like {status: \"down\"}": { + "status": 503, + "body": { + "status": "down" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "variable:default:userId::test[4]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + }, + "matcher:returns a (200) response with body an object shaped like {userId: {{userId}}}": { + "status": 200, + "body": { + "userId": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:an http \"GET\" request to \"/users\"?id={{userId}} without a body": { + "method": "GET", + "path": "/users", + "query": { + "id": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "variable:default:userId::test[5]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + }, + "matcher:returns a (404) response without a body": { + "status": 404, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "variable:default:userId::test[6]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + }, + "matcher:returns a (200) response with body an object shaped like {userId: {{userId}},name: }": { + "status": 200, + "body": { + "userId": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + }, + "name": { + "_case:matcher:type": "_case:MatchString", + "_case:matcher:example": "john smith", + "_case:matcher:resolvesTo": "string", + "_case:context:matchBy": "type" + } + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + }, + "matcher:an http \"GET\" request to \"/users/{{userId}}\" without a body": { + "method": "GET", + "path": { + "_case:matcher:type": "_case:StringPrefix", + "_case:matcher:prefix": "/users/", + "_case:matcher:suffix": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + }, + "_case:matcher:resolvesTo": "string" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + }, + "variable:default:userId::test[7]": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + }, + "_case:context:matchBy": "type" + } + }, + "examples": [ + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" with the following headers an object shaped like {accept: \"application/json\"} without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "headers": { + "accept": "application/json" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {status: \"up\"}", + "_case:matcher:child": { + "status": 200, + "body": { + "status": "up" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {status: }", + "_case:matcher:child": { + "status": 200, + "body": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": { + "status": "whatever" + }, + "_case:context:matchBy": "type" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is down" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (httpStatus 4XX | 5XX) response without a body", + "_case:matcher:child": { + "status": { + "_case:matcher:type": "_case:HttpStatusCode", + "_case:matcher:example": 400, + "_case:matcher:rule": [ + "4XX", + "5XX" + ], + "_case:matcher:resolvesTo": "HttpStatusCode" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is down" + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/health\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/health", + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (503) response with body an object shaped like {status: \"down\"}", + "_case:matcher:child": { + "status": 503, + "body": { + "status": "down" + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "A user exists", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users\"?id={{userId}} without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/users", + "query": { + "id": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {userId: {{userId}}}", + "_case:matcher:child": { + "status": 200, + "body": { + "userId": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "No users exist", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users\"?id={{userId}} without a body", + "_case:matcher:child": { + "method": "GET", + "path": "/users", + "query": { + "id": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + } + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (404) response without a body", + "_case:matcher:child": { + "status": 404, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "A user exists", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users/{{userId}}\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": { + "_case:matcher:type": "_case:StringPrefix", + "_case:matcher:prefix": "/users/", + "_case:matcher:suffix": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + }, + "_case:matcher:resolvesTo": "string" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (200) response with body an object shaped like {userId: {{userId}},name: }", + "_case:matcher:child": { + "status": 200, + "body": { + "userId": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + }, + "name": { + "_case:matcher:type": "_case:MatchString", + "_case:matcher:example": "john smith", + "_case:matcher:resolvesTo": "string", + "_case:context:matchBy": "type" + } + }, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + }, + { + "states": [ + { + "_case:state:type": "_case:NamedState", + "stateName": "Server is up" + }, + { + "_case:state:type": "_case:StateWithVariables", + "stateName": "No users exist", + "variables": { + "userId": { + "_case:matcher:type": "_case:CascadingContext", + "_case:matcher:child": "123", + "_case:context:matchBy": "type" + } + } + } + ], + "mock": { + "_case:mock:type": "_case:MockHttpClient", + "_case:run:context:setup": { + "read": { + "type": "_case:MockHttpClient", + "stateVariables": "state", + "triggers": "generated" + }, + "write": { + "type": "_case:MockHttpServer", + "stateVariables": "default", + "triggers": "provided" + } + }, + "request": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "an http \"GET\" request to \"/users/{{userId}}\" without a body", + "_case:matcher:child": { + "method": "GET", + "path": { + "_case:matcher:type": "_case:StringPrefix", + "_case:matcher:prefix": "/users/", + "_case:matcher:suffix": { + "_case:matcher:type": "_case:ContextVariable", + "_case:matcher:variableName": "userId" + }, + "_case:matcher:resolvesTo": "string" + }, + "_case:matcher:type": "_case:HttpRequestMatcher" + } + }, + "response": { + "_case:matcher:type": "_case:Lookup", + "_case:matcher:uniqueName": "returns a (404) response without a body", + "_case:matcher:child": { + "status": 404, + "_case:matcher:type": "_case:HttpResponseMatcher" + } + } + }, + "result": "VERIFIED" + } + ] +} \ No newline at end of file diff --git a/packages/contract-case-dsl-js-vitest/eslint.config.mjs b/packages/contract-case-dsl-js-vitest/eslint.config.mjs new file mode 100644 index 000000000..83c0f6f37 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/eslint.config.mjs @@ -0,0 +1,3 @@ +import lintConfig from '@contract-case/eslint-config-case-maintainer'; + +export default [...lintConfig]; diff --git a/packages/contract-case-dsl-js-vitest/package.json b/packages/contract-case-dsl-js-vitest/package.json new file mode 100644 index 000000000..f3cf95745 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/package.json @@ -0,0 +1,77 @@ +{ + "name": "@contract-case/contract-case-dsl-js-vitest", + "version": "0.29.1", + "description": "ContractCase contract testing suite for Vitest", + "keywords": [ + "testing", + "api", + "pact", + "contracttesting", + "contract-testing", + "contractcase", + "vitest" + ], + "author": "Timothy Jones (https://github.com/TimothyJones)", + "homepage": "https://case.contract-testing.io", + "license": "BSD-3-Clause", + "main": "./dist/src/index.js", + "types": "./dist/src/index.d.ts", + "directories": { + "src": "src", + "dist": "dist" + }, + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/case-contract-testing/case.git" + }, + "scripts": { + "build": "rimraf dist && tsc --project tsconfig.build.json", + "lint": "eslint", + "lint:fix": "eslint --fix", + "format:base": "prettier --parser typescript \"src/**/*.ts\"", + "format:check": "npm run format:base -- --list-different", + "format:fix": "npm run format:base -- --write ", + "test": "cross-env CASE_MAINTAINER_TESTING_VERSION_OVERRIDE=true vitest run", + "test:local": "cross-env CASE_MAINTAINER_TESTING_VERSION_OVERRIDE=true CASE_publish=false vitest run" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/TimothyJones" + }, + "engines": { + "node": ">=14.21.2" + }, + "bugs": { + "url": "https://github.com/case-contract-testing/case/issues" + }, + "devDependencies": { + "@contract-case/eslint-config-case-maintainer": "0.29.1", + "@grpc/grpc-js": "^1.13.3", + "@grpc/proto-loader": "^0.8.0", + "@types/body-parser": "^1.19.2", + "@types/express": "^4.17.14", + "axios": "^1.13.5", + "body-parser": "^2.2.0", + "cross-env": "^10.1.0", + "eslint": "^9.39.1", + "express": "^4.20.0", + "prettier": "3.6.2", + "pretty-format": "^30.2.0", + "protobufjs": "^7.5.4", + "rimraf": "^6.1.2", + "typescript": "5.9.3", + "vitest": "^3.2.1" + }, + "peerDependencies": { + "vitest": "^1.0.0 || ^2.0.0 || ^3.0.0" + }, + "dependencies": { + "@contract-case/contract-case-dsl-js": "0.29.1" + } +} diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/client/connectors/grpc/clientExample.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/client/connectors/grpc/clientExample.ts new file mode 100644 index 000000000..0a11c1ac4 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/client/connectors/grpc/clientExample.ts @@ -0,0 +1,76 @@ +import { credentials, ServerErrorResponse, status } from '@grpc/grpc-js'; + +import { + loadPackage, + loadServiceFromPackage, +} from '../../../fixtures/grpcLoader.js'; +import { + PACKAGE_NAME, + PROTO_PATH, + SERVICE_NAME, +} from '../../../fixtures/grpcConstants.js'; +import { ApiError } from '../../entities/apiErrors.js'; +import { UserNotFoundConsumerError } from '../../entities/errors.js'; +import { createTypeLookup } from '../../../fixtures/grpcTypeResolver.js'; +import { User } from '../../../server/entities/responses.js'; + +export type GrpcApi = { + getUser: (id: string) => Promise; +}; + +export const makeApi = (port: number): GrpcApi => { + const target = `localhost:${port}`; + + const serviceName = SERVICE_NAME; + const methodName = 'getUser'; + + const ExampleService = loadServiceFromPackage( + SERVICE_NAME, + loadPackage(PROTO_PATH, PACKAGE_NAME), + ); + + const client = new ExampleService(target, credentials.createInsecure()); + + return { + getUser: (id: string) => + new Promise((resolve, reject) => { + if (!client[methodName]) { + reject( + new Error( + `The service named '${serviceName}' doesn't appear to have a method named '${methodName}'`, + ), + ); + return; + } + + const typeLookup = createTypeLookup(PROTO_PATH); + + const UserRequest = typeLookup.lookup('grpc_endpoints.GetUserRequest'); + + const StringValue = typeLookup.lookup('google.protobuf.StringValue'); + + client[methodName]( + UserRequest.create({ + id: StringValue.create({ value: id }), + }), + (err: ServerErrorResponse, response: unknown) => { + if (err) { + if (err.code === status.NOT_FOUND) { + reject( + new UserNotFoundConsumerError( + `The user '${id}' was not found`, + ), + ); + } else { + reject(new ApiError(`Server failed with: ${err}`)); + } + return; + } + // eslint-disable-next-line no-console + console.log('User:', response); + resolve(response as User); + }, + ); + }), + }; +}; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/client/connectors/http/index.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/client/connectors/http/index.ts new file mode 100644 index 000000000..b847052ab --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/client/connectors/http/index.ts @@ -0,0 +1,52 @@ +import { UserNotFoundConsumerError } from '../../entities/errors.js'; +import { API_NOT_FOUND } from '../../entities/apiErrors.js'; +import { makeAxiosConnector } from './internals/axiosConnector.js'; +import type { ServerHealth } from '../../entities/types.js'; + +// This is the main API interface. It knows how to turn your business domain +// requests into logical requests for the connector. The connector's job is to +// turn the logical requests into actual requests. + +interface User { + userId: string; + name: string; +} + +interface Api { + getAllProducts: () => Promise>; + getProduct: (id: string) => Promise; + getUserByPath: (id: string) => Promise; + getUserByQuery: (id: string) => Promise; + health: () => Promise; +} + +type WireServerHealth = { + status: ServerHealth; +}; + +export const api = (baseurl: string): Api => { + const server = makeAxiosConnector(baseurl); + + return { + getAllProducts: () => server.authedGet('/products'), + getProduct: (id) => server.authedGet(`/products/${id}`), + getUserByPath: (id: string) => + server.authedGet(`/users/${id}`).catch((e) => { + if (e.code === API_NOT_FOUND) { + throw new UserNotFoundConsumerError(`Unable to find user '${id}'`); + } + throw e; + }), + getUserByQuery: (id: string) => + server.authedGet(`/users`, { id }).catch((e) => { + if (e.code === API_NOT_FOUND) { + throw new UserNotFoundConsumerError(`Unable to find user '${id}'`); + } + throw e; + }), + health: () => + server.get('/health').then(({ status }) => status), + }; +}; + +export default api; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/client/connectors/http/internals/axiosConnector.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/client/connectors/http/internals/axiosConnector.ts new file mode 100644 index 000000000..9a4ae5c87 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/client/connectors/http/internals/axiosConnector.ts @@ -0,0 +1,26 @@ +import axios from 'axios'; + +import { unmarshallSuccess, unmarshallFailure } from './marshaller.js'; + +type HttpConnector = { + authedGet: (path: string, query?: Record) => Promise; + get: (path: string) => Promise; +}; + +// This is the connector for axios. +// It knows how to turn logical requests into axios calls + +export const makeAxiosConnector = (baseurl: string): HttpConnector => ({ + authedGet: (path, query) => + axios + .get(`${baseurl}${path}`, { + headers: { Accept: 'application/json' }, + ...(query ? { params: query } : {}), + // headers: { Authorization: `Bearer ${authToken}` }, + }) + .then(unmarshallSuccess, unmarshallFailure), + get: (path) => + axios + .get(`${baseurl}${path}`, { headers: { Accept: 'application/json' } }) + .then(unmarshallSuccess, unmarshallFailure), +}); diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/client/connectors/http/internals/marshaller.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/client/connectors/http/internals/marshaller.ts new file mode 100644 index 000000000..0300b5b6f --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/client/connectors/http/internals/marshaller.ts @@ -0,0 +1,58 @@ +// This module knows how to turn axios responses into +// the relevant response objects or errors + +import axios, { AxiosResponse } from 'axios'; +import { + ApiError, + API_ERROR, + API_NOT_AUTHORISED, + API_NOT_FOUND, + API_NO_RESPONSE, +} from '../../../entities/apiErrors.js'; + +export const unmarshallSuccess = (response: AxiosResponse): T => + response.data; + +type WireErrorResponse = { + message: string; +}; + +const isWireErrorResponse = (data: unknown): data is WireErrorResponse => { + const maybeResponse = data as WireErrorResponse; + return ( + typeof maybeResponse === 'object' && + 'message' in maybeResponse && + typeof maybeResponse.message === 'string' + ); +}; + +export const unmarshallFailure = (error: Error): never => { + if (axios.isAxiosError(error)) { + if (error.response) { + if (error.response.status === 401) { + throw new ApiError( + "The server says that you're not authorised.", + API_NOT_AUTHORISED, + ); + } + + if (error.response.status === 404) { + throw new ApiError(`Not found: ${error.response.data}`, API_NOT_FOUND); + } + + throw new ApiError( + error.response.data && isWireErrorResponse(error.response.data) + ? error.response.data.message + : `The server returned an error code (${error.response.status})`, + API_ERROR, + ); + } + if (error.request) { + throw new ApiError( + `The server didn't respond: ${error.message} `, + API_NO_RESPONSE, + ); + } + } + throw new Error(`[API Failed] ${error.message}`); +}; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/client/entities/apiErrors.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/client/entities/apiErrors.ts new file mode 100644 index 000000000..490b8c1d2 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/client/entities/apiErrors.ts @@ -0,0 +1,20 @@ +export const API_ERROR = 'API_ERROR'; +export const API_NO_RESPONSE = 'API_NO_RESPONSE'; +export const API_NOT_AUTHORISED = 'API_NOT_AUTHORISED'; +export const API_NOT_FOUND = 'API_NOT_FOUND'; + +export class ApiError extends Error { + code: string; + + constructor(message = 'An API error occured', code = API_ERROR) { + super(message); + + // Maintains proper stack trace for where our error was thrown (only available on V8) + if (Error.captureStackTrace) { + Error.captureStackTrace(this, ApiError); + } + + this.name = code; + this.code = code; + } +} diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/client/entities/errors.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/client/entities/errors.ts new file mode 100644 index 000000000..7ad044bb9 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/client/entities/errors.ts @@ -0,0 +1,7 @@ +export class UserNotFoundConsumerError extends Error { + constructor(message: string) { + super(message); + Object.setPrototypeOf(this, new.target.prototype); + this.name = 'UserNotFoundConsumerError'; + } +} diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/client/entities/types.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/client/entities/types.ts new file mode 100644 index 000000000..6f60c2ca2 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/client/entities/types.ts @@ -0,0 +1 @@ +export type ServerHealth = 'up' | 'down'; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/client/http.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/client/http.ts new file mode 100644 index 000000000..ae311aec9 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/client/http.ts @@ -0,0 +1,3 @@ +import { api } from './connectors/http/index.js'; + +export default api; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/fixtures/grpcConstants.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/fixtures/grpcConstants.ts new file mode 100644 index 000000000..94b08109e --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/fixtures/grpcConstants.ts @@ -0,0 +1,4 @@ +export const PROTO_PATH = './src/__tests__/fixtures/grpc_endpoints.proto'; + +export const PACKAGE_NAME = 'grpc_endpoints'; +export const SERVICE_NAME = 'UserService'; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/fixtures/grpcLoader.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/fixtures/grpcLoader.ts new file mode 100644 index 000000000..673ee08cc --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/fixtures/grpcLoader.ts @@ -0,0 +1,44 @@ +import grpc, { GrpcObject, loadPackageDefinition } from '@grpc/grpc-js'; +import { loadSync } from '@grpc/proto-loader'; + +const loadProto = (protoPath: string) => { + try { + const packageDefinition = loadSync(protoPath, { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + }); + return loadPackageDefinition(packageDefinition); + } catch (e) { + throw new Error(`Unable to load proto from: ${protoPath}`, { cause: e }); + } +}; + +export const loadPackage = ( + protoPath: string, + packageName: string, +): GrpcObject => { + const loadedProto = loadProto(protoPath); + const loadedPackage = loadedProto[packageName] as GrpcObject; + if (loadedPackage == null) { + throw new Error( + `The proto file '${protoPath}' doesn't have a package named '${packageName}'`, + ); + } + + return loadedPackage; +}; + +export const loadServiceFromPackage = ( + serviceName: string, + servicePackage: GrpcObject, +): grpc.ServiceClientConstructor => { + if (!servicePackage[serviceName]) { + throw new Error( + `The loaded package doesn't appear to have a service named '${serviceName}'`, + ); + } + return servicePackage[serviceName] as grpc.ServiceClientConstructor; +}; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/fixtures/grpcTypeResolver.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/fixtures/grpcTypeResolver.ts new file mode 100644 index 000000000..fb6ec486c --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/fixtures/grpcTypeResolver.ts @@ -0,0 +1,24 @@ +// eslint-disable-next-line import/extensions +import { loadProtosWithOptionsSync } from '@grpc/proto-loader/build/src/util.js'; +import { Type } from 'protobufjs'; + +type TypeLookup = { + lookup: (path: string) => Type; +}; + +export const createTypeLookup = (protoPath: string): TypeLookup => { + const internals = loadProtosWithOptionsSync(protoPath, { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + }); + + // eslint-disable-next-line no-console + console.log('Internal proto: ', internals); + + return { + lookup: (path: string) => internals.lookupTypeOrEnum(path), + }; +}; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/fixtures/grpc_endpoints.proto b/packages/contract-case-dsl-js-vitest/src/__tests__/fixtures/grpc_endpoints.proto new file mode 100644 index 000000000..2f933840a --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/fixtures/grpc_endpoints.proto @@ -0,0 +1,47 @@ +syntax = "proto3"; + +import "google/protobuf/wrappers.proto"; + +option java_multiple_files = true; +option java_package = "io.contract_testing.contractcase.examples"; +option java_outer_classname = "ContractCaseExample"; + +package grpc_endpoints; + +// The UserService +service UserService { + // Get a user + rpc GetUser(GetUserRequest) returns (UserResponse) {} + + // Check the server's status + rpc HealthStatus(GetHealthRequest) returns (HealthResponse) {} +} + +// Get a user by ID +message GetUserRequest { + // The user ID to get + google.protobuf.StringValue id = 1; +} + +// Describes a user +message UserResponse { + // Username for logging in + string username = 1; + // User's first name + string first_name = 2; + // User's last name + string last_name = 3; + // User ID in the system + string id = 4; +} + +// Get the health status of the server +message GetHealthRequest { + // no parameters +} + +// Response describing the status of the server +message HealthResponse { + // status of the server + string status = 1; +} diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/grpc/createServer.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/grpc/createServer.ts new file mode 100644 index 000000000..f98ec960d --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/grpc/createServer.ts @@ -0,0 +1,14 @@ +import { + Server, + ServiceDefinition, + UntypedServiceImplementation, +} from '@grpc/grpc-js'; + +export const createServer = ( + service: ServiceDefinition, + handlers: UntypedServiceImplementation, +): Server => { + const server = new Server(); + server.addService(service, handlers); + return server; +}; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/grpc/handlers.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/grpc/handlers.ts new file mode 100644 index 000000000..00b36aed8 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/grpc/handlers.ts @@ -0,0 +1,38 @@ +import { handleUnaryCall, status } from '@grpc/grpc-js'; +import { Dependencies } from '../../domain/types.js'; + +type UserRequest = { + id: string; +}; + +type UserResponse = { + username: string; + first_name: string; + last_name: string; + id: string; +}; + +export const GetUser = + (deps: Dependencies): handleUnaryCall => + (call, callback) => { + // eslint-disable-next-line no-console + console.log(call.request); + + const user = deps.userRepository.get(call.request.id); + + if (user == null) { + callback({ + code: status.NOT_FOUND, + details: `No user with id '${call.request.id}' was found`, + }); + return; + } + + callback(null, { + id: user.userId, + username: user.name, + first_name: '', + last_name: '', + otherField: "this shoulnd't happen", + } as UserResponse); + }; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/grpc/start.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/grpc/start.ts new file mode 100644 index 000000000..a6b993a3b --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/grpc/start.ts @@ -0,0 +1,53 @@ +import { + ProtobufTypeDefinition, + Server, + ServerCredentials, +} from '@grpc/grpc-js'; +import { format } from 'pretty-format'; + +import { + PACKAGE_NAME, + PROTO_PATH, + SERVICE_NAME, +} from '../../../fixtures/grpcConstants.js'; +import { + loadPackage, + loadServiceFromPackage, +} from '../../../fixtures/grpcLoader.js'; +import { createServer } from './createServer.js'; +import { GetUser } from './handlers.js'; +import { Dependencies } from '../../domain/types.js'; + +export type RunningService = { port: number; server: Server }; + +export const start = (deps: Dependencies): Promise => { + const grpcPackage = loadPackage(PROTO_PATH, PACKAGE_NAME); + + const ExampleService = loadServiceFromPackage(SERVICE_NAME, grpcPackage); + + const userResponse = grpcPackage['UserResponse'] as ProtobufTypeDefinition; + // eslint-disable-next-line no-console + console.log(format(userResponse.type)); + // eslint-disable-next-line no-console + console.log(ExampleService); + + const server = createServer(ExampleService.service, { + GetUser: GetUser(deps), + }); + + return new Promise((resolve, reject) => { + server.bindAsync( + '0.0.0.0', + ServerCredentials.createInsecure(), + (err, port) => { + if (err) { + reject(err); + } else { + // eslint-disable-next-line no-console + console.log(`Server started on port: ${port}`); + resolve({ port, server }); + } + }, + ); + }); +}; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/http/handlers.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/http/handlers.ts new file mode 100644 index 000000000..2bee01fee --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/http/handlers.ts @@ -0,0 +1,51 @@ +import type { RequestHandler, Response, Request } from 'express'; +import responder from './responder.js'; +import { + BaseServiceDependencies, + HealthServiceDependencies, + UserServiceDependencies, +} from '../../domain/types.js'; +import { makeUserService } from '../../domain/userService.js'; +import { User } from '../../entities/responses.js'; + +export const base: (deps: BaseServiceDependencies) => RequestHandler = + ({ baseService }: BaseServiceDependencies) => + (req: Request, res: Response) => { + responder(res).success( + baseService(typeof req.ip === 'string' ? req.ip : 'no clear ip'), + ); + }; + +type HealthStatus = 'up' | 'down' | 'starting'; + +type HealthResponse = { status: HealthStatus }; + +export const health: (deps: HealthServiceDependencies) => RequestHandler = + ({ healthService }: HealthServiceDependencies) => + (_req: Request, res: Response) => { + if (healthService.ready()) { + responder(res).success({ status: 'up' }); + } else { + responder(res).status(503, { status: 'down' }); + } + }; + +export const usersByPath: (deps: UserServiceDependencies) => RequestHandler = + ({ userRepository }: UserServiceDependencies) => + (req: Request, res: Response) => { + const { userId } = req.params; + if (typeof userId !== 'string') throw new Error('No userID provided'); + responder(res).success( + makeUserService({ userRepository }).getUser(userId), + ); + }; + +export const usersByQuery: (deps: UserServiceDependencies) => RequestHandler = + ({ userRepository }: UserServiceDependencies) => + (req: Request, res: Response) => { + const { id } = req.query; + if (typeof id !== 'string') throw new Error('No userID provided'); + responder(res).success( + makeUserService({ userRepository }).getUser(id), + ); + }; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/http/index.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/http/index.ts new file mode 100644 index 000000000..1a103dc99 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/http/index.ts @@ -0,0 +1,37 @@ +import express from 'express'; +import type * as http from 'http'; +import bodyParser from 'body-parser'; +import routes from './routes.js'; +import { userRepo } from '../../domain/users/defaultUserRepository.js'; +import { baseService } from '../../domain/baseService.js'; +import { healthService } from '../../domain/healthService.js'; +import { Dependencies } from '../../domain/types.js'; + +const app = express(); +const PORT = 8282; // default port to listen + +const defaultDependencies: Dependencies = { + baseService, + healthService, + userRepository: userRepo, +}; + +const start = ( + port = PORT, + dependencies = defaultDependencies, +): Promise => + new Promise((resolve, reject) => { + try { + app.use(bodyParser.json()); + app.use(bodyParser.urlencoded({ extended: true })); + routes(app, dependencies); + const server = app.listen(port, '::'); + server.on('listening', () => { + resolve(server); + }); + } catch (e) { + reject(e); + } + }); + +export default start; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/http/responder.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/http/responder.ts new file mode 100644 index 000000000..ae89f2803 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/http/responder.ts @@ -0,0 +1,37 @@ +import type { Response } from 'express'; +import type { ErrorResponse } from '../../entities/responses.js'; + +interface Responder { + success: (data: T) => void; + status: (status: number, data: T) => void; + error: (error: ErrorResponse) => void; +} + +const responder = (res: Response): Responder => ({ + success: (data: T) => { + res.format({ + 'application/json': () => { + res.json(data); + }, + default: () => { + res.status(406).send('Not Acceptable'); + }, + }); + }, + status: (status: number, data: T) => { + res.format({ + 'application/json': () => { + res.status(status).json(data); + }, + default: () => { + res.status(406).send('Not Acceptable'); + }, + }); + }, + error: (error: ErrorResponse) => { + res.statusCode = 400; + res.json({ message: error.message }); + }, +}); + +export default responder; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/http/routes.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/http/routes.ts new file mode 100644 index 000000000..24142714b --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/connectors/http/routes.ts @@ -0,0 +1,21 @@ +import type { ErrorRequestHandler, Express } from 'express'; +import type { Dependencies } from '../../domain/types.js'; +import { UserNotFoundException } from '../../entities/UserNotFoundException.js'; +import * as handlers from './handlers.js'; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const errorHandler: ErrorRequestHandler = (err: Error, _req, res, _next) => { + if (err instanceof UserNotFoundException) { + res.status(404).send(err.message); + } + res.status(500).send('Something broke!'); +}; + +export default (app: Express, deps: Dependencies): void => { + app.get('/', handlers.base(deps)); + app.get('/health', handlers.health(deps)); + app.get('/users/:userId', handlers.usersByPath(deps)); + app.get('/users', handlers.usersByQuery(deps)); + + app.use(errorHandler); +}; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/domain/baseService.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/domain/baseService.ts new file mode 100644 index 000000000..e87a739c8 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/domain/baseService.ts @@ -0,0 +1,8 @@ +// Note that the Arbitrary response type should be updated to a more specific type +import type { HelloResponse } from '../entities/responses.js'; +import type { BaseService } from './types.js'; + +// when we actually implement services +export const baseService: BaseService = (ip: string): HelloResponse => ({ + hello: ip, +}); diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/domain/healthService.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/domain/healthService.ts new file mode 100644 index 000000000..dda6dd7d9 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/domain/healthService.ts @@ -0,0 +1,3 @@ +import type { HealthService } from './types.js'; + +export const healthService: HealthService = { ready: () => true }; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/domain/types.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/domain/types.ts new file mode 100644 index 000000000..e0a9f5c60 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/domain/types.ts @@ -0,0 +1,15 @@ +import type { HelloResponse, User } from '../entities/responses.js'; + +export type BaseService = (ip: string) => HelloResponse; +export type HealthService = { ready: () => boolean }; +export type UserService = { getUser: (id: string) => User }; + +export type UserRepository = { get: (id: string) => User | undefined }; + +export type BaseServiceDependencies = { baseService: BaseService }; +export type UserServiceDependencies = { userRepository: UserRepository }; +export type HealthServiceDependencies = { healthService: HealthService }; + +export type Dependencies = BaseServiceDependencies & + HealthServiceDependencies & + UserServiceDependencies; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/domain/userService.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/domain/userService.ts new file mode 100644 index 000000000..a01731aa4 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/domain/userService.ts @@ -0,0 +1,12 @@ +import { UserNotFoundException } from '../entities/UserNotFoundException.js'; +import type { UserService, UserServiceDependencies } from './types.js'; + +export const makeUserService = ({ + userRepository, +}: UserServiceDependencies): UserService => ({ + getUser: (id: string) => { + const user = userRepository.get(id); + if (user) return user; + throw new UserNotFoundException(`Unable to find user '${id}'`); + }, +}); diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/domain/users/defaultUserRepository.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/domain/users/defaultUserRepository.ts new file mode 100644 index 000000000..151f084d6 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/domain/users/defaultUserRepository.ts @@ -0,0 +1,3 @@ +import type { UserRepository } from '../types.js'; + +export const userRepo: UserRepository = { get: () => undefined }; diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/entities/UserNotFoundException.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/entities/UserNotFoundException.ts new file mode 100644 index 000000000..ab10d18f8 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/entities/UserNotFoundException.ts @@ -0,0 +1,7 @@ +export class UserNotFoundException extends Error { + constructor(message: string) { + super(message); + Object.setPrototypeOf(this, new.target.prototype); + this.name = UserNotFoundException.name; + } +} diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/entities/responses.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/entities/responses.ts new file mode 100644 index 000000000..d6c80a6d7 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/entities/responses.ts @@ -0,0 +1,11 @@ +export interface ErrorResponse { + message: string; +} + +// This will need to change when we build out the service +export type HelloResponse = { hello: string }; + +export interface User { + userId: string; + name: string; +} diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/grpc.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/grpc.ts new file mode 100644 index 000000000..abfc16e80 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/grpc.ts @@ -0,0 +1,5 @@ +import { RunningService, start } from './connectors/grpc/start.js'; +import { Dependencies } from './domain/types.js'; + +export default (dependencies: Dependencies): Promise => + start(dependencies); diff --git a/packages/contract-case-dsl-js-vitest/src/__tests__/server/http.ts b/packages/contract-case-dsl-js-vitest/src/__tests__/server/http.ts new file mode 100644 index 000000000..b88acc43c --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/__tests__/server/http.ts @@ -0,0 +1,8 @@ +import type * as http from 'http'; +import start from './connectors/http/index.js'; +import { Dependencies } from './domain/types.js'; + +export default ( + port: number, + dependencies: Dependencies, +): Promise => start(port, dependencies); diff --git a/packages/contract-case-dsl-js-vitest/src/boundaries/index.ts b/packages/contract-case-dsl-js-vitest/src/boundaries/index.ts new file mode 100644 index 000000000..53e8e51d0 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/boundaries/index.ts @@ -0,0 +1 @@ +export * from './vitest/index.js'; diff --git a/packages/contract-case-dsl-js-vitest/src/boundaries/vitest/index.ts b/packages/contract-case-dsl-js-vitest/src/boundaries/vitest/index.ts new file mode 100644 index 000000000..9c7a77606 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/boundaries/vitest/index.ts @@ -0,0 +1,2 @@ +export * from './vitest.js'; +export * from './types.js'; diff --git a/packages/contract-case-dsl-js-vitest/src/boundaries/vitest/types.ts b/packages/contract-case-dsl-js-vitest/src/boundaries/vitest/types.ts new file mode 100644 index 000000000..495217055 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/boundaries/vitest/types.ts @@ -0,0 +1,13 @@ +import type { + ContractCaseDefiner, + ContractVerifier, + ContractCaseConfig, + ContractCaseVerifierConfig, +} from '@contract-case/contract-case-dsl-js'; + +export type ContractCaseVitestConfig = ContractCaseConfig; +export type ContractCaseVitestVerifierConfig = ContractCaseVerifierConfig; + +export type DefineCaseVitestCallback = (contract: ContractCaseDefiner) => void; + +export type VerifyCaseVitestCallback = (contract: ContractVerifier) => void; diff --git a/packages/contract-case-dsl-js-vitest/src/boundaries/vitest/vitest.ts b/packages/contract-case-dsl-js-vitest/src/boundaries/vitest/vitest.ts new file mode 100644 index 000000000..4994d718a --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/boundaries/vitest/vitest.ts @@ -0,0 +1,113 @@ +import { describe, it, afterAll, vi } from 'vitest'; +import { + ContractCaseDefiner, + ContractVerifier, +} from '@contract-case/contract-case-dsl-js'; +import type { + ContractMetadata, + ContractWriteSuccess, +} from '@contract-case/contract-case-dsl-js'; +import type { + ContractCaseVitestConfig, + ContractCaseVitestVerifierConfig, + DefineCaseVitestCallback, + VerifyCaseVitestCallback, +} from './types.js'; + +/** + * @internal + * The timeout to use to override vitest's default timeout. + * + * If you update this, make sure you update the comments in {@link defineContract} and {@link verifyContract}. + */ +const TIMEOUT = 30000; + +/** + * Convenience wrapper for defining contracts + * + * @param config - Configuration for this definition run (may be overridden in individual tests) + * @param setupCallback - The test definitions + * @param onContractDefineSuccess - An optional callback to call if the contract was written successfully + * @param timeoutMillis - An optional timeout to set for vitest's hooks and tests. Defaults to 30000 + * @returns + */ +export const defineContract = ( + config: ContractCaseVitestConfig, + setupCallback: DefineCaseVitestCallback, + onContractDefineSuccess: ( + details: ContractWriteSuccess, + ) => Promise | void = () => {}, + timeoutMillis: number = TIMEOUT, +): void => { + describe(`Case contract definition`, () => { + const contract = new ContractCaseDefiner({ + testRunId: + process.env['VITEST_POOL_ID'] || 'VITEST_POOL_ID_WAS_UNDEFINED', + ...config, + }); + + afterAll( + () => contract.endRecord().then(onContractDefineSuccess), + timeoutMillis, + ); + + describe(`between ${config.consumerName} and ${config.providerName}`, () => { + vi.setConfig({ testTimeout: timeoutMillis }); + + setupCallback(contract); + }); + }); +}; + +const renderHash = (metadata: ContractMetadata) => + '_case' in metadata && + typeof metadata['_case'] === 'object' && + 'hash' in metadata['_case'] && + typeof metadata['_case']['hash'] === 'string' + ? ` (hash ${metadata['_case']['hash']})` + : ''; + +/** + * Convenience wrapper for verifying contracts. Calling this will generate all the tests + * you need for + * + * @param config - Configuration for this verification run + * @param setupCallback - Optional. Called with the contract verifier before any tests are run. You can use this to do any + * computed setup necessary + * @param verificationCompleteCallback - Optional. Called once the verification is complete. In a future release, this will contain the details + * of the verification success / failure. + * @param timeoutMillis - An optional timeout to set for vitest's hooks and tests. Defaults to 30000 + * @returns + */ +export const verifyContract = ( + config: ContractCaseVitestVerifierConfig, + setupCallback: VerifyCaseVitestCallback = () => {}, + verificationComplete = () => {}, + timeoutMillis: number = TIMEOUT, +): void => { + if (!config.providerName) { + throw new Error('Must specify a providerName to verify'); + } + describe(`Provider verification for ${config.providerName}`, () => { + const verifier = new ContractVerifier(config); + vi.setConfig({ testTimeout: timeoutMillis }); + + setupCallback(verifier); + + const contracts = verifier.prepareVerificationTests(config); + + contracts.forEach((contract) => { + describe(`Contract between ${contract.description.consumerName} and ${contract.description.providerName} ${renderHash(contract.metadata)}`, () => { + contract.testHandles.forEach((test) => { + it(`${test.testName}`, () => verifier.runPreparedTest(test)); + }); + }); + it('Overall verification result', () => + verifier.closePreparedVerification(contract.contractIndex)); + }); + + afterAll(() => { + verificationComplete(); + }); + }); +}; diff --git a/packages/contract-case-dsl-js-vitest/src/index.function.caller.define.spec.ts b/packages/contract-case-dsl-js-vitest/src/index.function.caller.define.spec.ts new file mode 100644 index 000000000..b18776875 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/index.function.caller.define.spec.ts @@ -0,0 +1,56 @@ +import { describe, it, expect } from 'vitest'; +import { + willCallFunction, + FunctionExecutorConfig, + defineContract, +} from './index.js'; + +describe('function executor', () => { + defineContract( + { + consumerName: 'function caller', + providerName: 'function execution', + changedContracts: 'OVERWRITE', + }, + (contract) => { + describe('function with no args', () => { + it('returns nothing', () => + contract.runInteraction( + { + definition: willCallFunction({ + arguments: [], + returnValue: null, + functionName: 'zeroArgs', + }), + }, + { + trigger: async (setup: FunctionExecutorConfig) => + setup.getFunction(setup.mock.functionHandle)(), + testResponse: (returnValue) => { + expect(returnValue).toEqual(null); + }, + }, + )); + }); + describe('function with two args', () => { + it('returns nothing', () => + contract.runInteraction( + { + definition: willCallFunction({ + arguments: ['example', 2], + returnValue: 'example2', + functionName: 'concatenate', + }), + }, + { + trigger: async (setup: FunctionExecutorConfig) => + setup.getFunction(setup.mock.functionHandle)('example', 2), + testResponse: (returnValue: unknown) => { + expect(returnValue).toEqual('example2'); + }, + }, + )); + }); + }, + ); +}); diff --git a/packages/contract-case-dsl-js-vitest/src/index.function.caller.spec.verify.ts b/packages/contract-case-dsl-js-vitest/src/index.function.caller.spec.verify.ts new file mode 100644 index 000000000..c0b7adbe8 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/index.function.caller.spec.verify.ts @@ -0,0 +1,16 @@ +import { describe } from 'vitest'; + +import { verifyContract } from './boundaries/vitest/vitest.js'; + +describe('verification', () => { + verifyContract( + { + providerName: 'function execution', + throwOnFail: true, + }, + (verifier) => { + verifier.registerFunction('zeroArgs', () => {}); + verifier.registerFunction('concatenate', (a, b) => `${a}${b}`); + }, + ); +}); diff --git a/packages/contract-case-dsl-js-vitest/src/index.function.implementer.define.spec.ts b/packages/contract-case-dsl-js-vitest/src/index.function.implementer.define.spec.ts new file mode 100644 index 000000000..b3462ad47 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/index.function.implementer.define.spec.ts @@ -0,0 +1,50 @@ +import { describe, it, beforeAll } from 'vitest'; +import { defineContract, willReceiveFunctionCall } from './index.js'; + +describe('function receiver', () => { + defineContract( + { + consumerName: 'function execution', + providerName: 'function definer', + }, + (contract) => { + describe('function with no args', () => { + // This string can be anything you like, as long as it's the same when + // registering the function, and executing the test + const NO_ARG_FUNCTION_HANDLE = 'NO ARG FUNCTION'; + beforeAll(() => { + contract.registerFunction(NO_ARG_FUNCTION_HANDLE, () => {}); + }); + + it('succeeds', () => + contract.runInteraction({ + definition: willReceiveFunctionCall({ + arguments: [], + returnValue: null, + functionName: NO_ARG_FUNCTION_HANDLE, + }), + })); + }); + describe('function with args', () => { + // This string can be anything you like, as long as it's the same when + // registering the function, and executing the test + const FUNCTION_WITH_ARG_HANDLE = 'HAS ARGS FUNCTION'; + beforeAll(() => { + contract.registerFunction( + FUNCTION_WITH_ARG_HANDLE, + (s: string, n: number) => `${s}${n}`, + ); + }); + + it('succeeds', () => + contract.runInteraction({ + definition: willReceiveFunctionCall({ + arguments: ['example', 2], + returnValue: 'example2', + functionName: FUNCTION_WITH_ARG_HANDLE, + }), + })); + }); + }, + ); +}); diff --git a/packages/contract-case-dsl-js-vitest/src/index.function.implementer.spec.verify.ts b/packages/contract-case-dsl-js-vitest/src/index.function.implementer.spec.verify.ts new file mode 100644 index 000000000..94a477cac --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/index.function.implementer.spec.verify.ts @@ -0,0 +1,30 @@ +import { describe, expect } from 'vitest'; + +import { verifyContract, TriggerGroupMap } from './index.js'; +import type { FunctionExecutorConfig } from './index.js'; + +describe('verification', () => { + verifyContract({ + throwOnFail: true, + providerName: 'function definer', + triggers: new TriggerGroupMap() + .addTriggerGroup('An invocation of NO ARG FUNCTION()', { + trigger: async (setup: FunctionExecutorConfig) => + setup.getFunction(setup.mock.functionHandle)(), + testResponses: { + 'returns null': (returnValue) => expect(returnValue).toBe(null), + 'returning null': (returnValue) => expect(returnValue).toBe(null), + }, + }) + .addTriggerGroup('An invocation of HAS ARGS FUNCTION( "example", 2 )', { + trigger: async (setup: FunctionExecutorConfig) => + setup.getFunction(setup.mock.functionHandle)('example', 2), + testResponses: { + 'returning "example2"': (returnValue) => + expect(returnValue).toEqual('example2'), + 'returns "example2"': (returnValue) => + expect(returnValue).toEqual('example2'), + }, + }), + }); +}); diff --git a/packages/contract-case-dsl-js-vitest/src/index.http.client.base.spec.verify.ts b/packages/contract-case-dsl-js-vitest/src/index.http.client.base.spec.verify.ts new file mode 100644 index 000000000..1490378a8 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/index.http.client.base.spec.verify.ts @@ -0,0 +1,91 @@ +import { describe, beforeAll, afterAll } from 'vitest'; +import type * as http from 'node:http'; + +import start from './__tests__/server/connectors/http/index.js'; +import { baseService } from './__tests__/server/domain/baseService.js'; +import type { Dependencies } from './__tests__/server/domain/types.js'; +import type { User } from './__tests__/server/entities/responses.js'; +import { verifyContract } from './boundaries/vitest/vitest.js'; +import type { StateHandlers } from './index.js'; + +describe('Server verification but with base config', () => { + // This test is like the non base one, but with state handlers + // passed in to the constructor + + // SERVER SETUP BOILERPLATE + // REPLACE WITH YOUR OWN SETUP CODE + let server: http.Server; + let mockHealthStatus = true; + let mockGetUser: (id: string) => User | undefined = () => undefined; + const port = 8097; + const serverDependencies: Dependencies = { + healthService: { + ready: () => mockHealthStatus, + }, + baseService, + userRepository: { get: (id) => mockGetUser(id) }, + }; + // END SERVER SETUP + + beforeAll( + async () => { + server = await start(port, serverDependencies); + }, + // Long timeout to reduce brittleness in windows tests in github + 60000, + ); + afterAll( + () => + new Promise((resolve, reject) => { + if (server) { + server.close((err?: Error) => { + if (err) reject(err); + resolve(); + }); + } else { + resolve(); + } + }), + ); + // END SERVER SETUP BOILERPLATE + + const stateHandlers: StateHandlers = { + 'Server is up': () => { + mockHealthStatus = true; + }, + 'Server is down': () => { + mockHealthStatus = false; + }, + 'A user exists': { + setup: () => { + const userId = '42'; + mockGetUser = (id) => { + if (id === userId) + return { + userId, + name: 'John', + }; + return undefined; + }; + return { userId }; + }, + teardown: () => { + mockGetUser = () => undefined; + }, + }, + 'No users exist': () => { + mockGetUser = () => undefined; + return { userId: '12' }; + }, + }; + + verifyContract({ + providerName: 'http response provider', + mockConfig: { + http: { + baseUrlUnderTest: `http://localhost:${port}`, + }, + }, + stateHandlers, + }); +}); diff --git a/packages/contract-case-dsl-js-vitest/src/index.http.client.define.spec.ts b/packages/contract-case-dsl-js-vitest/src/index.http.client.define.spec.ts new file mode 100644 index 000000000..79f859b20 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/index.http.client.define.spec.ts @@ -0,0 +1,279 @@ +import { describe, it, expect } from 'vitest'; +// These imports are our code under test +import api from './__tests__/client/http.js'; +import { ApiError } from './__tests__/client/entities/apiErrors.js'; +import { UserNotFoundConsumerError } from './__tests__/client/entities/errors.js'; + +// These imports are from Case +import { + inState, + httpStatus, + shapedLike, + stateVariable, + stringPrefix, + willSendHttpRequest, + HttpRequestConfig, + defineContract, + anyString, +} from './index.js'; + +const contractDetails = { + consumerName: 'http response consumer', + providerName: 'http response provider', +}; + +describe('e2e http consumer driven', () => { + defineContract( + { + ...contractDetails, + }, + (contract) => { + describe('health get', () => { + const sendHealthRequest = (config: HttpRequestConfig) => + api(config.mock.baseUrl).health(); + describe('When the server is up', () => { + const state = inState('Server is up'); + + describe('health endpoint', () => { + it('behaves as expected', () => + contract.runInteraction( + { + states: [state], + definition: willSendHttpRequest({ + request: { + method: 'GET', + path: '/health', + headers: { accept: 'application/json' }, + }, + response: { status: 200, body: { status: 'up' } }, + }), + }, + { + trigger: sendHealthRequest, + + testResponse: (health) => { + expect(health).toEqual('up'); + }, + }, + )); + + describe('arbitrary status response string', () => { + it('behaves as expected', () => + contract.runInteraction( + { + states: [state], + definition: willSendHttpRequest({ + request: { + method: 'GET', + path: '/health', + }, + response: { + status: 200, + body: shapedLike({ status: 'whatever' }), + }, + }), + }, + { + trigger: sendHealthRequest, + testResponse: (health) => { + expect(health).toEqual('whatever'); + }, + }, + )); + }); + }); + }); + describe('When the server is down', () => { + const state = inState('Server is down'); + describe('No body server response', () => { + it('calls server health', () => + contract.runRejectingInteraction( + { + states: [state], + definition: willSendHttpRequest({ + request: { + method: 'GET', + path: '/health', + }, + response: { status: httpStatus(['4XX', '5XX']) }, + }), + }, + { + trigger: sendHealthRequest, + testErrorResponse: (e) => { + expect(e).toBeInstanceOf(ApiError); + }, + }, + )); + }); + + describe('specific server response', () => { + it('calls server health', async () => + contract.runRejectingInteraction( + { + states: [state], + definition: willSendHttpRequest({ + request: { + method: 'GET', + path: '/health', + }, + response: { status: 503, body: { status: 'down' } }, + }), + }, + { + trigger: sendHealthRequest, + testErrorResponse: (e) => { + expect(e).toBeInstanceOf(ApiError); + }, + }, + )); + }); + }); + }); + describe('User', () => { + describe('With query variables', () => { + const sendUserRequest = (setup: HttpRequestConfig) => + api(setup.mock.baseUrl).getUserByQuery( + setup.getStateVariable('userId'), + ); + describe('when the user exists', () => { + const responseBody = { userId: stateVariable('userId') }; + + it('returns an existing user', async () => + contract.runInteraction( + { + states: [ + inState('Server is up'), + inState('A user exists', { userId: '123' }), + ], + definition: willSendHttpRequest({ + request: { + method: 'GET', + path: '/users', + query: { id: stateVariable('userId') }, + }, + response: { + status: 200, + body: responseBody, + }, + }), + }, + { + trigger: sendUserRequest, + testResponse: (user) => { + expect(contract.stripMatchers(responseBody)).toEqual({ + userId: '123', + }); + expect(user).toEqual(contract.stripMatchers(responseBody)); + }, + }, + )); + }); + describe("when the user doesn't exist", () => { + it('returns a user not found error', () => + contract.runRejectingInteraction( + { + states: [ + inState('Server is up'), + inState('No users exist', { userId: '123' }), + ], + definition: willSendHttpRequest({ + request: { + method: 'GET', + path: '/users', + query: { id: stateVariable('userId') }, + }, + response: { + status: 404, + }, + }), + }, + { + trigger: sendUserRequest, + testErrorResponse: (e) => { + expect(e).toBeInstanceOf(UserNotFoundConsumerError); + }, + }, + )); + }); + }); + describe('With path variables', () => { + const sendUserRequest = (setup: HttpRequestConfig) => + api(setup.mock.baseUrl).getUserByPath( + setup.getStateVariable('userId'), + ); + describe('when the user exists', () => { + const responseBody = { + userId: stateVariable('userId'), + name: anyString('john smith'), + }; + + it('returns an existing user', async () => + contract.runInteraction( + { + states: [ + inState('Server is up'), + inState('A user exists', { userId: '123' }), + ], + definition: willSendHttpRequest({ + request: { + method: 'GET', + path: stringPrefix('/users/', stateVariable('userId')), + }, + response: { + status: 200, + body: responseBody, + }, + }), + }, + { + trigger: sendUserRequest, + testResponse: (user) => { + expect(contract.stripMatchers(responseBody)).toEqual({ + name: 'john smith', + userId: '123', + }); + expect(user).toEqual(contract.stripMatchers(responseBody)); + }, + }, + )); + }); + describe("when the user doesn't exist", () => { + it('returns a user not found error', () => + contract.runRejectingInteraction( + { + states: [ + inState('Server is up'), + inState('No users exist', { userId: '123' }), + ], + definition: willSendHttpRequest({ + request: { + method: 'GET', + path: stringPrefix('/users/', stateVariable('userId')), + }, + response: { + status: 404, + }, + }), + }, + { + trigger: sendUserRequest, + testErrorResponse: (e) => { + expect(e).toBeInstanceOf(UserNotFoundConsumerError); + }, + }, + )); + }); + }); + }); + }, + (details) => { + expect(details.consumerSlug).toBe('http-response-consumer'); + expect(details.providerSlug).toBe('http-response-provider'); + expect(details.contractPaths).toHaveLength(2); + details.contractPaths.forEach((path) => { + expect(path.endsWith('.case.json')).toBeTruthy(); + }); + }, + ); +}); diff --git a/packages/contract-case-dsl-js-vitest/src/index.http.client.spec.verify.ts b/packages/contract-case-dsl-js-vitest/src/index.http.client.spec.verify.ts new file mode 100644 index 000000000..0f86adbb8 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/index.http.client.spec.verify.ts @@ -0,0 +1,88 @@ +import { describe, beforeAll, afterAll } from 'vitest'; +import type * as http from 'node:http'; + +import start from './__tests__/server/connectors/http/index.js'; +import { baseService } from './__tests__/server/domain/baseService.js'; +import type { Dependencies } from './__tests__/server/domain/types.js'; +import type { User } from './__tests__/server/entities/responses.js'; +import { verifyContract } from './boundaries/vitest/vitest.js'; +import type { StateHandlers } from './index.js'; + +describe('Server verification', () => { + // SERVER SETUP BOILERPLATE + // REPLACE WITH YOUR OWN SETUP CODE + let server: http.Server; + let mockHealthStatus = true; + let mockGetUser: (id: string) => User | undefined = () => undefined; + const port = 8096; + const serverDependencies: Dependencies = { + healthService: { + ready: () => mockHealthStatus, + }, + baseService, + userRepository: { get: (id) => mockGetUser(id) }, + }; + // END SERVER SETUP + + beforeAll( + async () => { + server = await start(port, serverDependencies); + }, + // Long timeout to reduce brittleness in windows tests in github + 60000, + ); + afterAll( + () => + new Promise((resolve, reject) => { + if (server) { + server.close((err?: Error) => { + if (err) reject(err); + resolve(); + }); + } else { + resolve(); + } + }), + ); + // END SERVER SETUP BOILERPLATE + + const stateHandlers: StateHandlers = { + 'Server is up': () => { + mockHealthStatus = true; + }, + 'Server is down': () => { + mockHealthStatus = false; + }, + 'A user exists': { + setup: () => { + const userId = '42'; + mockGetUser = (id) => { + if (id === userId) + return { + userId, + name: 'John', + }; + return undefined; + }; + return { userId }; + }, + teardown: () => { + mockGetUser = () => undefined; + }, + }, + 'No users exist': () => { + mockGetUser = () => undefined; + return { userId: '12' }; + }, + }; + + verifyContract({ + providerName: 'http response provider', + mockConfig: { + http: { + baseUrlUnderTest: `http://localhost:${port}`, + }, + }, + stateHandlers, + }); +}); diff --git a/packages/contract-case-dsl-js-vitest/src/index.http.server.define.spec.ts b/packages/contract-case-dsl-js-vitest/src/index.http.server.define.spec.ts new file mode 100644 index 000000000..470cec406 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/index.http.server.define.spec.ts @@ -0,0 +1,253 @@ +import { describe, it, beforeAll, afterAll } from 'vitest'; + +// These imports are our code under test +import type * as http from 'node:http'; +import start from './__tests__/server/http.js'; +import type { User } from './__tests__/server/entities/responses.js'; +import type { Dependencies } from './__tests__/server/domain/types.js'; +import { baseService } from './__tests__/server/domain/baseService.js'; + +import { + inState, + httpStatus, + shapedLike, + stateVariable, + stringPrefix, + StateHandlers, + willReceiveHttpRequest, + defineContract, +} from './index.js'; + +describe('e2e http provider driven', () => { + describe('test and write contract', () => { + // CODE UNDER TEST SETUP BOILERPLATE + let server: http.Server; + let mockHealthStatus = true; + let mockGetUser: (id: string) => User | undefined = () => undefined; + const port = 8095; + const serverDependencies: Dependencies = { + healthService: { + ready: () => mockHealthStatus, + }, + baseService, + userRepository: { get: (id) => mockGetUser(id) }, + }; + + beforeAll(async () => { + server = await start(port, serverDependencies); + }); + + afterAll( + () => + new Promise((resolve, reject) => { + if (server) { + server.close((err?: Error) => { + if (err) reject(err); + resolve(); + }); + } else { + resolve(); + } + }), + ); + // END CODE UNDER TEST SETUP BOILERPLATE + + const stateHandlers: StateHandlers = { + 'Server is up': () => { + mockHealthStatus = true; + }, + 'Server is down': () => { + mockHealthStatus = false; + }, + 'A user exists': { + setup: () => { + const userId = '42'; + mockGetUser = (id) => { + if (id === userId) + return { + userId, + name: 'John', + }; + return undefined; + }; + return { userId }; + }, + teardown: () => { + mockGetUser = () => undefined; + }, + }, + 'No users exist': () => { + mockGetUser = () => undefined; + return { userId: '345' }; + }, + }; + + defineContract( + { + consumerName: 'http request consumer', + providerName: 'http request provider', + stateHandlers, + mockConfig: { + http: { + baseUrlUnderTest: `http://localhost:${port}`, + }, + }, + }, + (contract) => { + describe('health get', () => { + describe('When the server is up', () => { + const state = inState('Server is up'); + + describe('health endpoint', () => { + it('behaves as expected', () => + contract.runInteraction({ + states: [state], + definition: willReceiveHttpRequest({ + request: { + method: 'GET', + path: '/health', + headers: { accept: 'application/json' }, + }, + response: { status: 200, body: { status: 'up' } }, + }), + })); + + describe('arbitrary status response string', () => { + it('behaves as expected', () => + contract.runInteraction({ + states: [state], + definition: willReceiveHttpRequest({ + request: { + method: 'GET', + path: '/health', + }, + response: { + status: 200, + body: shapedLike({ status: 'whatever' }), + }, + }), + })); + }); + }); + }); + describe('When the server is down', () => { + const state = inState('Server is down'); + describe('No body server response', () => { + it('calls server health', () => + contract.runRejectingInteraction({ + states: [state], + definition: willReceiveHttpRequest({ + request: { + method: 'GET', + path: '/health', + }, + response: { status: httpStatus(['4XX', '5XX']) }, + }), + })); + }); + + describe('specific server response', () => { + it('calls server health', async () => + contract.runRejectingInteraction({ + states: [state], + definition: willReceiveHttpRequest({ + request: { + method: 'GET', + path: '/health', + }, + response: { status: 503, body: { status: 'down' } }, + }), + })); + }); + }); + }); + describe('User', () => { + describe('With query variables', () => { + describe('when the user exists', () => { + const responseBody = { userId: stateVariable('userId') }; + + it('returns an existing user', async () => + contract.runInteraction({ + states: [ + inState('Server is up'), + inState('A user exists', { userId: '123' }), + ], + definition: willReceiveHttpRequest({ + request: { + method: 'GET', + path: '/users', + query: { id: stateVariable('userId') }, + }, + response: { + status: 200, + body: responseBody, + }, + }), + })); + }); + describe("when the user doesn't exist", () => { + it('returns a user not found error', () => + contract.runRejectingInteraction({ + states: [ + inState('Server is up'), + inState('No users exist', { userId: '123' }), + ], + definition: willReceiveHttpRequest({ + request: { + method: 'GET', + path: '/users', + query: { id: stateVariable('userId') }, + }, + response: { + status: 404, + }, + }), + })); + }); + }); + describe('with path variables', () => { + describe('when the user exists', () => { + const responseBody = { userId: stateVariable('userId') }; + + it('returns an existing user', async () => + contract.runInteraction({ + states: [ + inState('Server is up'), + inState('A user exists', { userId: '123' }), + ], + definition: willReceiveHttpRequest({ + request: { + method: 'GET', + path: stringPrefix('/users/', stateVariable('userId')), + }, + response: { + status: 200, + body: responseBody, + }, + }), + })); + }); + describe("when the user doesn't exist", () => { + it('returns a user not found error', () => + contract.runRejectingInteraction({ + states: [ + inState('Server is up'), + inState('No users exist', { userId: '123' }), + ], + definition: willReceiveHttpRequest({ + request: { + method: 'GET', + path: stringPrefix('/users/', '123'), + }, + response: { + status: 404, + }, + }), + })); + }); + }); + }); + }, + ); + }); +}); diff --git a/packages/contract-case-dsl-js-vitest/src/index.http.server.spec.verify.ts b/packages/contract-case-dsl-js-vitest/src/index.http.server.spec.verify.ts new file mode 100644 index 000000000..a72323c97 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/index.http.server.spec.verify.ts @@ -0,0 +1,132 @@ +import { expect } from 'vitest'; + +import api from './__tests__/client/http.js'; +import { UserNotFoundConsumerError } from './__tests__/client/entities/errors.js'; +import { ApiError } from './__tests__/client/entities/apiErrors.js'; + +import { verifyContract, TriggerGroupMap } from './index.js'; +import type { HttpRequestConfig } from './index.js'; + +verifyContract({ + providerName: 'http request provider', + + triggers: new TriggerGroupMap() + .addTriggerGroup('an http "GET" request to "/health" without a body', { + trigger: (setup: HttpRequestConfig) => api(setup.mock.baseUrl).health(), + testResponses: { + 'returns a (200) response with body an object shaped like {status: }': + (health) => expect(typeof health).toBe('string'), + 'a (200) response with body an object shaped like {status: }': + (health) => expect(typeof health).toBe('string'), + }, + testErrorResponses: { + 'returns a (httpStatus 4XX | 5XX) response without a body': (e) => { + expect(e).toBeInstanceOf(ApiError); + }, + 'returns a (503) response with body an object shaped like {status: "down"}': + (e) => { + expect(e).toBeInstanceOf(ApiError); + }, + 'a (httpStatus 4XX | 5XX) response without a body': (e) => { + expect(e).toBeInstanceOf(ApiError); + }, + 'a (503) response with body an object shaped like {status: "down"}': ( + e, + ) => { + expect(e).toBeInstanceOf(ApiError); + }, + }, + }) + .addTriggerGroup( + 'an http "GET" request to "/health" with the following headers an object shaped like {accept: "application/json"} without a body', + { + trigger: (config: HttpRequestConfig) => + api(config.mock.baseUrl).health(), + testResponses: { + 'returns a (200) response with body an object shaped like {status: "up"}': + (health) => { + expect(health).toEqual('up'); + }, + 'a (200) response with body an object shaped like {status: "up"}': ( + health, + ) => { + expect(health).toEqual('up'); + }, + }, + }, + ) + .addTriggerGroup( + 'an http "GET" request to "/users"?id={{userId}} without a body', + { + trigger: (setup: HttpRequestConfig) => + api(setup.mock.baseUrl).getUserByQuery( + setup.getStateVariable('userId'), + ), + testResponses: { + 'returns a (200) response with body an object shaped like {userId: {{userId}}}': + (user, setup) => { + expect(user).toEqual({ + userId: setup.getStateVariable('userId'), + }); + }, + 'a (200) response with body an object shaped like {userId: {{userId}}}': + (user, setup) => { + expect(user).toEqual({ + userId: setup.getStateVariable('userId'), + }); + }, + }, + testErrorResponses: { + 'returns a (404) response without a body': (e) => { + expect(e).toBeInstanceOf(UserNotFoundConsumerError); + }, + 'a (404) response without a body': (e) => { + expect(e).toBeInstanceOf(UserNotFoundConsumerError); + }, + }, + }, + ) + .addTriggerGroup('an http "GET" request to "/users/123" without a body', { + trigger: (config: HttpRequestConfig) => + api(config.mock.baseUrl).getUserByPath('123'), + testErrorResponses: { + 'returns a (404) response without a body': (e) => { + expect(e).toBeInstanceOf(UserNotFoundConsumerError); + }, + 'a (404) response without a body': (e) => { + expect(e).toBeInstanceOf(UserNotFoundConsumerError); + }, + }, + }) + .addTriggerGroup( + 'an http "GET" request to "/users/{{userId}}" without a body', + { + trigger: (setup: HttpRequestConfig) => + api(setup.mock.baseUrl).getUserByPath( + setup.getStateVariable('userId'), + ), + testResponses: { + 'returns a (200) response with body an object shaped like {userId: {{userId}}}': + (user, setup) => { + expect(user).toEqual({ + userId: setup.getStateVariable('userId'), + }); + }, + 'a (200) response with body an object shaped like {userId: {{userId}}}': + (user, setup) => { + expect(user).toEqual({ + userId: setup.getStateVariable('userId'), + }); + }, + }, + testErrorResponses: { + 'returns a (404) response without a body': (e) => { + expect(e).toBeInstanceOf(UserNotFoundConsumerError); + }, + 'a (404) response without a body': (e) => { + expect(e).toBeInstanceOf(UserNotFoundConsumerError); + }, + }, + }, + ), +}); diff --git a/packages/contract-case-dsl-js-vitest/src/index.ts b/packages/contract-case-dsl-js-vitest/src/index.ts new file mode 100644 index 000000000..9465ae64b --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/src/index.ts @@ -0,0 +1,29 @@ +import type { InteractionSetup } from '@contract-case/contract-case-dsl-js'; + +/*! + * ContractCase Vitest DSL + * Copyright(c) 2022-2024 Timothy Jones (TLJ) + * BSD-3-Clause license + */ + +// Re-export all shared DSL code +export * from '@contract-case/contract-case-dsl-js'; + +// Re-export vitest-specific bindings +export * from './boundaries/index.js'; + +// Namespace re-exports for backward compatibility +export * as dsl from '@contract-case/contract-case-dsl-js'; +export * as TestEquivalenceMatchers from '@contract-case/contract-case-dsl-js'; + +process.env['CASE_CONNECTOR_CLIENT'] = 'contract-case-vitest'; + +// TODO remove this hack type and do it properly +export type HttpRequestConfig = InteractionSetup<{ + baseUrl: string; +}>; + +// TODO remove this hack type too, and also do it properly +export type FunctionExecutorConfig = InteractionSetup<{ + functionHandle: string; +}>; diff --git a/packages/contract-case-dsl-js-vitest/tsconfig.build.json b/packages/contract-case-dsl-js-vitest/tsconfig.build.json new file mode 100644 index 000000000..77cae7cf0 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "extends": "@contract-case/case-maintainer-config/tsconfig.json", + "compilerOptions": { + "outDir": "dist/", + "module": "nodenext", + "moduleResolution": "nodenext" + }, + "include": ["src/**/*.ts"], + "exclude": [ + "src/**/*.spec.ts", + "src/**/*.spec.verify.ts", + "src/**/*.test.ts", + "dist/**/*.js", + "coverage" + ] +} diff --git a/packages/contract-case-dsl-js-vitest/tsconfig.json b/packages/contract-case-dsl-js-vitest/tsconfig.json new file mode 100644 index 000000000..81084cd89 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@contract-case/case-maintainer-config/tsconfig.json", + "compilerOptions": { + "outDir": "dist/" + }, + "exclude": ["vitest.config.ts", "dist/**/*.js", "coverage"] +} diff --git a/packages/contract-case-dsl-js-vitest/vitest.config.ts b/packages/contract-case-dsl-js-vitest/vitest.config.ts new file mode 100644 index 000000000..c3523a4f8 --- /dev/null +++ b/packages/contract-case-dsl-js-vitest/vitest.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + clearMocks: true, + coverage: { + provider: 'v8', + }, + environment: 'node', + include: [ + 'src/**/*.{test,spec}.{js,ts}', + 'src/**/*.spec.verify.ts', + ], + exclude: ['**/node_modules/**', '**/dist/**'], + }, +}); diff --git a/packages/contract-case-dsl-js/eslint.config.mjs b/packages/contract-case-dsl-js/eslint.config.mjs new file mode 100644 index 000000000..83c0f6f37 --- /dev/null +++ b/packages/contract-case-dsl-js/eslint.config.mjs @@ -0,0 +1,3 @@ +import lintConfig from '@contract-case/eslint-config-case-maintainer'; + +export default [...lintConfig]; diff --git a/packages/contract-case-dsl-js/package.json b/packages/contract-case-dsl-js/package.json new file mode 100644 index 000000000..c52f1175f --- /dev/null +++ b/packages/contract-case-dsl-js/package.json @@ -0,0 +1,66 @@ +{ + "name": "@contract-case/contract-case-dsl-js", + "version": "0.29.1", + "description": "User-facing DSL for ContractCase contract testing in JavaScript/TypeScript", + "keywords": [ + "testing", + "api", + "pact", + "contracttesting", + "contract-testing", + "contractcase" + ], + "author": "Timothy Jones (https://github.com/TimothyJones)", + "homepage": "https://case.contract-testing.io", + "license": "BSD-3-Clause", + "main": "./dist/src/index.js", + "types": "./dist/src/index.d.ts", + "directories": { + "src": "src", + "dist": "dist" + }, + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/case-contract-testing/case.git" + }, + "scripts": { + "build": "rimraf dist && tsc --project tsconfig.build.json", + "lint": "eslint", + "lint:fix": "eslint --fix", + "format:base": "prettier --parser typescript \"src/**/*.ts\"", + "format:check": "npm run format:base -- --list-different", + "format:fix": "npm run format:base -- --write " + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/TimothyJones" + }, + "engines": { + "node": ">=14.21.2" + }, + "bugs": { + "url": "https://github.com/case-contract-testing/case/issues" + }, + "devDependencies": { + "@contract-case/eslint-config-case-maintainer": "0.29.1", + "eslint": "^9.39.1", + "prettier": "3.6.2", + "rimraf": "^6.1.2", + "typescript": "5.9.3" + }, + "dependencies": { + "@contract-case/contract-case-dsl-js-internals": "0.29.1", + "@contract-case/case-connector": "0.29.1", + "@contract-case/case-core-plugin-http-dsl": "0.29.1", + "@contract-case/case-definition-dsl": "0.29.1", + "@contract-case/case-entities-internal": "0.29.1", + "@contract-case/case-plugin-base": "0.29.1", + "@contract-case/case-plugin-dsl-types": "0.29.1" + } +} diff --git a/packages/contract-case-jest/src/boundaries/dsl/Interactions/index.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Interactions/index.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/Interactions/index.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Interactions/index.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/arrays.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/arrays.ts similarity index 95% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/arrays.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/arrays.ts index 4c7dbb235..27124d6ee 100644 --- a/packages/contract-case-jest/src/boundaries/dsl/Matchers/arrays.ts +++ b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/arrays.ts @@ -7,11 +7,11 @@ import { ARRAY_CONTAINS_TYPE, CoreShapedArrayMatcher, } from '@contract-case/case-entities-internal'; +import { ContractCaseConfigurationError } from '@contract-case/contract-case-dsl-js-internals'; import { coreArrayLengthMatcher, coreShapedArrayMatcher, } from './core/index.js'; -import { ContractCaseConfigurationError } from '../../../entities/errors/ContractCaseConfigurationError.js'; type ArrayLengthOptions = { minLength?: number; maxLength?: number }; diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/auth.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/auth.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/auth.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/auth.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/core/auxiliary.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/auxiliary.ts similarity index 97% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/core/auxiliary.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/auxiliary.ts index cc30970ea..ffc4c857d 100644 --- a/packages/contract-case-jest/src/boundaries/dsl/Matchers/core/auxiliary.ts +++ b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/auxiliary.ts @@ -37,7 +37,7 @@ export const coreAndMatcher = ( * @param content - The example object, array, primitive or matcher to match against */ export const coreShapedLike = ( - content: AnyCaseMatcherOrData + content: AnyCaseMatcherOrData, ): CoreCascadingMatcher & MatchContextByType => ({ '_case:matcher:type': CASCADING_CONTEXT_MATCHER_TYPE, '_case:matcher:child': content, diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/core/http/index.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/http/index.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/core/http/index.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/http/index.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/core/http/matcher.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/http/matcher.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/core/http/matcher.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/http/matcher.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/core/http/types.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/http/types.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/core/http/types.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/http/types.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/core/http/validator.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/http/validator.ts similarity index 92% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/core/http/validator.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/http/validator.ts index 62b27a92d..4654be129 100644 --- a/packages/contract-case-jest/src/boundaries/dsl/Matchers/core/http/validator.ts +++ b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/http/validator.ts @@ -1,4 +1,4 @@ -import { ContractCaseConfigurationError } from '../../../../../entities/errors/ContractCaseConfigurationError.js'; +import { ContractCaseConfigurationError } from '@contract-case/contract-case-dsl-js-internals'; const validateCodeNumber = (code: number): number => { if (code < 100 || code >= 600) { diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/core/index.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/index.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/core/index.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/index.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/core/leaf.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/leaf.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/core/leaf.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/leaf.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/core/structure.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/structure.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/core/structure.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/core/structure.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/http.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/http.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/http.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/http.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/index.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/index.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/index.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/index.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/meta.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/meta.ts similarity index 98% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/meta.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/meta.ts index 4aa7da6d7..22349c5f9 100644 --- a/packages/contract-case-jest/src/boundaries/dsl/Matchers/meta.ts +++ b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/meta.ts @@ -14,13 +14,13 @@ import { LookupableMatcher, ResolvesTo, } from '@contract-case/case-plugin-dsl-types'; +import type { LogLevel } from '@contract-case/contract-case-dsl-js-internals'; import { coreLookupMatcherRequest, coreAndMatcher, coreLookupMatcher, coreShapedLike, } from './core/index.js'; -import { LogLevel } from '../../../entities/config.js'; /** * Meta matcher that matches all matchers provided. Use this to combine matching rules for the same element diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/objects.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/objects.ts similarity index 93% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/objects.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/objects.ts index bd9b65dbb..4fc1d3474 100644 --- a/packages/contract-case-jest/src/boundaries/dsl/Matchers/objects.ts +++ b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/objects.ts @@ -14,7 +14,7 @@ import { */ export const objectEachValueMatches = ( matcher: AnyCaseMatcherOrData, - example?: Record + example?: Record, ): CoreObjectValuesMatch => ({ '_case:matcher:type': OBJECT_VALUES_MATCH_TYPE, '_case:matcher:matcher': matcher, @@ -29,7 +29,7 @@ export const objectEachValueMatches = ( */ export const objectEachKeyMatches = ( matcher: AnyCaseMatcherOrData, - exampleKey?: string + exampleKey?: string, ): CoreObjectKeysMatcher => ({ '_case:matcher:type': OBJECT_KEYS_MATCH_TYPE, '_case:matcher:matcher': matcher, diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/primitives.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/primitives.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/primitives.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/primitives.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/strings.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/strings.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/strings.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/strings.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/Matchers/types.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/types.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/Matchers/types.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/Matchers/types.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/States/index.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/States/index.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/States/index.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/States/index.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/States/states.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/States/states.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/States/states.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/States/states.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/index.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/index.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/index.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/index.ts diff --git a/packages/contract-case-jest/src/boundaries/dsl/types.ts b/packages/contract-case-dsl-js/src/boundaries/dsl/types.ts similarity index 100% rename from packages/contract-case-jest/src/boundaries/dsl/types.ts rename to packages/contract-case-dsl-js/src/boundaries/dsl/types.ts diff --git a/packages/contract-case-jest/src/connectors/ContractDefiner.ts b/packages/contract-case-dsl-js/src/connectors/ContractDefiner.ts similarity index 94% rename from packages/contract-case-jest/src/connectors/ContractDefiner.ts rename to packages/contract-case-dsl-js/src/connectors/ContractDefiner.ts index 93e8e014c..7373a0b1e 100644 --- a/packages/contract-case-jest/src/connectors/ContractDefiner.ts +++ b/packages/contract-case-dsl-js/src/connectors/ContractDefiner.ts @@ -5,24 +5,23 @@ import { } from '@contract-case/case-connector/cjs'; import { interactions } from '@contract-case/case-definition-dsl'; -import { defaultPrinter } from './defaultTestPrinter.js'; - -import { - ContractCaseConfig, - ContractWriteSuccess, - IndividualFailedTestConfig, - IndividualSuccessTestConfig, - versionString, -} from '../entities/index.js'; import { + defaultPrinter, mapSuccess, mapConfig, mapSuccessConfig, mapFailingConfig, mapSuccessWithAny, mapInvokeableFunction, -} from './case-boundary/index.js'; -import { errorHandler } from './handler.js'; + errorHandler, + versionString, +} from '@contract-case/contract-case-dsl-js-internals'; +import type { + ContractCaseConfig, + ContractWriteSuccess, + IndividualFailedTestConfig, + IndividualSuccessTestConfig, +} from '@contract-case/contract-case-dsl-js-internals'; const mapDefinition = ( definition: ExampleDefinition, diff --git a/packages/contract-case-jest/src/connectors/ContractVerifier.ts b/packages/contract-case-dsl-js/src/connectors/ContractVerifier.ts similarity index 95% rename from packages/contract-case-jest/src/connectors/ContractVerifier.ts rename to packages/contract-case-dsl-js/src/connectors/ContractVerifier.ts index 45dddf908..45a897b1f 100644 --- a/packages/contract-case-jest/src/connectors/ContractVerifier.ts +++ b/packages/contract-case-dsl-js/src/connectors/ContractVerifier.ts @@ -2,24 +2,25 @@ import { BoundaryContractVerifier, BoundaryInvokableFunction, } from '@contract-case/case-connector/cjs'; -import { defaultPrinter } from './defaultTestPrinter.js'; import { + defaultPrinter, mapSuccess, mapConfig, mapSuccessWithAny, mapInvokeableFunction, mapContractVerificationHandles, -} from './case-boundary/index.js'; -import { + errorHandler, + errorReporter, ContractCaseConfigurationError, + versionString, +} from '@contract-case/contract-case-dsl-js-internals'; +import type { ContractCaseVerifierConfig, ContractDescription, VerificationHandle, VerificationTestHandle, - versionString, -} from '../entities/index.js'; -import { errorHandler, errorReporter } from './handler.js'; +} from '@contract-case/contract-case-dsl-js-internals'; export class ContractVerifier { private boundaryVerifier: BoundaryContractVerifier; diff --git a/packages/contract-case-jest/src/connectors/TriggerGroup.ts b/packages/contract-case-dsl-js/src/connectors/TriggerGroup.ts similarity index 73% rename from packages/contract-case-jest/src/connectors/TriggerGroup.ts rename to packages/contract-case-dsl-js/src/connectors/TriggerGroup.ts index d8ca30c83..44de63c0f 100644 --- a/packages/contract-case-jest/src/connectors/TriggerGroup.ts +++ b/packages/contract-case-dsl-js/src/connectors/TriggerGroup.ts @@ -1,4 +1,8 @@ -import { Groups, TriggerGroups, TriggerGroup } from '../entities/index.js'; +import type { + Groups, + TriggerGroups, + TriggerGroup, +} from '@contract-case/contract-case-dsl-js-internals'; export class TriggerGroupMap implements TriggerGroups { groups: Groups = {}; diff --git a/packages/contract-case-dsl-js/src/index.ts b/packages/contract-case-dsl-js/src/index.ts new file mode 100644 index 000000000..76c7d9b53 --- /dev/null +++ b/packages/contract-case-dsl-js/src/index.ts @@ -0,0 +1,50 @@ +/*! + * ContractCase DSL JS - User-facing DSL for ContractCase test framework bindings + * Copyright(c) 2022-2024 Timothy Jones (TLJ) + * BSD-3-Clause license + */ + +export { ContractCaseDefiner } from './connectors/ContractDefiner.js'; +export type { ExampleDefinition } from './connectors/ContractDefiner.js'; +export { ContractVerifier } from './connectors/ContractVerifier.js'; +export { TriggerGroupMap } from './connectors/TriggerGroup.js'; + +export * from './boundaries/dsl/index.js'; + +export * as Matchers from './boundaries/dsl/Matchers/index.js'; +export * as Interactions from './boundaries/dsl/Interactions/index.js'; +export * as States from './boundaries/dsl/States/index.js'; + +// Re-export entity types from connector-js +export type { + ContractCaseConfig, + ContractCaseVerifierConfig, + IndividualSuccessTestConfig, + IndividualFailedTestConfig, + LogLevel, + UserNamePassword, + SetupFunction, + TeardownFunction, + ContractWriteSuccess, + StateHandler, + StateHandlers, + ContractDescription, + VerificationTestHandle, + ContractMetadata, + VerificationHandle, + InteractionSetup, + Trigger, + TestResponseFunction, + TestErrorResponseFunction, + TriggerGroup, + TriggerGroups, + Groups, + InferredTriggerPair, +} from '@contract-case/contract-case-dsl-js-internals'; + +export { + ContractCaseConfigurationError, + ContractCaseCoreError, + ContractCaseExpectationsNotMet, + versionString, +} from '@contract-case/contract-case-dsl-js-internals'; diff --git a/packages/contract-case-dsl-js/tsconfig.build.json b/packages/contract-case-dsl-js/tsconfig.build.json new file mode 100644 index 000000000..9084ff334 --- /dev/null +++ b/packages/contract-case-dsl-js/tsconfig.build.json @@ -0,0 +1,15 @@ +{ + "extends": "@contract-case/case-maintainer-config/tsconfig.json", + "compilerOptions": { + "outDir": "dist/", + "module": "nodenext", + "moduleResolution": "nodenext" + }, + "include": ["src/**/*.ts"], + "exclude": [ + "src/**/*.spec.ts", + "src/**/*.test.ts", + "dist/**/*.js", + "coverage" + ] +} diff --git a/packages/contract-case-dsl-js/tsconfig.json b/packages/contract-case-dsl-js/tsconfig.json new file mode 100644 index 000000000..9ec8df590 --- /dev/null +++ b/packages/contract-case-dsl-js/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@contract-case/case-maintainer-config/tsconfig.json", + "compilerOptions": { + "outDir": "dist/" + }, + "exclude": ["dist/**/*.js", "coverage"] +} diff --git a/packages/contract-case-jest/dist/bin/ContractCase.mjs b/packages/contract-case-jest/dist/bin/ContractCase.mjs deleted file mode 100755 index 73bad3aff..000000000 --- a/packages/contract-case-jest/dist/bin/ContractCase.mjs +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ts-node -import '@contract-case/cli'; -//# sourceMappingURL=ContractCase.mjs.map \ No newline at end of file diff --git a/packages/contract-case-jest/src/connectors/case-boundary/mappers/config/state/index.ts b/packages/contract-case-jest/src/connectors/case-boundary/mappers/config/state/index.ts deleted file mode 100644 index 29ec84ba4..000000000 --- a/packages/contract-case-jest/src/connectors/case-boundary/mappers/config/state/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './state.js'; diff --git a/packages/documentation/docs/defining-contracts/intro.mdx b/packages/documentation/docs/defining-contracts/intro.mdx index cad9d6261..26e4c9cbf 100644 --- a/packages/documentation/docs/defining-contracts/intro.mdx +++ b/packages/documentation/docs/defining-contracts/intro.mdx @@ -48,7 +48,7 @@ have completed. This tells ContractCase to write the contract file to disk. ``` // With Typescript/Javascript, there is no need // to explicitly end the contract as the - // `defineContract` Jest DSL handles this for you + // `defineContract` Jest/Vitest DSL handles this for you ``` diff --git a/packages/documentation/docs/examples/_install_js.mdx b/packages/documentation/docs/examples/_install_js.mdx index dcee448b7..64b2e7ac3 100644 --- a/packages/documentation/docs/examples/_install_js.mdx +++ b/packages/documentation/docs/examples/_install_js.mdx @@ -1,3 +1,11 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +ContractCase works with both Jest and Vitest. Install the package for your test runner: + + + + ```bash npm install --save-dev @contract-case/contract-case-jest @@ -5,3 +13,17 @@ npm install --save-dev @contract-case/contract-case-jest npm install --save-dev jest@^29.4.3 ``` + + + + +```bash +npm install --save-dev @contract-case/contract-case-dsl-js-vitest + +# You may also need the peer dependencies: + +npm install --save-dev vitest@^3.0.0 +``` + + + diff --git a/packages/documentation/docs/getting-started.mdx b/packages/documentation/docs/getting-started.mdx index e3ae145f7..d22f8d027 100644 --- a/packages/documentation/docs/getting-started.mdx +++ b/packages/documentation/docs/getting-started.mdx @@ -39,10 +39,19 @@ Here's the lifecycle of a contract test: If you just want to jump in to some examples, you can have a read of: -* Typescript [client-driven contract definition](https://github.com/case-contract-testing/contract-case/blob/main/packages/contract-case-jest/src/index.http.client.define.spec.ts) -* Typescript [client-driven contract verification](https://github.com/case-contract-testing/contract-case/blob/main/packages/contract-case-jest/src/index.http.client.spec.verify.ts) -* Typescript [server-driven contract definition](https://github.com/case-contract-testing/contract-case/blob/main/packages/contract-case-jest/src/index.http.server.define.spec.ts) -* Typescript [server-driven contract verification](https://github.com/case-contract-testing/contract-case/blob/main/packages/contract-case-jest/src/index.http.server.spec.verify.ts) +Jest: + +* Typescript [client-driven contract definition](https://github.com/case-contract-testing/contract-case/blob/main/packages/contract-case-dsl-js-jest/src/index.http.client.define.spec.ts) +* Typescript [client-driven contract verification](https://github.com/case-contract-testing/contract-case/blob/main/packages/contract-case-dsl-js-jest/src/index.http.client.spec.verify.ts) +* Typescript [server-driven contract definition](https://github.com/case-contract-testing/contract-case/blob/main/packages/contract-case-dsl-js-jest/src/index.http.server.define.spec.ts) +* Typescript [server-driven contract verification](https://github.com/case-contract-testing/contract-case/blob/main/packages/contract-case-dsl-js-jest/src/index.http.server.spec.verify.ts) + +Vitest: + +* Typescript [client-driven contract definition](https://github.com/case-contract-testing/contract-case/blob/main/packages/contract-case-dsl-js-vitest/src/index.http.client.define.spec.ts) +* Typescript [client-driven contract verification](https://github.com/case-contract-testing/contract-case/blob/main/packages/contract-case-dsl-js-vitest/src/index.http.client.spec.verify.ts) +* Typescript [server-driven contract definition](https://github.com/case-contract-testing/contract-case/blob/main/packages/contract-case-dsl-js-vitest/src/index.http.server.define.spec.ts) +* Typescript [server-driven contract verification](https://github.com/case-contract-testing/contract-case/blob/main/packages/contract-case-dsl-js-vitest/src/index.http.server.spec.verify.ts) If you're new to contract testing, have a read of [what is contract testing](./what-is-contract-testing/). diff --git a/packages/dsl-java/src/test/java/io/contract_testing/contractcase/test/httpclient/JestHttpApiExampleVerifyTest.java b/packages/dsl-java/src/test/java/io/contract_testing/contractcase/test/httpclient/JestHttpApiExampleVerifyTest.java index 157f51e3e..c852bdd07 100644 --- a/packages/dsl-java/src/test/java/io/contract_testing/contractcase/test/httpclient/JestHttpApiExampleVerifyTest.java +++ b/packages/dsl-java/src/test/java/io/contract_testing/contractcase/test/httpclient/JestHttpApiExampleVerifyTest.java @@ -29,7 +29,7 @@ public class JestHttpApiExampleVerifyTest { // TODO: This contract must have the wrong name? Confirm and correct this .providerName("http request provider") .publish(PublishType.NEVER) - .contractDir("../contract-case-jest/case-contracts/http-request-provider/") + .contractDir("../contract-case-dsl-js-jest/case-contracts/http-request-provider/") .build()); Trigger getHealth = (setupInfo) -> { diff --git a/release-please-config.json b/release-please-config.json index 687b32532..bf73b8d3c 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -18,7 +18,10 @@ "@contract-case/case-definition-generator", "@contract-case/cli", "documentation", + "@contract-case/contract-case-dsl-js-internals", + "@contract-case/contract-case-dsl-js", "@contract-case/contract-case-jest", + "@contract-case/contract-case-dsl-js-vitest", "@contract-case/case-connector", "@contract-case/case-connector-proto", "@contract-case/case-maintainer-config", @@ -144,13 +147,34 @@ { "type": "ci", "section": "Continuous Integration", "hidden": true } ] }, - "packages/contract-case-jest": { + "packages/contract-case-dsl-js-internals": { + "component": "@contract-case/contract-case-dsl-js-internals", + "extra-files": ["package.json"], + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": true, + "changelog-path": "CHANGELOG.md" + }, + "packages/contract-case-dsl-js": { + "component": "@contract-case/contract-case-dsl-js", + "extra-files": ["package.json"], + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": true, + "changelog-path": "CHANGELOG.md" + }, + "packages/contract-case-dsl-js-jest": { "component": "@contract-case/contract-case-jest", "extra-files": ["src/entities/versionString.ts", "package.json"], "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": true, "changelog-path": "CHANGELOG.md" }, + "packages/contract-case-dsl-js-vitest": { + "component": "@contract-case/contract-case-dsl-js-vitest", + "extra-files": ["package.json"], + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": true, + "changelog-path": "CHANGELOG.md" + }, "packages/case-connector": { "component": "@contract-case/case-connector", "extra-files": ["src/entities/versionString.ts", "package.json"], diff --git a/tsconfig.json b/tsconfig.json index 9413a097e..a2477c13e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,10 @@ { "path": "./packages/case-plugin-base" }, { "path": "./packages/case-plugin-dsl-types" }, { "path": "./packages/contract-case-cli" }, - { "path": "./packages/contract-case-jest" }, + { "path": "./packages/contract-case-dsl-js-internals" }, + { "path": "./packages/contract-case-dsl-js" }, + { "path": "./packages/contract-case-dsl-js-jest" }, + { "path": "./packages/contract-case-dsl-js-vitest" }, { "path": "./packages/documentation-matchers-generator" } ] }