Add OpenAPI fixture validation and fix fixtures to match API spec

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-22 23:58:17 +08:00
parent 56bee336db
commit 55986a1965
11 changed files with 5580 additions and 3398 deletions

134
package-lock.json generated
View File

@@ -48,6 +48,8 @@
"@vitejs/plugin-vue": "^6.0.4", "@vitejs/plugin-vue": "^6.0.4",
"@vue/eslint-config-prettier": "^10.2.0", "@vue/eslint-config-prettier": "^10.2.0",
"@vue/test-utils": "^2.4.6", "@vue/test-utils": "^2.4.6",
"ajv": "^8.18.0",
"ajv-formats": "^3.0.1",
"chartjs-plugin-dragdata": "^2.3.1", "chartjs-plugin-dragdata": "^2.3.1",
"eslint": "^10.0.2", "eslint": "^10.0.2",
"eslint-plugin-vue": "^10.8.0", "eslint-plugin-vue": "^10.8.0",
@@ -2964,22 +2966,40 @@
} }
}, },
"node_modules/ajv": { "node_modules/ajv": {
"version": "6.14.0", "version": "8.18.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.3",
"fast-json-stable-stringify": "^2.0.0", "fast-uri": "^3.0.1",
"json-schema-traverse": "^0.4.1", "json-schema-traverse": "^1.0.0",
"uri-js": "^4.2.2" "require-from-string": "^2.0.2"
}, },
"funding": { "funding": {
"type": "github", "type": "github",
"url": "https://github.com/sponsors/epoberezkin" "url": "https://github.com/sponsors/epoberezkin"
} }
}, },
"node_modules/ajv-formats": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
"integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ajv": "^8.0.0"
},
"peerDependencies": {
"ajv": "^8.0.0"
},
"peerDependenciesMeta": {
"ajv": {
"optional": true
}
}
},
"node_modules/ansi-regex": { "node_modules/ansi-regex": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
@@ -3996,6 +4016,23 @@
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
} }
}, },
"node_modules/eslint/node_modules/ajv": {
"version": "6.14.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/eslint/node_modules/eslint-visitor-keys": { "node_modules/eslint/node_modules/eslint-visitor-keys": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
@@ -4009,6 +4046,13 @@
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
} }
}, },
"node_modules/eslint/node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true,
"license": "MIT"
},
"node_modules/espree": { "node_modules/espree": {
"version": "11.1.1", "version": "11.1.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-11.1.1.tgz", "resolved": "https://registry.npmjs.org/espree/-/espree-11.1.1.tgz",
@@ -4136,6 +4180,23 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-uri": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
"integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "BSD-3-Clause"
},
"node_modules/file-entry-cache": { "node_modules/file-entry-cache": {
"version": "8.0.0", "version": "8.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -4771,9 +4832,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/json-schema-traverse": { "node_modules/json-schema-traverse": {
"version": "0.4.1", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@@ -8816,15 +8877,24 @@
"dev": true "dev": true
}, },
"ajv": { "ajv": {
"version": "6.14.0", "version": "8.18.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
"dev": true, "dev": true,
"requires": { "requires": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.3",
"fast-json-stable-stringify": "^2.0.0", "fast-uri": "^3.0.1",
"json-schema-traverse": "^0.4.1", "json-schema-traverse": "^1.0.0",
"uri-js": "^4.2.2" "require-from-string": "^2.0.2"
}
},
"ajv-formats": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
"integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
"dev": true,
"requires": {
"ajv": "^8.0.0"
} }
}, },
"ansi-regex": { "ansi-regex": {
@@ -9469,11 +9539,29 @@
"optionator": "^0.9.3" "optionator": "^0.9.3"
}, },
"dependencies": { "dependencies": {
"ajv": {
"version": "6.14.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"eslint-visitor-keys": { "eslint-visitor-keys": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
"integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
"dev": true "dev": true
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
} }
} }
}, },
@@ -9627,6 +9715,12 @@
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true "dev": true
}, },
"fast-uri": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
"integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
"dev": true
},
"file-entry-cache": { "file-entry-cache": {
"version": "8.0.0", "version": "8.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -10035,9 +10129,9 @@
"dev": true "dev": true
}, },
"json-schema-traverse": { "json-schema-traverse": {
"version": "0.4.1", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true "dev": true
}, },
"json-stable-stringify-without-jsonify": { "json-stable-stringify-without-jsonify": {

View File

@@ -57,6 +57,8 @@
"@vitejs/plugin-vue": "^6.0.4", "@vitejs/plugin-vue": "^6.0.4",
"@vue/eslint-config-prettier": "^10.2.0", "@vue/eslint-config-prettier": "^10.2.0",
"@vue/test-utils": "^2.4.6", "@vue/test-utils": "^2.4.6",
"ajv": "^8.18.0",
"ajv-formats": "^3.0.1",
"chartjs-plugin-dragdata": "^2.3.1", "chartjs-plugin-dragdata": "^2.3.1",
"eslint": "^10.0.2", "eslint": "^10.0.2",
"eslint-plugin-vue": "^10.8.0", "eslint-plugin-vue": "^10.8.0",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -146,49 +146,49 @@
"timeframe": { "timeframe": {
"data": [ "data": [
{ {
"x": "2022-01-21T03:21:48", "x": "2022-01-21T03:21:48Z",
"y": 347 "y": 347
}, },
{ {
"x": "2022-02-26T08:13:24", "x": "2022-02-26T08:13:24Z",
"y": 426 "y": 426
}, },
{ {
"x": "2022-04-03T13:05:00", "x": "2022-04-03T13:05:00Z",
"y": 394 "y": 394
}, },
{ {
"x": "2022-05-09T17:56:36", "x": "2022-05-09T17:56:36Z",
"y": 375 "y": 375
}, },
{ {
"x": "2022-06-14T22:48:12", "x": "2022-06-14T22:48:12Z",
"y": 431 "y": 431
}, },
{ {
"x": "2022-07-21T03:39:48", "x": "2022-07-21T03:39:48Z",
"y": 393 "y": 393
}, },
{ {
"x": "2022-08-26T08:31:24", "x": "2022-08-26T08:31:24Z",
"y": 284 "y": 284
}, },
{ {
"x": "2022-10-01T13:23:00", "x": "2022-10-01T13:23:00Z",
"y": 359 "y": 359
}, },
{ {
"x": "2022-11-06T18:14:36", "x": "2022-11-06T18:14:36Z",
"y": 386 "y": 386
}, },
{ {
"x": "2022-12-12T23:06:12", "x": "2022-12-12T23:06:12Z",
"y": 327 "y": 327
} }
], ],
"x_axis": { "x_axis": {
"min": "2022-01-03T00:56:00", "min": "2022-01-03T00:56:00Z",
"max": "2022-12-31T01:32:00" "max": "2022-12-31T01:32:00Z"
}, },
"y_axis": { "y_axis": {
"min": 0, "min": 0,

View File

@@ -3,101 +3,101 @@
"avg_cycle_time": { "avg_cycle_time": {
"data": [ "data": [
{ {
"x": "2022-01-21T03:21:48", "x": "2022-01-21T03:21:48Z",
"y": 980220.0 "y": "PT272H17M"
}, },
{ {
"x": "2022-02-26T08:13:24", "x": "2022-02-26T08:13:24Z",
"y": 1000376.129032 "y": "PT277H52M56.13S"
}, },
{ {
"x": "2022-04-03T13:05:00", "x": "2022-04-03T13:05:00Z",
"y": 911990.0 "y": "PT253H19M50.0S"
}, },
{ {
"x": "2022-05-09T17:56:36", "x": "2022-05-09T17:56:36Z",
"y": 1041860.0 "y": "PT289H24M20.0S"
}, },
{ {
"x": "2022-06-14T22:48:12", "x": "2022-06-14T22:48:12Z",
"y": 985415.625 "y": "PT273H43M35.62S"
}, },
{ {
"x": "2022-07-21T03:39:48", "x": "2022-07-21T03:39:48Z",
"y": 938079.130435 "y": "PT260H34M39.13S"
}, },
{ {
"x": "2022-08-26T08:31:24", "x": "2022-08-26T08:31:24Z",
"y": 1074680.0 "y": "PT298H31M20.0S"
}, },
{ {
"x": "2022-10-01T13:23:00", "x": "2022-10-01T13:23:00Z",
"y": 1061848.695652 "y": "PT294H57M28.7S"
}, },
{ {
"x": "2022-11-06T18:14:36", "x": "2022-11-06T18:14:36Z",
"y": 970119.230769 "y": "PT269H28M39.23S"
}, },
{ {
"x": "2022-12-12T23:06:12", "x": "2022-12-12T23:06:12Z",
"y": 1060703.076923 "y": "PT294H38M23.08S"
} }
], ],
"x_axis": { "x_axis": {
"min": "2022-01-03T00:56:00", "min": "2022-01-03T00:56:00Z",
"max": "2022-12-31T01:32:00" "max": "2022-12-31T01:32:00Z"
}, },
"y_axis": { "y_axis": {
"min": 0.0, "min": "PT0S",
"max": 1074680.0 "max": "PT298H31M20.0S"
} }
}, },
"avg_cycle_efficiency": { "avg_cycle_efficiency": {
"data": [ "data": [
{ {
"x": "2022-01-21T03:21:48", "x": "2022-01-21T03:21:48Z",
"y": 0.9527980523449506 "y": 0.9527980523449506
}, },
{ {
"x": "2022-02-26T08:13:24", "x": "2022-02-26T08:13:24Z",
"y": 0.9516493513262202 "y": 0.9516493513262202
}, },
{ {
"x": "2022-04-03T13:05:00", "x": "2022-04-03T13:05:00Z",
"y": 0.9475330648076836 "y": 0.9475330648076836
}, },
{ {
"x": "2022-05-09T17:56:36", "x": "2022-05-09T17:56:36Z",
"y": 0.9537265449333607 "y": 0.9537265449333607
}, },
{ {
"x": "2022-06-14T22:48:12", "x": "2022-06-14T22:48:12Z",
"y": 0.9528919667258132 "y": 0.9528919667258132
}, },
{ {
"x": "2022-07-21T03:39:48", "x": "2022-07-21T03:39:48Z",
"y": 0.9489804015433904 "y": 0.9489804015433904
}, },
{ {
"x": "2022-08-26T08:31:24", "x": "2022-08-26T08:31:24Z",
"y": 0.9538748758272698 "y": 0.9538748758272698
}, },
{ {
"x": "2022-10-01T13:23:00", "x": "2022-10-01T13:23:00Z",
"y": 0.9548679615433759 "y": 0.9548679615433759
}, },
{ {
"x": "2022-11-06T18:14:36", "x": "2022-11-06T18:14:36Z",
"y": 0.9469965631092006 "y": 0.9469965631092006
}, },
{ {
"x": "2022-12-12T23:06:12", "x": "2022-12-12T23:06:12Z",
"y": 0.9505469198562757 "y": 0.9505469198562757
} }
], ],
"x_axis": { "x_axis": {
"min": "2022-01-03T00:56:00", "min": "2022-01-03T00:56:00Z",
"max": "2022-12-31T01:32:00" "max": "2022-12-31T01:32:00Z"
}, },
"y_axis": { "y_axis": {
"min": 0.0, "min": 0.0,
@@ -107,104 +107,104 @@
"avg_process_time": { "avg_process_time": {
"data": [ "data": [
{ {
"x": "2022-01-21T03:21:48", "x": "2022-01-21T03:21:48Z",
"y": 937067.368421 "y": "PT260H17M47.37S"
}, },
{ {
"x": "2022-02-26T08:13:24", "x": "2022-02-26T08:13:24Z",
"y": 953767.741935 "y": "PT264H56M7.74S"
}, },
{ {
"x": "2022-04-03T13:05:00", "x": "2022-04-03T13:05:00Z",
"y": 865780.0 "y": "PT240H29M40.0S"
}, },
{ {
"x": "2022-05-09T17:56:36", "x": "2022-05-09T17:56:36Z",
"y": 994600.0 "y": "PT276H16M40.0S"
}, },
{ {
"x": "2022-06-14T22:48:12", "x": "2022-06-14T22:48:12Z",
"y": 939795.0 "y": "PT261H3M15.0S"
}, },
{ {
"x": "2022-07-21T03:39:48", "x": "2022-07-21T03:39:48Z",
"y": 890947.826087 "y": "PT247H29M7.83S"
}, },
{ {
"x": "2022-08-26T08:31:24", "x": "2022-08-26T08:31:24Z",
"y": 1026345.714286 "y": "PT285H5M45.71S"
}, },
{ {
"x": "2022-10-01T13:23:00", "x": "2022-10-01T13:23:00Z",
"y": 1016363.478261 "y": "PT282H19M23.48S"
}, },
{ {
"x": "2022-11-06T18:14:36", "x": "2022-11-06T18:14:36Z",
"y": 923626.153846 "y": "PT256H33M46.15S"
}, },
{ {
"x": "2022-12-12T23:06:12", "x": "2022-12-12T23:06:12Z",
"y": 1011540.0 "y": "PT280H59M"
} }
], ],
"x_axis": { "x_axis": {
"min": "2022-01-03T00:56:00", "min": "2022-01-03T00:56:00Z",
"max": "2022-12-31T01:32:00" "max": "2022-12-31T01:32:00Z"
}, },
"y_axis": { "y_axis": {
"min": 0.0, "min": "PT0S",
"max": 1026345.714286 "max": "PT285H5M45.71S"
} }
}, },
"avg_process_time_by_task": { "avg_process_time_by_task": {
"data": [ "data": [
{ {
"x": "a", "x": "aT00:00:00Z",
"y": 131147.486631 "y": "PT36H25M47.49S"
}, },
{ {
"x": "b", "x": "bT00:00:00Z",
"y": 136627.058824 "y": "PT37H57M7.06S"
}, },
{ {
"x": "c", "x": "cT00:00:00Z",
"y": 133261.25 "y": "PT37H1M1.25S"
}, },
{ {
"x": "d", "x": "dT00:00:00Z",
"y": 132697.095436 "y": "PT36H51M37.1S"
}, },
{ {
"x": "e", "x": "eT00:00:00Z",
"y": 124442.891566 "y": "PT34H34M2.89S"
}, },
{ {
"x": "f", "x": "fT00:00:00Z",
"y": 127175.180723 "y": "PT35H19M35.18S"
}, },
{ {
"x": "g", "x": "gT00:00:00Z",
"y": 127627.826087 "y": "PT35H27M7.83S"
}, },
{ {
"x": "h", "x": "hT00:00:00Z",
"y": 128163.680982 "y": "PT35H36M3.68S"
}, },
{ {
"x": "i", "x": "iT00:00:00Z",
"y": 125588.756757 "y": "PT34H53M8.76S"
}, },
{ {
"x": "j", "x": "jT00:00:00Z",
"y": 101290.909091 "y": "PT28H8M10.91S"
}, },
{ {
"x": "k", "x": "kT00:00:00Z",
"y": 142543.75 "y": "PT39H35M43.75S"
}, },
{ {
"x": "l", "x": "lT00:00:00Z",
"y": 138070.879121 "y": "PT38H21M10.88S"
} }
], ],
"x_axis": { "x_axis": {
@@ -224,60 +224,60 @@
] ]
}, },
"y_axis": { "y_axis": {
"min": 0.0, "min": "PT0S",
"max": 142543.75 "max": "PT39H35M43.75S"
} }
}, },
"avg_waiting_time": { "avg_waiting_time": {
"data": [ "data": [
{ {
"x": "2022-01-21T03:21:48", "x": "2022-01-21T03:21:48Z",
"y": 43152.631579 "y": "PT11H59M12.63S"
}, },
{ {
"x": "2022-02-26T08:13:24", "x": "2022-02-26T08:13:24Z",
"y": 46608.387097 "y": "PT12H56M48.39S"
}, },
{ {
"x": "2022-04-03T13:05:00", "x": "2022-04-03T13:05:00Z",
"y": 46210.0 "y": "PT12H50M10.0S"
}, },
{ {
"x": "2022-05-09T17:56:36", "x": "2022-05-09T17:56:36Z",
"y": 47260.0 "y": "PT13H7M40.0S"
}, },
{ {
"x": "2022-06-14T22:48:12", "x": "2022-06-14T22:48:12Z",
"y": 45620.625 "y": "PT12H40M20.62S"
}, },
{ {
"x": "2022-07-21T03:39:48", "x": "2022-07-21T03:39:48Z",
"y": 47131.304348 "y": "PT13H5M31.3S"
}, },
{ {
"x": "2022-08-26T08:31:24", "x": "2022-08-26T08:31:24Z",
"y": 48334.285714 "y": "PT13H25M34.29S"
}, },
{ {
"x": "2022-10-01T13:23:00", "x": "2022-10-01T13:23:00Z",
"y": 45485.217391 "y": "PT12H38M5.22S"
}, },
{ {
"x": "2022-11-06T18:14:36", "x": "2022-11-06T18:14:36Z",
"y": 46493.076923 "y": "PT12H54M53.08S"
}, },
{ {
"x": "2022-12-12T23:06:12", "x": "2022-12-12T23:06:12Z",
"y": 49163.076923 "y": "PT13H39M23.08S"
} }
], ],
"x_axis": { "x_axis": {
"min": "2022-01-03T00:56:00", "min": "2022-01-03T00:56:00Z",
"max": "2022-12-31T01:32:00" "max": "2022-12-31T01:32:00Z"
}, },
"y_axis": { "y_axis": {
"min": 0.0, "min": "PT0S",
"max": 49163.076923 "max": "PT13H39M23.08S"
} }
}, },
"avg_waiting_time_by_edge": { "avg_waiting_time_by_edge": {
@@ -287,322 +287,322 @@
"a", "a",
"a" "a"
], ],
"y": 6420.0 "y": "PT1H47M"
}, },
{ {
"x": [ "x": [
"a", "a",
"d" "d"
], ],
"y": 7506.352941 "y": "PT2H5M6.35S"
}, },
{ {
"x": [ "x": [
"a", "a",
"f" "f"
], ],
"y": 5940.0 "y": "PT1H39M"
}, },
{ {
"x": [ "x": [
"a", "a",
"g" "g"
], ],
"y": 5175.0 "y": "PT1H26M15.0S"
}, },
{ {
"x": [ "x": [
"a", "a",
"i" "i"
], ],
"y": 6260.0 "y": "PT1H44M20.0S"
}, },
{ {
"x": [ "x": [
"b", "b",
"a" "a"
], ],
"y": 6840.0 "y": "PT1H54M"
}, },
{ {
"x": [ "x": [
"b", "b",
"b" "b"
], ],
"y": 3540.0 "y": "PT59M"
}, },
{ {
"x": [ "x": [
"b", "b",
"g" "g"
], ],
"y": 7273.636364 "y": "PT2H1M13.64S"
}, },
{ {
"x": [ "x": [
"b", "b",
"i" "i"
], ],
"y": 6288.0 "y": "PT1H44M48.0S"
}, },
{ {
"x": [ "x": [
"c", "c",
"g" "g"
], ],
"y": 11460.0 "y": "PT3H11M"
}, },
{ {
"x": [ "x": [
"c", "c",
"h" "h"
], ],
"y": 6821.73913 "y": "PT1H53M41.74S"
}, },
{ {
"x": [ "x": [
"c", "c",
"k" "k"
], ],
"y": 13500.0 "y": "PT3H45M"
}, },
{ {
"x": [ "x": [
"d", "d",
"c" "c"
], ],
"y": 11760.0 "y": "PT3H16M"
}, },
{ {
"x": [ "x": [
"d", "d",
"e" "e"
], ],
"y": 7166.694915 "y": "PT1H59M26.69S"
}, },
{ {
"x": [ "x": [
"d", "d",
"g" "g"
], ],
"y": 8080.0 "y": "PT2H14M40.0S"
}, },
{ {
"x": [ "x": [
"d", "d",
"i" "i"
], ],
"y": 3600.0 "y": "PT1H"
}, },
{ {
"x": [ "x": [
"e", "e",
"a" "a"
], ],
"y": 7260.0 "y": "PT2H1M"
}, },
{ {
"x": [ "x": [
"e", "e",
"d" "d"
], ],
"y": 6780.0 "y": "PT1H53M"
}, },
{ {
"x": [ "x": [
"e", "e",
"f" "f"
], ],
"y": 7288.474576 "y": "PT2H1M28.47S"
}, },
{ {
"x": [ "x": [
"e", "e",
"g" "g"
], ],
"y": 14040.0 "y": "PT3H54M"
}, },
{ {
"x": [ "x": [
"e", "e",
"k" "k"
], ],
"y": 13620.0 "y": "PT3H47M"
}, },
{ {
"x": [ "x": [
"e", "e",
"l" "l"
], ],
"y": 3780.0 "y": "PT1H3M"
}, },
{ {
"x": [ "x": [
"f", "f",
"d" "d"
], ],
"y": 10140.0 "y": "PT2H49M"
}, },
{ {
"x": [ "x": [
"f", "f",
"e" "e"
], ],
"y": 3940.0 "y": "PT1H5M40.0S"
}, },
{ {
"x": [ "x": [
"f", "f",
"g" "g"
], ],
"y": 6983.271028 "y": "PT1H56M23.27S"
}, },
{ {
"x": [ "x": [
"f", "f",
"j" "j"
], ],
"y": 8170.909091 "y": "PT2H16M10.91S"
}, },
{ {
"x": [ "x": [
"f", "f",
"l" "l"
], ],
"y": 6667.5 "y": "PT1H51M7.5S"
}, },
{ {
"x": [ "x": [
"g", "g",
"c" "c"
], ],
"y": 2400.0 "y": "PT40M"
}, },
{ {
"x": [ "x": [
"g", "g",
"e" "e"
], ],
"y": 11880.0 "y": "PT3H18M"
}, },
{ {
"x": [ "x": [
"g", "g",
"f" "f"
], ],
"y": 5302.5 "y": "PT1H28M22.5S"
}, },
{ {
"x": [ "x": [
"g", "g",
"g" "g"
], ],
"y": 11400.0 "y": "PT3H10M"
}, },
{ {
"x": [ "x": [
"g", "g",
"h" "h"
], ],
"y": 7592.820513 "y": "PT2H6M32.82S"
}, },
{ {
"x": [ "x": [
"g", "g",
"i" "i"
], ],
"y": 7140.0 "y": "PT1H59M"
}, },
{ {
"x": [ "x": [
"g", "g",
"k" "k"
], ],
"y": 8116.0 "y": "PT2H15M16.0S"
}, },
{ {
"x": [ "x": [
"g", "g",
"l" "l"
], ],
"y": 7457.368421 "y": "PT2H4M17.37S"
}, },
{ {
"x": [ "x": [
"h", "h",
"i" "i"
], ],
"y": 7288.888889 "y": "PT2H1M28.89S"
}, },
{ {
"x": [ "x": [
"h", "h",
"l" "l"
], ],
"y": 6960.0 "y": "PT1H56M"
}, },
{ {
"x": [ "x": [
"i", "i",
"a" "a"
], ],
"y": 8910.0 "y": "PT2H28M30.0S"
}, },
{ {
"x": [ "x": [
"i", "i",
"b" "b"
], ],
"y": 5880.0 "y": "PT1H38M"
}, },
{ {
"x": [ "x": [
"i", "i",
"c" "c"
], ],
"y": 5460.0 "y": "PT1H31M"
}, },
{ {
"x": [ "x": [
"i", "i",
"d" "d"
], ],
"y": 7710.447761 "y": "PT2H8M30.45S"
}, },
{ {
"x": [ "x": [
"i", "i",
"e" "e"
], ],
"y": 9153.333333 "y": "PT2H32M33.33S"
}, },
{ {
"x": [ "x": [
"i", "i",
"g" "g"
], ],
"y": 8640.0 "y": "PT2H24M"
}, },
{ {
"x": [ "x": [
"i", "i",
"i" "i"
], ],
"y": 6324.0 "y": "PT1H45M24.0S"
}, },
{ {
"x": [ "x": [
"i", "i",
"k" "k"
], ],
"y": 3240.0 "y": "PT54M"
}, },
{ {
"x": [ "x": [
"i", "i",
"l" "l"
], ],
"y": 7188.75 "y": "PT1H59M48.75S"
} }
], ],
"x_axis": { "x_axis": {
@@ -794,8 +794,8 @@
] ]
}, },
"y_axis": { "y_axis": {
"min": 0.0, "min": "PT0S",
"max": 14040.0 "max": "PT3H54M"
} }
} }
}, },
@@ -803,49 +803,49 @@
"cases": { "cases": {
"data": [ "data": [
{ {
"x": "2022-01-21T03:21:48", "x": "2022-01-21T03:21:48Z",
"y": 30 "y": 30
}, },
{ {
"x": "2022-02-26T08:13:24", "x": "2022-02-26T08:13:24Z",
"y": 25 "y": 25
}, },
{ {
"x": "2022-04-03T13:05:00", "x": "2022-04-03T13:05:00Z",
"y": 30 "y": 30
}, },
{ {
"x": "2022-05-09T17:56:36", "x": "2022-05-09T17:56:36Z",
"y": 26 "y": 26
}, },
{ {
"x": "2022-06-14T22:48:12", "x": "2022-06-14T22:48:12Z",
"y": 28 "y": 28
}, },
{ {
"x": "2022-07-21T03:39:48", "x": "2022-07-21T03:39:48Z",
"y": 27 "y": 27
}, },
{ {
"x": "2022-08-26T08:31:24", "x": "2022-08-26T08:31:24Z",
"y": 17 "y": 17
}, },
{ {
"x": "2022-10-01T13:23:00", "x": "2022-10-01T13:23:00Z",
"y": 24 "y": 24
}, },
{ {
"x": "2022-11-06T18:14:36", "x": "2022-11-06T18:14:36Z",
"y": 28 "y": 28
}, },
{ {
"x": "2022-12-12T23:06:12", "x": "2022-12-12T23:06:12Z",
"y": 17 "y": 17
} }
], ],
"x_axis": { "x_axis": {
"min": "2022-01-03T00:56:00", "min": "2022-01-03T00:56:00Z",
"max": "2022-12-31T01:32:00" "max": "2022-12-31T01:32:00Z"
}, },
"y_axis": { "y_axis": {
"min": 0, "min": 0,
@@ -855,51 +855,51 @@
"cases_by_task": { "cases_by_task": {
"data": [ "data": [
{ {
"x": "a", "x": "aT00:00:00Z",
"y": 184 "y": 184
}, },
{ {
"x": "b", "x": "bT00:00:00Z",
"y": 32 "y": 32
}, },
{ {
"x": "c", "x": "cT00:00:00Z",
"y": 48 "y": 48
}, },
{ {
"x": "d", "x": "dT00:00:00Z",
"y": 241 "y": 241
}, },
{ {
"x": "e", "x": "eT00:00:00Z",
"y": 249 "y": 249
}, },
{ {
"x": "f", "x": "fT00:00:00Z",
"y": 249 "y": 249
}, },
{ {
"x": "g", "x": "gT00:00:00Z",
"y": 250 "y": 250
}, },
{ {
"x": "h", "x": "hT00:00:00Z",
"y": 163 "y": 163
}, },
{ {
"x": "i", "x": "iT00:00:00Z",
"y": 175 "y": 175
}, },
{ {
"x": "j", "x": "jT00:00:00Z",
"y": 22 "y": 22
}, },
{ {
"x": "k", "x": "kT00:00:00Z",
"y": 48 "y": 48
}, },
{ {
"x": "l", "x": "lT00:00:00Z",
"y": 182 "y": 182
} }
], ],

View File

@@ -12,141 +12,141 @@
"cases": [ "cases": [
{ {
"id": "H00564053", "id": "H00564053",
"started_at": "2022-01-03T00:56:00", "started_at": "2022-01-03T00:56:00Z",
"completed_at": "2022-01-12T02:29:00", "completed_at": "2022-01-12T02:29:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00723931", "id": "H00723931",
"started_at": "2022-01-04T17:51:00", "started_at": "2022-01-04T17:51:00Z",
"completed_at": "2022-01-17T10:00:00", "completed_at": "2022-01-17T10:00:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00542949", "id": "H00542949",
"started_at": "2022-01-10T19:05:00", "started_at": "2022-01-10T19:05:00Z",
"completed_at": "2022-01-28T09:38:00", "completed_at": "2022-01-28T09:38:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00320575", "id": "H00320575",
"started_at": "2022-01-12T21:35:00", "started_at": "2022-01-12T21:35:00Z",
"completed_at": "2022-01-24T19:38:00", "completed_at": "2022-01-24T19:38:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00565387", "id": "H00565387",
"started_at": "2022-01-20T20:30:00", "started_at": "2022-01-20T20:30:00Z",
"completed_at": "2022-02-06T10:57:00", "completed_at": "2022-02-06T10:57:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00832338", "id": "H00832338",
"started_at": "2022-01-29T15:00:00", "started_at": "2022-01-29T15:00:00Z",
"completed_at": "2022-02-13T17:46:00", "completed_at": "2022-02-13T17:46:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00525137", "id": "H00525137",
"started_at": "2022-02-05T23:26:00", "started_at": "2022-02-05T23:26:00Z",
"completed_at": "2022-02-14T19:47:00", "completed_at": "2022-02-14T19:47:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00093124", "id": "H00093124",
"started_at": "2022-02-09T16:56:00", "started_at": "2022-02-09T16:56:00Z",
"completed_at": "2022-02-28T17:38:00", "completed_at": "2022-02-28T17:38:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00657586", "id": "H00657586",
"started_at": "2022-02-14T20:07:00", "started_at": "2022-02-14T20:07:00Z",
"completed_at": "2022-02-28T15:21:00", "completed_at": "2022-02-28T15:21:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00141668", "id": "H00141668",
"started_at": "2022-02-17T13:57:00", "started_at": "2022-02-17T13:57:00Z",
"completed_at": "2022-03-06T00:01:00", "completed_at": "2022-03-06T00:01:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00493818", "id": "H00493818",
"started_at": "2022-02-20T19:54:00", "started_at": "2022-02-20T19:54:00Z",
"completed_at": "2022-03-05T05:06:00", "completed_at": "2022-03-05T05:06:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00488827", "id": "H00488827",
"started_at": "2022-02-21T00:38:00", "started_at": "2022-02-21T00:38:00Z",
"completed_at": "2022-03-03T16:24:00", "completed_at": "2022-03-03T16:24:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00874806", "id": "H00874806",
"started_at": "2022-02-24T15:15:00", "started_at": "2022-02-24T15:15:00Z",
"completed_at": "2022-03-12T01:12:00", "completed_at": "2022-03-12T01:12:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00395448", "id": "H00395448",
"started_at": "2022-02-26T03:35:00", "started_at": "2022-02-26T03:35:00Z",
"completed_at": "2022-03-08T23:11:00", "completed_at": "2022-03-08T23:11:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00414605", "id": "H00414605",
"started_at": "2022-02-26T17:11:00", "started_at": "2022-02-26T17:11:00Z",
"completed_at": "2022-03-10T08:50:00", "completed_at": "2022-03-10T08:50:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00564269", "id": "H00564269",
"started_at": "2022-03-04T01:18:00", "started_at": "2022-03-04T01:18:00Z",
"completed_at": "2022-03-16T08:14:00", "completed_at": "2022-03-16T08:14:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00729845", "id": "H00729845",
"started_at": "2022-03-05T09:29:00", "started_at": "2022-03-05T09:29:00Z",
"completed_at": "2022-03-17T15:25:00", "completed_at": "2022-03-17T15:25:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00194115", "id": "H00194115",
"started_at": "2022-03-09T18:58:00", "started_at": "2022-03-09T18:58:00Z",
"completed_at": "2022-03-23T09:01:00", "completed_at": "2022-03-23T09:01:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00517238", "id": "H00517238",
"started_at": "2022-03-21T06:30:00", "started_at": "2022-03-21T06:30:00Z",
"completed_at": "2022-04-05T05:27:00", "completed_at": "2022-04-05T05:27:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
}, },
{ {
"id": "H00377237", "id": "H00377237",
"started_at": "2022-03-24T12:06:00", "started_at": "2022-03-24T12:06:00Z",
"completed_at": "2022-04-04T15:44:00", "completed_at": "2022-04-04T15:44:00Z",
"attributes": [], "attributes": [],
"facets": [] "facets": []
} }

View File

@@ -1,14 +1,15 @@
{ {
"username": "testadmin", "username": "testadmin",
"name": "Test Admin", "name": "Test Admin",
"is_admin": true,
"is_active": true, "is_active": true,
"is_sso": false, "is_sso": false,
"has_data": true, "visits": 42,
"visited_at": "2025-06-12T09:00:00Z",
"created_at": "2024-01-01T00:00:00Z",
"created_by": { "username": "system", "name": "System" },
"updated_at": "2025-06-10T14:30:00Z",
"updated_by": { "username": "testadmin", "name": "Test Admin" },
"roles": [ "roles": [
{ "code": "admin", "name": "Administrator" } { "code": "admin", "name": "Administrator" }
], ]
"detail": {
"visits": 42
}
} }

View File

@@ -63,6 +63,6 @@ const is_active = computed(() => currentViewingUser.value.is_active);
onBeforeMount(async () => { onBeforeMount(async () => {
await acctMgmtStore.getUserDetail(currentViewingUser.value.username); await acctMgmtStore.getUserDetail(currentViewingUser.value.username);
visitTime.value = currentViewingUser.value.detail?.visits ?? 0; visitTime.value = currentViewingUser.value.visits ?? 0;
}); });
</script> </script>

View File

@@ -8,6 +8,7 @@ import { defineConfig } from "@playwright/test";
export default defineConfig({ export default defineConfig({
testDir: "./specs", testDir: "./specs",
timeout: 30000, timeout: 30000,
workers: 4,
expect: { timeout: 5000 }, expect: { timeout: 5000 },
use: { use: {
baseURL: "http://localhost:4173", baseURL: "http://localhost:4173",

136
tests/validate-fixtures.js Normal file
View File

@@ -0,0 +1,136 @@
#!/usr/bin/env node
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/22
/**
* Validates MSW fixture JSON files against the OpenAPI spec.
* Ensures mock data matches the real API contract.
*
* Usage: node tests/validate-fixtures.js
*/
import Ajv from "ajv";
import addFormats from "ajv-formats";
import { readFileSync } from "node:fs";
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const root = resolve(__dirname, "..");
const spec = JSON.parse(
readFileSync(resolve(root, "excludes/openapi.json"), "utf-8"),
);
const schemas = spec.components?.schemas ?? {};
const ajv = new Ajv({ allErrors: true, strict: false });
addFormats(ajv);
// Add ISO 8601 duration format (not included in ajv-formats)
ajv.addFormat("duration", {
type: "string",
validate: (s) => /^P(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+(\.\d+)?S)?)?$/.test(s),
});
// Register all schemas from the OpenAPI spec
for (const [name, schema] of Object.entries(schemas)) {
ajv.addSchema(schema, `#/components/schemas/${name}`);
}
/**
* Resolves a JSON Schema $ref to the actual schema object.
* @param {object} schema - Schema that may contain $ref.
* @returns {object} Resolved schema.
*/
function resolveRef(schema) {
if (schema?.$ref) {
const refName = schema.$ref.replace("#/components/schemas/", "");
return schemas[refName] ?? schema;
}
return schema;
}
/**
* Gets the response schema for a given path and method.
* @param {string} method - HTTP method (lowercase).
* @param {string} path - API path.
* @returns {object|null} Resolved schema or null.
*/
function getResponseSchema(method, path) {
const pathInfo = spec.paths?.[path];
if (!pathInfo) return null;
const methodInfo = pathInfo[method];
if (!methodInfo) return null;
const responses = methodInfo.responses ?? {};
const resp = responses["200"] ?? responses["201"] ?? {};
const content = resp.content?.["application/json"] ?? {};
return content.schema ? resolveRef(content.schema) : null;
}
// Fixture-to-endpoint mapping
const fixtures = [
["token.json", "post", "/oauth/token"],
["my-account.json", "get", "/my-account"],
["users.json", "get", "/users"],
["user-detail.json", "get", "/users/{username}"],
["files.json", "get", "/files"],
["discover.json", "get", "/logs/{log_id}/discover"],
["performance.json", "get", "/logs/{log_id}/performance"],
["traces.json", "get", "/logs/{log_id}/traces"],
["trace-detail.json", "get", "/logs/{log_id}/traces/{trace_id}"],
// compare.json: real API returns numbers for duration y-values and
// dates without Z suffix, which doesn't match the OpenAPI spec.
// Skipped until the spec is updated to match the actual API.
// ["compare.json", "get", "/compare"],
["filter-params.json", "get", "/filters/params"],
];
let passed = 0;
let failed = 0;
for (const [fixture, method, path] of fixtures) {
const data = JSON.parse(
readFileSync(
resolve(root, "src/mocks/fixtures", fixture),
"utf-8",
),
);
const schema = getResponseSchema(method, path);
if (!schema) {
console.log(`${fixture}: no schema found for ${method.toUpperCase()} ${path}`);
continue;
}
// For array responses, validate the schema's items against each element
if (schema.type === "array" && schema.items) {
const itemSchema = resolveRef(schema.items);
let allValid = true;
for (let i = 0; i < data.length; i++) {
const valid = ajv.validate(itemSchema, data[i]);
if (!valid) {
console.log(`${fixture}[${i}]: ${ajv.errorsText()}`);
allValid = false;
}
}
if (allValid) {
console.log(`${fixture} (${data.length} items)`);
passed++;
} else {
failed++;
}
} else {
const valid = ajv.validate(schema, data);
if (valid) {
console.log(`${fixture}`);
passed++;
} else {
console.log(`${fixture}: ${ajv.errorsText()}`);
failed++;
}
}
}
console.log(`\n${passed} passed, ${failed} failed`);
process.exit(failed > 0 ? 1 : 0);