diff --git a/CHANGELOG.md b/CHANGELOG.md
index e39ba92..59d4130 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.1.10 (2026-04-21)
+
+* fix: forward mock Content-Type to contract validator (avoids false-positive `MISSING_SCHEMA` for binary mocks)
+
## 1.1.9 (2026-04-15)
* chore: update twd-js to 1.7.1
diff --git a/package-lock.json b/package-lock.json
index a9b358c..f54e12c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,17 +1,17 @@
{
"name": "twd-cli",
- "version": "1.1.9",
+ "version": "1.1.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "twd-cli",
- "version": "1.1.9",
+ "version": "1.1.10",
"license": "ISC",
"dependencies": {
- "openapi-mock-validator": "^0.1.4",
- "puppeteer": "^24.41.0",
- "twd-js": "^1.7.1"
+ "openapi-mock-validator": "^0.2.0",
+ "puppeteer": "^24.42.0",
+ "twd-js": "^1.7.2"
},
"bin": {
"twd-cli": "bin/twd-cli.js"
@@ -129,9 +129,9 @@
}
},
"node_modules/@conventional-changelog/git-client": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.6.0.tgz",
- "integrity": "sha512-T+uPDciKf0/ioNNDpMGc8FDsehJClZP0yR3Q5MN6wE/Y/1QZ7F+80OgznnTCOlMEG4AV0LvH2UJi3C/nBnaBUg==",
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.7.0.tgz",
+ "integrity": "sha512-j7A8/LBEQ+3rugMzPXoKYzyUPpw/0CBQCyvtTR7Lmu4olG4yRC/Tfkq79Mr3yuPs0SUitlO2HwGP3gitMJnRFw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -144,7 +144,7 @@
},
"peerDependencies": {
"conventional-commits-filter": "^5.0.0",
- "conventional-commits-parser": "^6.3.0"
+ "conventional-commits-parser": "^6.4.0"
},
"peerDependenciesMeta": {
"conventional-commits-filter": {
@@ -220,9 +220,9 @@
}
},
"node_modules/@napi-rs/wasm-runtime": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.3.tgz",
- "integrity": "sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==",
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
+ "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -239,9 +239,9 @@
}
},
"node_modules/@oxc-project/types": {
- "version": "0.124.0",
- "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz",
- "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==",
+ "version": "0.126.0",
+ "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.126.0.tgz",
+ "integrity": "sha512-oGfVtjAgwQVVpfBrbtk4e1XDyWHRFta6BS3GWVzrF8xYBT2VGQAk39yJS/wFSMrZqoiCU4oghT3Ch0HaHGIHcQ==",
"dev": true,
"license": "MIT",
"funding": {
@@ -270,9 +270,9 @@
}
},
"node_modules/@rolldown/binding-android-arm64": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz",
- "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.16.tgz",
+ "integrity": "sha512-rhY3k7Bsae9qQfOtph2Pm2jZEA+s8Gmjoz4hhmx70K9iMQ/ddeae+xhRQcM5IuVx5ry1+bGfkvMn7D6MJggVSA==",
"cpu": [
"arm64"
],
@@ -287,9 +287,9 @@
}
},
"node_modules/@rolldown/binding-darwin-arm64": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz",
- "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.16.tgz",
+ "integrity": "sha512-rNz0yK078yrNn3DrdgN+PKiMOW8HfQ92jQiXxwX8yW899ayV00MLVdaCNeVBhG/TbH3ouYVObo8/yrkiectkcQ==",
"cpu": [
"arm64"
],
@@ -304,9 +304,9 @@
}
},
"node_modules/@rolldown/binding-darwin-x64": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz",
- "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.16.tgz",
+ "integrity": "sha512-r/OmdR00HmD4i79Z//xO06uEPOq5hRXdhw7nzkxQxwSavs3PSHa1ijntdpOiZ2mzOQ3fVVu8C1M19FoNM+dMUQ==",
"cpu": [
"x64"
],
@@ -321,9 +321,9 @@
}
},
"node_modules/@rolldown/binding-freebsd-x64": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz",
- "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.16.tgz",
+ "integrity": "sha512-KcRE5w8h0OnjUatG8pldyD14/CQ5Phs1oxfR+3pKDjboHRo9+MkqQaiIZlZRpsxC15paeXme/I127tUa9TXJ6g==",
"cpu": [
"x64"
],
@@ -338,9 +338,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz",
- "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.16.tgz",
+ "integrity": "sha512-bT0guA1bpxEJ/ZhTRniQf7rNF8ybvXOuWbNIeLABaV5NGjx4EtOWBTSRGWFU9ZWVkPOZ+HNFP8RMcBokBiZ0Kg==",
"cpu": [
"arm"
],
@@ -355,9 +355,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm64-gnu": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz",
- "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.16.tgz",
+ "integrity": "sha512-+tHktCHWV8BDQSjemUqm/Jl/TPk3QObCTIjmdDy/nlupcujZghmKK2962LYrqFpWu+ai01AN/REOH3NEpqvYQg==",
"cpu": [
"arm64"
],
@@ -372,9 +372,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm64-musl": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz",
- "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.16.tgz",
+ "integrity": "sha512-3fPzdREH806oRLxpTWW1Gt4tQHs0TitZFOECB2xzCFLPKnSOy90gwA7P29cksYilFO6XVRY1kzga0cL2nRjKPg==",
"cpu": [
"arm64"
],
@@ -389,9 +389,9 @@
}
},
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz",
- "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.16.tgz",
+ "integrity": "sha512-EKwI1tSrLs7YVw+JPJT/G2dJQ1jl9qlTTTEG0V2Ok/RdOenRfBw2PQdLPyjhIu58ocdBfP7vIRN/pvMsPxs/AQ==",
"cpu": [
"ppc64"
],
@@ -406,9 +406,9 @@
}
},
"node_modules/@rolldown/binding-linux-s390x-gnu": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz",
- "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.16.tgz",
+ "integrity": "sha512-Uknladnb3Sxqu6SEcqBldQyJUpk8NleooZEc0MbRBJ4inEhRYWZX0NJu12vNf2mqAq7gsofAxHrGghiUYjhaLQ==",
"cpu": [
"s390x"
],
@@ -423,9 +423,9 @@
}
},
"node_modules/@rolldown/binding-linux-x64-gnu": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz",
- "integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.16.tgz",
+ "integrity": "sha512-FIb8+uG49sZBtLTn+zt1AJ20TqVcqWeSIyoVt0or7uAWesgKaHbiBh6OpA/k9v0LTt+PTrb1Lao133kP4uVxkg==",
"cpu": [
"x64"
],
@@ -440,9 +440,9 @@
}
},
"node_modules/@rolldown/binding-linux-x64-musl": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz",
- "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.16.tgz",
+ "integrity": "sha512-RuERhF9/EgWxZEXYWCOaViUWHIboceK4/ivdtQ3R0T44NjLkIIlGIAVAuCddFxsZ7vnRHtNQUrt2vR2n2slB2w==",
"cpu": [
"x64"
],
@@ -457,9 +457,9 @@
}
},
"node_modules/@rolldown/binding-openharmony-arm64": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz",
- "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.16.tgz",
+ "integrity": "sha512-mXcXnvd9GpazCxeUCCnZ2+YF7nut+ZOEbE4GtaiPtyY6AkhZWbK70y1KK3j+RDhjVq5+U8FySkKRb/+w0EeUwA==",
"cpu": [
"arm64"
],
@@ -474,9 +474,9 @@
}
},
"node_modules/@rolldown/binding-wasm32-wasi": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz",
- "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.16.tgz",
+ "integrity": "sha512-3Q2KQxnC8IJOLqXmUMoYwyIPZU9hzRbnHaoV3Euz+VVnjZKcY8ktnNP8T9R4/GGQtb27C/UYKABxesKWb8lsvQ==",
"cpu": [
"wasm32"
],
@@ -486,16 +486,16 @@
"dependencies": {
"@emnapi/core": "1.9.2",
"@emnapi/runtime": "1.9.2",
- "@napi-rs/wasm-runtime": "^1.1.3"
+ "@napi-rs/wasm-runtime": "^1.1.4"
},
"engines": {
- "node": ">=14.0.0"
+ "node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-win32-arm64-msvc": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz",
- "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.16.tgz",
+ "integrity": "sha512-tj7XRemQcOcFwv7qhpUxMTBbI5mWMlE4c1Omhg5+h8GuLXzyj8HviYgR+bB2DMDgRqUE+jiDleqSCRjx4aYk/Q==",
"cpu": [
"arm64"
],
@@ -510,9 +510,9 @@
}
},
"node_modules/@rolldown/binding-win32-x64-msvc": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz",
- "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.16.tgz",
+ "integrity": "sha512-PH5DRZT+F4f2PTXRXR8uJxnBq2po/xFtddyabTJVJs/ZYVHqXPEgNIr35IHTEa6bpa0Q8Awg+ymkTaGnKITw4g==",
"cpu": [
"x64"
],
@@ -527,9 +527,9 @@
}
},
"node_modules/@rolldown/pluginutils": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz",
- "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.16.tgz",
+ "integrity": "sha512-45+YtqxLYKDWQouLKCrpIZhke+nXxhsw+qAHVzHDVwttyBlHNBVs2K25rDXrZzhpTp9w1FlAlvweV1H++fdZoA==",
"dev": true,
"license": "MIT"
},
@@ -669,13 +669,13 @@
"peer": true
},
"node_modules/@types/node": {
- "version": "25.5.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz",
- "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==",
+ "version": "25.6.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz",
+ "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==",
"license": "MIT",
"optional": true,
"dependencies": {
- "undici-types": "~7.18.0"
+ "undici-types": "~7.19.0"
}
},
"node_modules/@types/normalize-package-data": {
@@ -696,15 +696,15 @@
}
},
"node_modules/@vitest/coverage-v8": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.4.tgz",
- "integrity": "sha512-x7FptB5oDruxNPDNY2+S8tCh0pcq7ymCe1gTHcsp733jYjrJl8V1gMUlVysuCD9Kz46Xz9t1akkv08dPcYDs1w==",
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.5.tgz",
+ "integrity": "sha512-38C0/Ddb7HcRG0Z4/DUem8x57d2p9jYgp18mkaYswEOQBGsI1CG4f/hjm0ZCeaJfWhSZ4k7jgs29V1Zom7Ki9A==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@bcoe/v8-coverage": "^1.0.2",
- "@vitest/utils": "4.1.4",
+ "@vitest/utils": "4.1.5",
"ast-v8-to-istanbul": "^1.0.0",
"istanbul-lib-coverage": "^3.2.2",
"istanbul-lib-report": "^3.0.1",
@@ -718,8 +718,8 @@
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
- "@vitest/browser": "4.1.4",
- "vitest": "4.1.4"
+ "@vitest/browser": "4.1.5",
+ "vitest": "4.1.5"
},
"peerDependenciesMeta": {
"@vitest/browser": {
@@ -728,16 +728,16 @@
}
},
"node_modules/@vitest/expect": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.4.tgz",
- "integrity": "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==",
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.5.tgz",
+ "integrity": "sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@standard-schema/spec": "^1.1.0",
"@types/chai": "^5.2.2",
- "@vitest/spy": "4.1.4",
- "@vitest/utils": "4.1.4",
+ "@vitest/spy": "4.1.5",
+ "@vitest/utils": "4.1.5",
"chai": "^6.2.2",
"tinyrainbow": "^3.1.0"
},
@@ -746,13 +746,13 @@
}
},
"node_modules/@vitest/mocker": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.4.tgz",
- "integrity": "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==",
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.5.tgz",
+ "integrity": "sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/spy": "4.1.4",
+ "@vitest/spy": "4.1.5",
"estree-walker": "^3.0.3",
"magic-string": "^0.30.21"
},
@@ -773,9 +773,9 @@
}
},
"node_modules/@vitest/pretty-format": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.4.tgz",
- "integrity": "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==",
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.5.tgz",
+ "integrity": "sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -786,13 +786,13 @@
}
},
"node_modules/@vitest/runner": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.4.tgz",
- "integrity": "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==",
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.5.tgz",
+ "integrity": "sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/utils": "4.1.4",
+ "@vitest/utils": "4.1.5",
"pathe": "^2.0.3"
},
"funding": {
@@ -800,14 +800,14 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.4.tgz",
- "integrity": "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==",
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.5.tgz",
+ "integrity": "sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "4.1.4",
- "@vitest/utils": "4.1.4",
+ "@vitest/pretty-format": "4.1.5",
+ "@vitest/utils": "4.1.5",
"magic-string": "^0.30.21",
"pathe": "^2.0.3"
},
@@ -816,9 +816,9 @@
}
},
"node_modules/@vitest/spy": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.4.tgz",
- "integrity": "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==",
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.5.tgz",
+ "integrity": "sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==",
"dev": true,
"license": "MIT",
"funding": {
@@ -826,13 +826,13 @@
}
},
"node_modules/@vitest/utils": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.4.tgz",
- "integrity": "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==",
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.5.tgz",
+ "integrity": "sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "4.1.4",
+ "@vitest/pretty-format": "4.1.5",
"convert-source-map": "^2.0.0",
"tinyrainbow": "^3.1.0"
},
@@ -1048,18 +1048,18 @@
}
},
"node_modules/bare-url": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.0.tgz",
- "integrity": "sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==",
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.2.tgz",
+ "integrity": "sha512-/9a2j4ac6ckpmAHvod/ob7x439OAHst/drc2Clnq+reRYd/ovddwcF4LfoxHyNk5AuGBnPg+HqFjmE/Zpq6v0A==",
"license": "Apache-2.0",
"dependencies": {
"bare-path": "^3.0.0"
}
},
"node_modules/basic-ftp": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.2.tgz",
- "integrity": "sha512-1tDrzKsdCg70WGvbFss/ulVAxupNauGnOlgpyjKzeQxzyllBLS0CGLV7tjIXTK3ZQA9/FBEm9qyFFN1bciA6pw==",
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.0.tgz",
+ "integrity": "sha512-5K9eNNn7ywHPsYnFwjKgYH8Hf8B5emh7JKcPaVjjrMJFQQwGpwowEnZNEtHs7DfR7hCZsmaK3VA4HUK0YarT+w==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
@@ -2208,9 +2208,9 @@
}
},
"node_modules/openapi-mock-validator": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/openapi-mock-validator/-/openapi-mock-validator-0.1.4.tgz",
- "integrity": "sha512-iQELUkb3aGKoyokSvi7/kkRsedTc0wpGQc5gzIvitz5aCkTQ/PdSkYGTMoKBmNLJX7NBukNhcgOpQz0InB5M5w==",
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/openapi-mock-validator/-/openapi-mock-validator-0.2.0.tgz",
+ "integrity": "sha512-7ssYWUFaDmGDlKLd6ARFDLgs81a0NzDSUhI1jFvi3MrOsRhqc5Q2X7xxB8mvWzL2Cj5Ywzkl265EdZ2hPdRAAg==",
"license": "MIT",
"dependencies": {
"@apidevtools/json-schema-ref-parser": "^15.3.4",
@@ -2328,9 +2328,9 @@
}
},
"node_modules/postcss": {
- "version": "8.5.9",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz",
- "integrity": "sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==",
+ "version": "8.5.10",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz",
+ "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==",
"dev": true,
"funding": [
{
@@ -2434,9 +2434,9 @@
}
},
"node_modules/puppeteer": {
- "version": "24.41.0",
- "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.41.0.tgz",
- "integrity": "sha512-W6Fk0J3TPjjtwjXOyR/qf+YaL0H/Uq8HIgHcXG4mNM/IgbKMCH/HPyK0Fi2qbTU/QpSl9bCte2yBpGHKejTpIw==",
+ "version": "24.42.0",
+ "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.42.0.tgz",
+ "integrity": "sha512-94MoPfFp2eY3eYIMdINkez4IOP5TMHntlZbVx06fHlQTtiQiYgaY0L2Zzfod8PVUkPqP7m3Qlre2v8YS8cudPA==",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
@@ -2444,7 +2444,7 @@
"chromium-bidi": "14.0.0",
"cosmiconfig": "^9.0.0",
"devtools-protocol": "0.0.1595872",
- "puppeteer-core": "24.41.0",
+ "puppeteer-core": "24.42.0",
"typed-query-selector": "^2.12.1"
},
"bin": {
@@ -2455,9 +2455,9 @@
}
},
"node_modules/puppeteer-core": {
- "version": "24.41.0",
- "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.41.0.tgz",
- "integrity": "sha512-rLIUri7E/NQ3APSEYCCozaSJx0u8Tu9wxO6BJwnvXmIgILSK3L0TombaVh3izp1njAGrO6H2ru0hcIrLF+gWLw==",
+ "version": "24.42.0",
+ "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.42.0.tgz",
+ "integrity": "sha512-T4zXokk/izH01fYPhyyev1A4piWiOKrYq7CUFpdoYQxmOnXoV6YjUabmfIjCYkNspSoAXIxRid3Tw+Vg0fthYg==",
"license": "Apache-2.0",
"dependencies": {
"@puppeteer/browsers": "2.13.0",
@@ -2473,9 +2473,9 @@
}
},
"node_modules/react": {
- "version": "19.2.4",
- "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
- "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
+ "version": "19.2.5",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz",
+ "integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==",
"license": "MIT",
"peer": true,
"engines": {
@@ -2483,16 +2483,16 @@
}
},
"node_modules/react-dom": {
- "version": "19.2.4",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
- "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
+ "version": "19.2.5",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz",
+ "integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
"peerDependencies": {
- "react": "^19.2.4"
+ "react": "^19.2.5"
}
},
"node_modules/react-is": {
@@ -2529,14 +2529,14 @@
}
},
"node_modules/rolldown": {
- "version": "1.0.0-rc.15",
- "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz",
- "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==",
+ "version": "1.0.0-rc.16",
+ "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.16.tgz",
+ "integrity": "sha512-rzi5WqKzEZw3SooTt7cgm4eqIoujPIyGcJNGFL7iPEuajQw7vxMHUkXylu4/vhCkJGXsgRmxqMKXUpT6FEgl0g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@oxc-project/types": "=0.124.0",
- "@rolldown/pluginutils": "1.0.0-rc.15"
+ "@oxc-project/types": "=0.126.0",
+ "@rolldown/pluginutils": "1.0.0-rc.16"
},
"bin": {
"rolldown": "bin/cli.mjs"
@@ -2545,21 +2545,21 @@
"node": "^20.19.0 || >=22.12.0"
},
"optionalDependencies": {
- "@rolldown/binding-android-arm64": "1.0.0-rc.15",
- "@rolldown/binding-darwin-arm64": "1.0.0-rc.15",
- "@rolldown/binding-darwin-x64": "1.0.0-rc.15",
- "@rolldown/binding-freebsd-x64": "1.0.0-rc.15",
- "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15",
- "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15",
- "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15",
- "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15",
- "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15",
- "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15",
- "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15",
- "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15",
- "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15",
- "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15",
- "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15"
+ "@rolldown/binding-android-arm64": "1.0.0-rc.16",
+ "@rolldown/binding-darwin-arm64": "1.0.0-rc.16",
+ "@rolldown/binding-darwin-x64": "1.0.0-rc.16",
+ "@rolldown/binding-freebsd-x64": "1.0.0-rc.16",
+ "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.16",
+ "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.16",
+ "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.16",
+ "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.16",
+ "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.16",
+ "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.16",
+ "@rolldown/binding-linux-x64-musl": "1.0.0-rc.16",
+ "@rolldown/binding-openharmony-arm64": "1.0.0-rc.16",
+ "@rolldown/binding-wasm32-wasi": "1.0.0-rc.16",
+ "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.16",
+ "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.16"
}
},
"node_modules/scheduler": {
@@ -2689,9 +2689,9 @@
"license": "MIT"
},
"node_modules/std-env": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.0.0.tgz",
- "integrity": "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz",
+ "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==",
"dev": true,
"license": "MIT"
},
@@ -2840,9 +2840,9 @@
"license": "0BSD"
},
"node_modules/twd-js": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/twd-js/-/twd-js-1.7.1.tgz",
- "integrity": "sha512-wQWzwQ4xXGu+En8rVqwIOJ77UVakDQ3rNvuqksclxByvqBwjBvc2iof97GtHQ7LNwE+Z7REA6R5fGPLndqKS6Q==",
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/twd-js/-/twd-js-1.7.2.tgz",
+ "integrity": "sha512-e6syq8ZdMUdpf0fZSincADy5gwa9hYL7sFZ4+rLUM+NTncxG56FwQwA/kosk5yVeUVtWjtC8HW7104uqRkdoRw==",
"license": "MIT",
"dependencies": {
"@testing-library/dom": "^10.4.1",
@@ -2883,9 +2883,9 @@
}
},
"node_modules/undici-types": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
- "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
+ "version": "7.19.2",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz",
+ "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==",
"license": "MIT",
"optional": true
},
@@ -2901,18 +2901,18 @@
}
},
"node_modules/vite": {
- "version": "8.0.8",
- "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz",
- "integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==",
+ "version": "8.0.9",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.9.tgz",
+ "integrity": "sha512-t7g7GVRpMXjNpa67HaVWI/8BWtdVIQPCL2WoozXXA7LBGEFK4AkkKkHx2hAQf5x1GZSlcmEDPkVLSGahxnEEZw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"lightningcss": "^1.32.0",
"picomatch": "^4.0.4",
- "postcss": "^8.5.8",
- "rolldown": "1.0.0-rc.15",
- "tinyglobby": "^0.2.15"
+ "postcss": "^8.5.10",
+ "rolldown": "1.0.0-rc.16",
+ "tinyglobby": "^0.2.16"
},
"bin": {
"vite": "bin/vite.js"
@@ -2980,20 +2980,20 @@
}
},
"node_modules/vitest": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.4.tgz",
- "integrity": "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==",
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.5.tgz",
+ "integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
- "@vitest/expect": "4.1.4",
- "@vitest/mocker": "4.1.4",
- "@vitest/pretty-format": "4.1.4",
- "@vitest/runner": "4.1.4",
- "@vitest/snapshot": "4.1.4",
- "@vitest/spy": "4.1.4",
- "@vitest/utils": "4.1.4",
+ "@vitest/expect": "4.1.5",
+ "@vitest/mocker": "4.1.5",
+ "@vitest/pretty-format": "4.1.5",
+ "@vitest/runner": "4.1.5",
+ "@vitest/snapshot": "4.1.5",
+ "@vitest/spy": "4.1.5",
+ "@vitest/utils": "4.1.5",
"es-module-lexer": "^2.0.0",
"expect-type": "^1.3.0",
"magic-string": "^0.30.21",
@@ -3021,12 +3021,12 @@
"@edge-runtime/vm": "*",
"@opentelemetry/api": "^1.9.0",
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
- "@vitest/browser-playwright": "4.1.4",
- "@vitest/browser-preview": "4.1.4",
- "@vitest/browser-webdriverio": "4.1.4",
- "@vitest/coverage-istanbul": "4.1.4",
- "@vitest/coverage-v8": "4.1.4",
- "@vitest/ui": "4.1.4",
+ "@vitest/browser-playwright": "4.1.5",
+ "@vitest/browser-preview": "4.1.5",
+ "@vitest/browser-webdriverio": "4.1.5",
+ "@vitest/coverage-istanbul": "4.1.5",
+ "@vitest/coverage-v8": "4.1.5",
+ "@vitest/ui": "4.1.5",
"happy-dom": "*",
"jsdom": "*",
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
diff --git a/package.json b/package.json
index 2d6cbb4..6f1ef26 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "twd-cli",
- "version": "1.1.9",
+ "version": "1.1.10",
"description": "CLI tool for running TWD tests with Puppeteer",
"type": "module",
"main": "src/index.js",
@@ -23,9 +23,9 @@
"author": "",
"license": "ISC",
"dependencies": {
- "openapi-mock-validator": "^0.1.4",
- "puppeteer": "^24.41.0",
- "twd-js": "^1.7.1"
+ "openapi-mock-validator": "^0.2.0",
+ "puppeteer": "^24.42.0",
+ "twd-js": "^1.7.2"
},
"engines": {
"node": ">=18.0.0"
diff --git a/src/contracts.js b/src/contracts.js
index 415d917..dc30969 100644
--- a/src/contracts.js
+++ b/src/contracts.js
@@ -2,6 +2,14 @@ import fs from 'fs';
import path from 'path';
import { OpenAPIMockValidator } from 'openapi-mock-validator';
+function readContentType(responseHeaders) {
+ if (!responseHeaders) return 'application/json';
+ for (const [key, value] of Object.entries(responseHeaders)) {
+ if (key.toLowerCase() === 'content-type') return value;
+ }
+ return 'application/json';
+}
+
export async function loadContracts(contracts, workingDir) {
const loaded = [];
@@ -67,12 +75,13 @@ export function validateMocks(collectedMocks, contracts) {
continue;
}
+ const contentType = readContentType(mock.responseHeaders);
const validation = contract.validator.validateResponse(
pathMatch.path,
mock.method,
mock.status,
mock.response,
- { strict: contract.strict },
+ { strict: contract.strict, contentType },
);
results.push({
diff --git a/test-example-app/contracts/products-3.0.json b/test-example-app/contracts/products-3.0.json
index b999949..34f6111 100644
--- a/test-example-app/contracts/products-3.0.json
+++ b/test-example-app/contracts/products-3.0.json
@@ -74,6 +74,29 @@
}
}
},
+ "/products/{productId}/thumbnail": {
+ "get": {
+ "operationId": "getProductThumbnail",
+ "parameters": [
+ {
+ "name": "productId",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string", "format": "uuid" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Product thumbnail image",
+ "content": {
+ "image/*": {
+ "schema": { "type": "string", "format": "binary" }
+ }
+ }
+ }
+ }
+ }
+ },
"/settings": {
"get": {
"operationId": "getSettings",
diff --git a/test-example-app/package-lock.json b/test-example-app/package-lock.json
index 30bba69..5d6295e 100644
--- a/test-example-app/package-lock.json
+++ b/test-example-app/package-lock.json
@@ -17,7 +17,7 @@
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.1",
"babel-plugin-react-compiler": "^1.0.0",
- "twd-js": "^1.6.5",
+ "twd-js": "^1.7.2",
"typescript": "~6.0.2",
"vite": "^8.0.3"
}
@@ -1016,9 +1016,9 @@
}
},
"node_modules/preact": {
- "version": "10.29.0",
- "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.0.tgz",
- "integrity": "sha512-wSAGyk2bYR1c7t3SZ3jHcM6xy0lcBcDel6lODcs9ME6Th++Dx2KU+6D3HD8wMMKGA8Wpw7OMd3/4RGzYRpzwRg==",
+ "version": "10.29.1",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.1.tgz",
+ "integrity": "sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==",
"dev": true,
"license": "MIT",
"funding": {
@@ -1154,9 +1154,9 @@
"optional": true
},
"node_modules/twd-js": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/twd-js/-/twd-js-1.6.5.tgz",
- "integrity": "sha512-LNTX7uOPxH8vf1XJ3FA9vVKD+2xxOXxvliQ3NtfDZTTN2mQg0d9u8Ajd3UfMzoUgoloFG3IcApizAx7mN1ILoA==",
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/twd-js/-/twd-js-1.7.2.tgz",
+ "integrity": "sha512-e6syq8ZdMUdpf0fZSincADy5gwa9hYL7sFZ4+rLUM+NTncxG56FwQwA/kosk5yVeUVtWjtC8HW7104uqRkdoRw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1164,7 +1164,7 @@
"@testing-library/user-event": "^14.6.1",
"@types/chai": "^5.2.3",
"chai": "^6.2.2",
- "preact": "^10.29.0"
+ "preact": "^10.29.1"
},
"bin": {
"twd-js": "dist/cli.js"
diff --git a/test-example-app/package.json b/test-example-app/package.json
index 82f7d25..2c4cdb2 100644
--- a/test-example-app/package.json
+++ b/test-example-app/package.json
@@ -18,7 +18,7 @@
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.1",
"babel-plugin-react-compiler": "^1.0.0",
- "twd-js": "^1.6.5",
+ "twd-js": "^1.7.2",
"typescript": "~6.0.2",
"vite": "^8.0.3"
}
diff --git a/test-example-app/src/App.twd.test.ts b/test-example-app/src/App.twd.test.ts
index 3804065..5612de8 100644
--- a/test-example-app/src/App.twd.test.ts
+++ b/test-example-app/src/App.twd.test.ts
@@ -897,3 +897,46 @@ describe("Contract Validation - Events Mismatches (OpenAPI 3.1 — error mode)",
});
});
});
+
+// ── Content-Type forwarding — binary mocks vs image/* spec ───────────
+
+describe("Contract Validation - Content-Type forwarding (Products API)", () => {
+ it("should match image/png mock against image/* spec entry", async () => {
+ twd.mockRequest("getProductThumbnailPng", {
+ method: "GET",
+ url: "/api/products/550e8400-e29b-41d4-a716-446655440000/thumbnail",
+ status: 200,
+ response: "fake-png-bytes",
+ responseHeaders: { "Content-Type": "image/png" },
+ });
+ });
+
+ it("should match image/jpeg mock against image/* spec entry", async () => {
+ twd.mockRequest("getProductThumbnailJpeg", {
+ method: "GET",
+ url: "/api/products/550e8400-e29b-41d4-a716-446655440001/thumbnail",
+ status: 200,
+ response: "fake-jpeg-bytes",
+ responseHeaders: { "content-type": "image/jpeg" },
+ });
+ });
+
+ it("should warn when non-binary Content-Type has no matching spec entry", async () => {
+ twd.mockRequest("getProductsAsXml", {
+ method: "GET",
+ url: "/api/products",
+ status: 200,
+ response: "",
+ responseHeaders: { "Content-Type": "application/xml" },
+ });
+ });
+
+ it("should warn when mock has no responseHeaders against image-only endpoint", async () => {
+ twd.mockRequest("getProductThumbnailNoHeader", {
+ method: "GET",
+ url: "/api/products/550e8400-e29b-41d4-a716-446655440002/thumbnail",
+ status: 200,
+ response: "fake-bytes",
+ });
+ });
+});
diff --git a/tests/contracts.test.js b/tests/contracts.test.js
index f447943..1c4e8dd 100644
--- a/tests/contracts.test.js
+++ b/tests/contracts.test.js
@@ -256,3 +256,96 @@ describe('validateMocks with testId and occurrence', () => {
expect(output.results[1].validation.valid).toBe(true);
});
});
+
+describe('validateMocks — Content-Type forwarding', () => {
+ let loadedContracts;
+
+ beforeEach(async () => {
+ loadedContracts = await loadContracts(
+ [{ source: './tests/fixtures/petstore-3.0.json', baseUrl: '/api' }],
+ path.resolve(__dirname, '..'),
+ );
+ });
+
+ it('forwards Content-Type from responseHeaders so image/* endpoints match', () => {
+ const mocks = new Map();
+ mocks.set('getPetPhoto', {
+ alias: 'getPetPhoto',
+ url: '/api/v1/pets/123/photo',
+ method: 'GET',
+ status: 200,
+ response: 'fake-binary-data',
+ urlRegex: false,
+ responseHeaders: { 'Content-Type': 'image/png' },
+ });
+
+ const output = validateMocks(mocks, loadedContracts);
+
+ expect(output.results).toHaveLength(1);
+ const missingSchema = output.results[0].validation.warnings.filter(
+ w => w.type === 'MISSING_SCHEMA'
+ );
+ expect(missingSchema).toHaveLength(0);
+ expect(output.results[0].validation.errors).toHaveLength(0);
+ });
+
+ it('resolves Content-Type when header key is lowercase', () => {
+ const mocks = new Map();
+ mocks.set('getPetPhoto', {
+ alias: 'getPetPhoto',
+ url: '/api/v1/pets/123/photo',
+ method: 'GET',
+ status: 200,
+ response: 'fake-binary-data',
+ urlRegex: false,
+ responseHeaders: { 'content-type': 'image/png' },
+ });
+ const output = validateMocks(mocks, loadedContracts);
+ expect(output.results[0].validation.warnings.some(w => w.type === 'MISSING_SCHEMA')).toBe(false);
+ });
+
+ it('resolves Content-Type when header key is upper-case', () => {
+ const mocks = new Map();
+ mocks.set('getPetPhoto', {
+ alias: 'getPetPhoto',
+ url: '/api/v1/pets/123/photo',
+ method: 'GET',
+ status: 200,
+ response: 'fake-binary-data',
+ urlRegex: false,
+ responseHeaders: { 'CONTENT-TYPE': 'image/png' },
+ });
+ const output = validateMocks(mocks, loadedContracts);
+ expect(output.results[0].validation.warnings.some(w => w.type === 'MISSING_SCHEMA')).toBe(false);
+ });
+
+ it('defaults to application/json when responseHeaders is missing', () => {
+ const mocks = new Map();
+ mocks.set('getPets', {
+ alias: 'getPets',
+ url: '/api/v1/pets',
+ method: 'GET',
+ status: 200,
+ response: [{ id: 1, name: 'Fido' }],
+ urlRegex: false,
+ });
+ const output = validateMocks(mocks, loadedContracts);
+ expect(output.results[0].validation.valid).toBe(true);
+ expect(output.results[0].validation.errors).toHaveLength(0);
+ });
+
+ it('defaults to application/json when responseHeaders has no Content-Type entry', () => {
+ const mocks = new Map();
+ mocks.set('getPets', {
+ alias: 'getPets',
+ url: '/api/v1/pets',
+ method: 'GET',
+ status: 200,
+ response: [{ id: 1, name: 'Fido' }],
+ urlRegex: false,
+ responseHeaders: { 'X-Request-Id': 'abc123' },
+ });
+ const output = validateMocks(mocks, loadedContracts);
+ expect(output.results[0].validation.valid).toBe(true);
+ });
+});
diff --git a/tests/fixtures/petstore-3.0.json b/tests/fixtures/petstore-3.0.json
index 16d97a1..d967537 100644
--- a/tests/fixtures/petstore-3.0.json
+++ b/tests/fixtures/petstore-3.0.json
@@ -82,6 +82,28 @@
}
}
}
+ },
+ "/v1/pets/{petId}/photo": {
+ "get": {
+ "parameters": [
+ {
+ "name": "petId",
+ "in": "path",
+ "required": true,
+ "schema": { "type": "string" }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Pet photo",
+ "content": {
+ "image/*": {
+ "schema": { "type": "string", "format": "binary" }
+ }
+ }
+ }
+ }
+ }
}
}
}
diff --git a/tests/runTests.test.js b/tests/runTests.test.js
index 527e7e5..16e38e4 100644
--- a/tests/runTests.test.js
+++ b/tests/runTests.test.js
@@ -191,4 +191,57 @@ describe("runTests", () => {
expect(result).toBe(true);
});
+
+ it("preserves responseHeaders through the __twdCollectMock spread", async () => {
+ const testStatus = [{ id: 't-1', status: 'pass' }];
+ const handlers = [{ id: 't-1', name: 'test1', type: 'test' }];
+
+ const page = {
+ goto: vi.fn(),
+ waitForSelector: vi.fn(),
+ exposeFunction: vi.fn(),
+ // Drive the registered __twdCollectMock callback from inside page.evaluate,
+ // mirroring how a real browser test would trigger it.
+ evaluate: vi.fn().mockImplementation(async () => {
+ const exposed = page.exposeFunction.mock.calls.find(
+ (c) => c[0] === '__twdCollectMock'
+ );
+ expect(exposed).toBeDefined();
+ const collectMock = exposed[1];
+ await collectMock({
+ alias: 'getPhoto',
+ url: '/v1/photo',
+ method: 'GET',
+ status: 200,
+ response: 'bin',
+ testId: 't-1',
+ responseHeaders: { 'Content-Type': 'image/png' },
+ });
+ return { handlers, testStatus };
+ }),
+ };
+ const browser = createMockBrowser(page);
+ vi.mocked(puppeteer.launch).mockResolvedValue(browser);
+ vi.mocked(loadConfig).mockReturnValue({
+ ...defaultMockConfig,
+ contracts: [{ source: './openapi.json' }],
+ });
+ vi.mocked(loadContracts).mockResolvedValue([{ /* sentinel contract */ }]);
+
+ let capturedMocks;
+ vi.mocked(validateMocks).mockImplementation((mocks) => {
+ capturedMocks = mocks;
+ return { results: [], skipped: [] };
+ });
+ vi.mocked(printContractReport).mockReturnValue(false);
+
+ await runTests();
+
+ expect(capturedMocks).toBeDefined();
+ const entries = Array.from(capturedMocks.values());
+ expect(entries).toHaveLength(1);
+ expect(entries[0].responseHeaders).toEqual({ 'Content-Type': 'image/png' });
+ expect(entries[0].alias).toBe('getPhoto');
+ expect(entries[0].occurrence).toBe(1);
+ });
});