made unit testing xml compatible

This commit is contained in:
JasonLandbridge
2025-02-05 12:53:53 +01:00
parent aea7a4bf90
commit 401efaf340
4 changed files with 48 additions and 9 deletions

BIN
bun.lockb

Binary file not shown.

View File

@@ -38,7 +38,8 @@
"swagger-cli": "^4.0.4", "swagger-cli": "^4.0.4",
"typescript": "^5.5.4", "typescript": "^5.5.4",
"vite-tsconfig-paths": "^5.0.1", "vite-tsconfig-paths": "^5.0.1",
"vitest": "^2.0.5" "vitest": "^2.0.5",
"xml-js": "^1.6.11"
}, },
"dependencies": { "dependencies": {
"ajv": "^8.17.1", "ajv": "^8.17.1",

View File

@@ -97,8 +97,8 @@ get:
description: "User's email address." description: "User's email address."
example: "zgfuc7krcqfimrmb9lsl5j@protonmail.com" example: "zgfuc7krcqfimrmb9lsl5j@protonmail.com"
recommendationsPlaylistId: recommendationsPlaylistId:
type: string
description: "ID of the user's recommendation playlist." description: "ID of the user's recommendation playlist."
type: ["null", string]
example: "" example: ""
thumb: thumb:
type: string type: string
@@ -133,19 +133,19 @@ get:
- description: "Indicates if the user can manage subtitles." - description: "Indicates if the user can manage subtitles."
- $ref: "../../models/common/PlexBoolean.yaml" - $ref: "../../models/common/PlexBoolean.yaml"
filterAll: filterAll:
type: string type: ["null", string]
description: "Filters applied for all content." description: "Filters applied for all content."
example: "" example: ""
filterMovies: filterMovies:
type: string type: ["null", string]
description: "Filters applied for movies." description: "Filters applied for movies."
example: "" example: ""
filterMusic: filterMusic:
type: string type: ["null", string]
description: "Filters applied for music." description: "Filters applied for music."
example: "" example: ""
filterPhotos: filterPhotos:
type: string type: ["null", string]
description: "Filters applied for photos." description: "Filters applied for photos."
example: "" example: ""
filterTelevision: filterTelevision:

View File

@@ -3,6 +3,7 @@ import Ajv from "ajv"
import addFormats from "ajv-formats" import addFormats from "ajv-formats"
import { expect } from "vitest" import { expect } from "vitest"
import { merge } from "lodash-es" import { merge } from "lodash-es"
import { xml2json } from "xml-js"
/** /**
* Validate a response against the OpenAPI spec * Validate a response against the OpenAPI spec
* NOTE: It accounts for the following scenarios: * NOTE: It accounts for the following scenarios:
@@ -13,12 +14,14 @@ import { merge } from "lodash-es"
* @param type * @param type
* @param statusCode * @param statusCode
* @param response * @param response
* @param responseType
*/ */
export function validateResponseSpec( export function validateResponseSpec(
path: string, path: string,
type: "get" | "post" | "delete", type: "get" | "post" | "delete",
statusCode: number, statusCode: number,
response: any response: any,
responseType: "json" | "xml" = "json"
): void { ): void {
const ajv = new Ajv({ allErrors: true, strict: false }) const ajv = new Ajv({ allErrors: true, strict: false })
@@ -30,9 +33,28 @@ export function validateResponseSpec(
addFormats(ajv) addFormats(ajv)
// Convert JSONPath to JSON Pointer // Convert JSONPath to JSON Pointer
const pathPointer = `/paths/${path.replace(/\//g, `~1`)}/${type}/responses/${statusCode}/content/application~1json/schema` const pathPointer = `/paths/${path.replace(/\//g, `~1`)}/${type}/responses/${statusCode}/content/application~1${responseType}/schema`
const validate = ajv.validate({ $ref: "API.yaml#" + pathPointer }, response) let jsonResponse = response
if (responseType === "xml") {
const x = response.replace(/=""/g, '="a"')
jsonResponse = flattenAttributes(
JSON.parse(
xml2json(x, {
compact: true,
ignoreDeclaration: true,
nativeType: true,
// @ts-ignore
nativeTypeAttributes: true
})
)
)
}
const validate = ajv.validate(
{ $ref: "API.yaml#" + pathPointer },
jsonResponse
)
if (!validate) { if (!validate) {
console.error(ajv.errors) console.error(ajv.errors)
@@ -78,3 +100,19 @@ function addAdditionalProperties(schema) {
} }
} }
} }
function flattenAttributes(obj: any): any {
if (Array.isArray(obj)) {
return obj.map(flattenAttributes)
} else if (typeof obj === "object" && obj !== null) {
if ("_attributes" in obj) {
Object.assign(obj, obj._attributes)
delete obj._attributes
}
// Recursively process all properties
for (const key in obj) {
obj[key] = flattenAttributes(obj[key])
}
}
return obj
}