feat(codegen:test): coverage x-expanded-relation + x-codegen.queryParams (#3675)
## What Adding tests to cover `x-expanded-relation` and `x-codegen.queryParams` handling ## Why The logic that processes these OAS extension can be complex to reason with. Therefore, we should have automated tests to prevent unintentional regression. ## How * Focus on `getModels` method and its sub-routines. * Add coverage to getOperation codegen parsing. * Add coverage to model and operation spec property.
This commit is contained in:
1 parent
dd1e86b0d4
commit
0b3c6fde30
15 files changed
+900
-49
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/openapi-typescript-codegen": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(codegen:test): coverage x-expanded-relation + x-codegen.queryParams
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
module.exports = {
|
||||||
|
globals: {
|
||||||
|
"ts-jest": {
|
||||||
|
tsConfig: "tsconfig.json",
|
||||||
|
isolatedModules: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
transform: {
|
||||||
|
"^.+\\.[jt]s?$": "ts-jest",
|
||||||
|
},
|
||||||
|
testEnvironment: `node`,
|
||||||
|
moduleFileExtensions: [`js`, `ts`],
|
||||||
|
testTimeout: 30000,
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
"prepare": "cross-env NODE_ENV=production yarn run release",
|
"prepare": "cross-env NODE_ENV=production yarn run release",
|
||||||
"build": "rollup --config --environment NODE_ENV:development",
|
"build": "rollup --config --environment NODE_ENV:development",
|
||||||
"release": "rollup --config --environment NODE_ENV:production",
|
"release": "rollup --config --environment NODE_ENV:production",
|
||||||
"test": "jest --passWithNoTests"
|
"test": "jest src"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"camelcase": "^6.3.0",
|
"camelcase": "^6.3.0",
|
||||||
@@ -49,12 +49,12 @@
|
|||||||
"abort-controller": "3.0.0",
|
"abort-controller": "3.0.0",
|
||||||
"axios": "1.2.0",
|
"axios": "1.2.0",
|
||||||
"form-data": "4.0.0",
|
"form-data": "4.0.0",
|
||||||
"jest": "26.6.3",
|
"jest": "^25.5.4",
|
||||||
"jest-cli": "26.6.3",
|
|
||||||
"node-fetch": "2.6.7",
|
"node-fetch": "2.6.7",
|
||||||
"qs": "6.10.3",
|
"qs": "6.10.3",
|
||||||
"rollup": "3.9.1",
|
"rollup": "3.9.1",
|
||||||
"rollup-plugin-terser": "7.0.2",
|
"rollup-plugin-terser": "7.0.2",
|
||||||
|
"ts-jest": "^25.5.1",
|
||||||
"tslib": "2.3.1",
|
"tslib": "2.3.1",
|
||||||
"typescript": "4.9.5"
|
"typescript": "4.9.5"
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ import type { OpenApiResponse } from "./OpenApiResponse"
|
|||||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responsesObject
|
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responsesObject
|
||||||
*/
|
*/
|
||||||
export interface OpenApiResponses extends OpenApiReference {
|
export interface OpenApiResponses extends OpenApiReference {
|
||||||
default: OpenApiResponse
|
default?: OpenApiResponse
|
||||||
|
|
||||||
[httpcode: string]: OpenApiResponse
|
[httpcode: string]: OpenApiResponse
|
||||||
}
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
import { getModel } from "../getModel"
|
||||||
|
import { OpenApi } from "../../interfaces/OpenApi"
|
||||||
|
import { Model } from "../../../../client/interfaces/Model"
|
||||||
|
import { OpenApiSchema } from "../../interfaces/OpenApiSchema"
|
||||||
|
|
||||||
|
describe("getModel", () => {
|
||||||
|
let openApi: OpenApi
|
||||||
|
beforeEach(async () => {
|
||||||
|
openApi = {
|
||||||
|
openapi: "3.0.0",
|
||||||
|
info: {
|
||||||
|
title: "Test",
|
||||||
|
version: "1.0.0",
|
||||||
|
},
|
||||||
|
paths: {},
|
||||||
|
components: {},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should set model spec with definition", () => {
|
||||||
|
const modelName = "OrderRes"
|
||||||
|
const definition: OpenApiSchema = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const model: Model = getModel(openApi, definition, true, modelName)
|
||||||
|
expect(model.spec).toEqual(definition)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should set property spec with definition", () => {
|
||||||
|
const modelName = "OrderRes"
|
||||||
|
const definition: OpenApiSchema = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
order: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const model: Model = getModel(openApi, definition, true, modelName)
|
||||||
|
expect(model.properties[0].spec).toEqual(definition.properties!.order)
|
||||||
|
})
|
||||||
|
})
|
||||||
+169
@@ -0,0 +1,169 @@
|
|||||||
|
import { getModels } from "../getModels"
|
||||||
|
import { OpenApi } from "../../interfaces/OpenApi"
|
||||||
|
|
||||||
|
describe("getModels", () => {
|
||||||
|
let openApi: OpenApi
|
||||||
|
beforeEach(async () => {
|
||||||
|
openApi = {
|
||||||
|
openapi: "3.0.0",
|
||||||
|
info: {
|
||||||
|
title: "Test",
|
||||||
|
version: "1.0.0",
|
||||||
|
},
|
||||||
|
paths: {},
|
||||||
|
components: {},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should return an empty array if no models are found", () => {
|
||||||
|
const models = getModels(openApi)
|
||||||
|
expect(models).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should return an array of models", () => {
|
||||||
|
openApi.components = {
|
||||||
|
schemas: {
|
||||||
|
OrderRes: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const models = getModels(openApi)
|
||||||
|
expect(models).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
name: "OrderRes",
|
||||||
|
properties: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
name: "id",
|
||||||
|
type: "string",
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should return an array of models with expanded relations", () => {
|
||||||
|
openApi.components = {
|
||||||
|
schemas: {
|
||||||
|
OrderRes: {
|
||||||
|
type: "object",
|
||||||
|
"x-expanded-relations": {
|
||||||
|
field: "order",
|
||||||
|
relations: ["region", "region.country"],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
order: {
|
||||||
|
$ref: "#/components/schemas/Order",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Order: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
region: {
|
||||||
|
$ref: "#/components/schemas/Region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Region: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
country: {
|
||||||
|
$ref: "#/components/schemas/Country",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Country: {
|
||||||
|
type: "object",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const models = getModels(openApi)
|
||||||
|
expect(models).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
name: "OrderRes",
|
||||||
|
properties: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
name: "order",
|
||||||
|
base: "Order",
|
||||||
|
nestedRelations: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
base: "Order",
|
||||||
|
field: "order",
|
||||||
|
nestedRelations: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
field: "region",
|
||||||
|
base: "Region",
|
||||||
|
nestedRelations: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
base: "Country",
|
||||||
|
field: "country",
|
||||||
|
nestedRelations: [],
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should convert query parameters into a schema when x-codegen.queryParams is declared", () => {
|
||||||
|
openApi.paths = {
|
||||||
|
"/": {
|
||||||
|
get: {
|
||||||
|
operationId: "GetOrder",
|
||||||
|
"x-codegen": {
|
||||||
|
queryParams: "GetOrderQueryParams",
|
||||||
|
},
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
description: "Limit the number of results",
|
||||||
|
in: "query",
|
||||||
|
name: "limit",
|
||||||
|
schema: {
|
||||||
|
type: "integer",
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
deprecated: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "OK",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const models = getModels(openApi)
|
||||||
|
expect(models).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
name: "GetOrderQueryParams",
|
||||||
|
properties: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
description: "Limit the number of results",
|
||||||
|
name: "limit",
|
||||||
|
type: "number",
|
||||||
|
isRequired: true,
|
||||||
|
deprecated: true,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
+436
@@ -0,0 +1,436 @@
|
|||||||
|
import { Model } from "../../../../client/interfaces/Model"
|
||||||
|
import { handleExpandedRelations } from "../getModelsExpandedRelations"
|
||||||
|
import { getModel } from "../getModel"
|
||||||
|
import { OpenApi } from "../../interfaces/OpenApi"
|
||||||
|
import { OpenApiSchema } from "../../interfaces/OpenApiSchema"
|
||||||
|
import { getType } from "../getType"
|
||||||
|
|
||||||
|
function getModelsTest(openApi: OpenApi): Model[] {
|
||||||
|
const models: Model[] = []
|
||||||
|
if (openApi.components) {
|
||||||
|
for (const definitionName in openApi.components.schemas) {
|
||||||
|
if (openApi.components.schemas.hasOwnProperty(definitionName)) {
|
||||||
|
const definition = openApi.components.schemas[definitionName]
|
||||||
|
const definitionType = getType(definitionName)
|
||||||
|
const model = getModel(openApi, definition, true, definitionType.base)
|
||||||
|
models.push(model)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return models
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("getModelsExpandedRelations", () => {
|
||||||
|
let openApi: OpenApi
|
||||||
|
beforeEach(async () => {
|
||||||
|
openApi = {
|
||||||
|
openapi: "3.0.0",
|
||||||
|
info: {
|
||||||
|
title: "Test",
|
||||||
|
version: "1.0.0",
|
||||||
|
},
|
||||||
|
paths: {},
|
||||||
|
components: {
|
||||||
|
schemas: {
|
||||||
|
Order: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
region: {
|
||||||
|
$ref: "#/components/schemas/Region",
|
||||||
|
},
|
||||||
|
total: {
|
||||||
|
type: "number",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Region: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
country: {
|
||||||
|
$ref: "#/components/schemas/Country",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Country: {
|
||||||
|
type: "object",
|
||||||
|
},
|
||||||
|
Customer: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
orders: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
$ref: "#/components/schemas/Order",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("basic use cases", () => {
|
||||||
|
it("should find nested relation - model", () => {
|
||||||
|
const modelName: string = "OrderRes"
|
||||||
|
const definition: OpenApiSchema = {
|
||||||
|
type: "object",
|
||||||
|
"x-expanded-relations": {
|
||||||
|
field: "order",
|
||||||
|
relations: ["region"],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
order: {
|
||||||
|
$ref: "#/components/schemas/Order",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const model: Model = getModel(openApi, definition, true, modelName)
|
||||||
|
const models: Model[] = [...getModelsTest(openApi), model]
|
||||||
|
|
||||||
|
handleExpandedRelations(model, models)
|
||||||
|
|
||||||
|
expect(model.properties[0].nestedRelations).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
field: "order",
|
||||||
|
base: "Order",
|
||||||
|
isArray: false,
|
||||||
|
nestedRelations: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
field: "region",
|
||||||
|
base: "Region",
|
||||||
|
isArray: false,
|
||||||
|
nestedRelations: [],
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should find nested relation - shallow", () => {
|
||||||
|
const modelName: string = "OrderRes"
|
||||||
|
const definition: OpenApiSchema = {
|
||||||
|
type: "object",
|
||||||
|
"x-expanded-relations": {
|
||||||
|
field: "order",
|
||||||
|
relations: ["total"],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
order: {
|
||||||
|
$ref: "#/components/schemas/Order",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const model: Model = getModel(openApi, definition, true, modelName)
|
||||||
|
const models: Model[] = [...getModelsTest(openApi), model]
|
||||||
|
|
||||||
|
handleExpandedRelations(model, models)
|
||||||
|
|
||||||
|
expect(model.properties[0].nestedRelations).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
field: "order",
|
||||||
|
base: "Order",
|
||||||
|
isArray: false,
|
||||||
|
nestedRelations: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
field: "total",
|
||||||
|
nestedRelations: [],
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should find nested relation - array", () => {
|
||||||
|
const modelName: string = "CustomerRes"
|
||||||
|
const definition: OpenApiSchema = {
|
||||||
|
type: "object",
|
||||||
|
"x-expanded-relations": {
|
||||||
|
field: "customer",
|
||||||
|
relations: ["orders"],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
customer: {
|
||||||
|
$ref: "#/components/schemas/Customer",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const model: Model = getModel(openApi, definition, true, modelName)
|
||||||
|
const models: Model[] = [...getModelsTest(openApi), model]
|
||||||
|
|
||||||
|
handleExpandedRelations(model, models)
|
||||||
|
|
||||||
|
expect(model.properties[0].nestedRelations).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
field: "customer",
|
||||||
|
base: "Customer",
|
||||||
|
isArray: false,
|
||||||
|
nestedRelations: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
field: "orders",
|
||||||
|
base: "Order",
|
||||||
|
isArray: true,
|
||||||
|
nestedRelations: [],
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("misc usage", () => {
|
||||||
|
it.each([["allOf"], ["anyOf"], ["oneOf"]])(
|
||||||
|
"should findPropInCombination - %s",
|
||||||
|
(combination) => {
|
||||||
|
openApi.components!.schemas!.ExpandedOrder = {
|
||||||
|
[combination]: [{ $ref: "#/components/schemas/Order" }],
|
||||||
|
}
|
||||||
|
const modelName: string = "OrderRes"
|
||||||
|
const definition: OpenApiSchema = {
|
||||||
|
type: "object",
|
||||||
|
"x-expanded-relations": {
|
||||||
|
field: "order",
|
||||||
|
relations: ["region"],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
order: {
|
||||||
|
$ref: "#/components/schemas/ExpandedOrder",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const model: Model = getModel(openApi, definition, true, modelName)
|
||||||
|
const models: Model[] = [...getModelsTest(openApi), model]
|
||||||
|
|
||||||
|
handleExpandedRelations(model, models)
|
||||||
|
|
||||||
|
expect(model.properties[0].nestedRelations).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
nestedRelations: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
field: "region",
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
it.each([["relations"], ["totals"], ["implicit"], ["eager"]])(
|
||||||
|
"should find nested relation with relation type - %s",
|
||||||
|
(relationType) => {
|
||||||
|
const modelName: string = "OrderRes"
|
||||||
|
const definition: OpenApiSchema = {
|
||||||
|
type: "object",
|
||||||
|
"x-expanded-relations": {
|
||||||
|
field: "order",
|
||||||
|
[relationType]: ["region"],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
order: {
|
||||||
|
$ref: "#/components/schemas/Order",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const model: Model = getModel(openApi, definition, true, modelName)
|
||||||
|
const models: Model[] = [...getModelsTest(openApi), model]
|
||||||
|
|
||||||
|
handleExpandedRelations(model, models)
|
||||||
|
|
||||||
|
expect(model.properties[0].nestedRelations).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
nestedRelations: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
field: "region",
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
it("should set field hasDepth - true", () => {
|
||||||
|
const modelName: string = "OrderRes"
|
||||||
|
const definition: OpenApiSchema = {
|
||||||
|
type: "object",
|
||||||
|
"x-expanded-relations": {
|
||||||
|
field: "order",
|
||||||
|
relations: ["region.country"],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
order: {
|
||||||
|
$ref: "#/components/schemas/Order",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const model: Model = getModel(openApi, definition, true, modelName)
|
||||||
|
const models: Model[] = [...getModelsTest(openApi), model]
|
||||||
|
|
||||||
|
handleExpandedRelations(model, models)
|
||||||
|
|
||||||
|
expect(model.properties[0].nestedRelations).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
hasDepth: true,
|
||||||
|
nestedRelations: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
field: "region",
|
||||||
|
nestedRelations: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
field: "country",
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should set relation hasDepth - true", () => {
|
||||||
|
const modelName: string = "CustomerRes"
|
||||||
|
const definition: OpenApiSchema = {
|
||||||
|
type: "object",
|
||||||
|
"x-expanded-relations": {
|
||||||
|
field: "customer",
|
||||||
|
relations: ["orders.region.country"],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
customer: {
|
||||||
|
$ref: "#/components/schemas/Customer",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const model: Model = getModel(openApi, definition, true, modelName)
|
||||||
|
const models: Model[] = [...getModelsTest(openApi), model]
|
||||||
|
|
||||||
|
handleExpandedRelations(model, models)
|
||||||
|
|
||||||
|
expect(model.properties[0].nestedRelations).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
hasDepth: true,
|
||||||
|
nestedRelations: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
field: "orders",
|
||||||
|
hasDepth: true,
|
||||||
|
nestedRelations: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
field: "region",
|
||||||
|
nestedRelations: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
field: "country",
|
||||||
|
nestedRelations: [],
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should add models with relation to root model imports, only once", () => {
|
||||||
|
const modelName: string = "OrderRes"
|
||||||
|
const definition: OpenApiSchema = {
|
||||||
|
type: "object",
|
||||||
|
"x-expanded-relations": {
|
||||||
|
field: "order",
|
||||||
|
relations: ["region", "region.country"],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
order: {
|
||||||
|
$ref: "#/components/schemas/Order",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const model: Model = getModel(openApi, definition, true, modelName)
|
||||||
|
const models: Model[] = [...getModelsTest(openApi), model]
|
||||||
|
|
||||||
|
handleExpandedRelations(model, models)
|
||||||
|
|
||||||
|
expect(model.imports).toEqual(expect.arrayContaining(["Order", "Region"]))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("errors", () => {
|
||||||
|
it("should throw if field is not found", () => {
|
||||||
|
const modelName: string = "OrderRes"
|
||||||
|
const definition: OpenApiSchema = {
|
||||||
|
type: "object",
|
||||||
|
"x-expanded-relations": {
|
||||||
|
field: "nope",
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
order: {
|
||||||
|
$ref: "#/components/schemas/Order",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const model: Model = getModel(openApi, definition, true, modelName)
|
||||||
|
const models: Model[] = [...getModelsTest(openApi), model]
|
||||||
|
|
||||||
|
expect(() => handleExpandedRelations(model, models)).toThrow(
|
||||||
|
"x-expanded-relations - field not found"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw if relation is not found", () => {
|
||||||
|
const modelName: string = "OrderRes"
|
||||||
|
const definition: OpenApiSchema = {
|
||||||
|
type: "object",
|
||||||
|
"x-expanded-relations": {
|
||||||
|
field: "order",
|
||||||
|
relations: ["nope"],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
order: {
|
||||||
|
$ref: "#/components/schemas/Order",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const model: Model = getModel(openApi, definition, true, modelName)
|
||||||
|
const models: Model[] = [...getModelsTest(openApi), model]
|
||||||
|
|
||||||
|
expect(() => handleExpandedRelations(model, models)).toThrow(
|
||||||
|
"x-expanded-relations - relation not found"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.each([["allOf"], ["anyOf"], ["oneOf"]])(
|
||||||
|
"should throw if field exports as a combination - %s",
|
||||||
|
(combination) => {
|
||||||
|
const modelName: string = "OrderRes"
|
||||||
|
const definition: OpenApiSchema = {
|
||||||
|
type: "object",
|
||||||
|
"x-expanded-relations": {
|
||||||
|
field: "order",
|
||||||
|
relations: ["region"],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
order: {
|
||||||
|
[combination]: [{ $ref: "#/components/schemas/Order" }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const model: Model = getModel(openApi, definition, true, modelName)
|
||||||
|
const models: Model[] = [...getModelsTest(openApi), model]
|
||||||
|
|
||||||
|
expect(() => handleExpandedRelations(model, models)).toThrow(
|
||||||
|
"x-expanded-relations - unsupported - field referencing multiple models"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
import { OpenApi } from "../../interfaces/OpenApi"
|
||||||
|
import { OpenApiOperation } from "../../interfaces/OpenApiOperation"
|
||||||
|
import { getOperation } from "../getOperation"
|
||||||
|
import { getOperationParameters } from "../getOperationParameters"
|
||||||
|
|
||||||
|
describe("getOperation", () => {
|
||||||
|
let openApi: OpenApi
|
||||||
|
beforeEach(async () => {
|
||||||
|
openApi = {
|
||||||
|
openapi: "3.0.0",
|
||||||
|
info: {
|
||||||
|
title: "Test",
|
||||||
|
version: "1.0.0",
|
||||||
|
},
|
||||||
|
paths: {},
|
||||||
|
components: {},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should parse x-codegen", () => {
|
||||||
|
const op: OpenApiOperation = {
|
||||||
|
"x-codegen": {
|
||||||
|
method: "list",
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "OK",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const pathParams = getOperationParameters(openApi, [])
|
||||||
|
const operation = getOperation(
|
||||||
|
openApi,
|
||||||
|
"/orders",
|
||||||
|
"get",
|
||||||
|
"Orders",
|
||||||
|
op,
|
||||||
|
pathParams
|
||||||
|
)
|
||||||
|
expect(operation).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
codegen: { method: "list" },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should add x-codegen.queryParams to imports", () => {
|
||||||
|
const op: OpenApiOperation = {
|
||||||
|
"x-codegen": {
|
||||||
|
queryParams: "OrdersQueryParams",
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "OK",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const pathParams = getOperationParameters(openApi, [])
|
||||||
|
const operation = getOperation(
|
||||||
|
openApi,
|
||||||
|
"/orders",
|
||||||
|
"get",
|
||||||
|
"Orders",
|
||||||
|
op,
|
||||||
|
pathParams
|
||||||
|
)
|
||||||
|
expect(operation.imports).toEqual(
|
||||||
|
expect.arrayContaining(["OrdersQueryParams"])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
import { OpenApi } from "../../interfaces/OpenApi"
|
||||||
|
import { getOperationParameter } from "../getOperationParameter"
|
||||||
|
import { OpenApiParameter } from "../../interfaces/OpenApiParameter"
|
||||||
|
|
||||||
|
describe("getOperation", () => {
|
||||||
|
let openApi: OpenApi
|
||||||
|
beforeEach(async () => {
|
||||||
|
openApi = {
|
||||||
|
openapi: "3.0.0",
|
||||||
|
info: {
|
||||||
|
title: "Test",
|
||||||
|
version: "1.0.0",
|
||||||
|
},
|
||||||
|
paths: {},
|
||||||
|
components: {},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should set spec with definition", () => {
|
||||||
|
const parameter: OpenApiParameter = {
|
||||||
|
name: "id",
|
||||||
|
in: "path",
|
||||||
|
}
|
||||||
|
const operationParameter = getOperationParameter(openApi, parameter)
|
||||||
|
expect(operationParameter.spec).toEqual(parameter)
|
||||||
|
})
|
||||||
|
})
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
import { OpenApi } from "../../interfaces/OpenApi"
|
||||||
|
import { getOperationRequestBody } from "../getOperationRequestBody"
|
||||||
|
import { OpenApiRequestBody } from "../../interfaces/OpenApiRequestBody"
|
||||||
|
|
||||||
|
describe("getOperation", () => {
|
||||||
|
let openApi: OpenApi
|
||||||
|
beforeEach(async () => {
|
||||||
|
openApi = {
|
||||||
|
openapi: "3.0.0",
|
||||||
|
info: {
|
||||||
|
title: "Test",
|
||||||
|
version: "1.0.0",
|
||||||
|
},
|
||||||
|
paths: {},
|
||||||
|
components: {},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should set spec with definition", () => {
|
||||||
|
const body: OpenApiRequestBody = {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const operationRequestBody = getOperationRequestBody(openApi, body)
|
||||||
|
expect(operationRequestBody.spec).toEqual(body)
|
||||||
|
})
|
||||||
|
})
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
import { OpenApi } from "../../interfaces/OpenApi"
|
||||||
|
import { getOperationResponse } from "../getOperationResponse"
|
||||||
|
import { OpenApiResponse } from "../../interfaces/OpenApiResponse"
|
||||||
|
|
||||||
|
describe("getOperation", () => {
|
||||||
|
let openApi: OpenApi
|
||||||
|
beforeEach(async () => {
|
||||||
|
openApi = {
|
||||||
|
openapi: "3.0.0",
|
||||||
|
info: {
|
||||||
|
title: "Test",
|
||||||
|
version: "1.0.0",
|
||||||
|
},
|
||||||
|
paths: {},
|
||||||
|
components: {},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should set spec with definition", () => {
|
||||||
|
const response: OpenApiResponse = {
|
||||||
|
description: "OK",
|
||||||
|
}
|
||||||
|
const operationResponse = getOperationResponse(openApi, response, 200)
|
||||||
|
expect(operationResponse.spec).toEqual(response)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -38,7 +38,7 @@ export const getModelProperties = (
|
|||||||
| "enums"
|
| "enums"
|
||||||
| "properties"
|
| "properties"
|
||||||
> = {
|
> = {
|
||||||
spec: definition,
|
spec: property,
|
||||||
name: escapeName(propertyName),
|
name: escapeName(propertyName),
|
||||||
description: property.description || null,
|
description: property.description || null,
|
||||||
deprecated: property.deprecated === true,
|
deprecated: property.deprecated === true,
|
||||||
|
|||||||
+15
-6
@@ -21,16 +21,21 @@ export const handleExpandedRelations = (model: Model, allModels: Model[]) => {
|
|||||||
walkSplitRelations(nestedRelation, splitRelation, 0)
|
walkSplitRelations(nestedRelation, splitRelation, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
walkNestedRelations(allModels, model, model, nestedRelation)
|
|
||||||
model.imports = [...new Set(model.imports)]
|
|
||||||
|
|
||||||
const prop = getPropertyByName(nestedRelation.field, model)
|
const prop = getPropertyByName(nestedRelation.field, model)
|
||||||
if (!prop) {
|
if (!prop) {
|
||||||
throw new Error(`x-expanded-relations error - field not found
|
throw new Error(`x-expanded-relations - field not found
|
||||||
Schema: ${model.name}
|
Schema: ${model.name}
|
||||||
NestedRelation: ${JSON.stringify(nestedRelation, null, 2)}
|
NestedRelation: ${JSON.stringify(nestedRelation, null, 2)}
|
||||||
Model: ${JSON.stringify(model.spec, null, 2)}`)
|
Model: ${JSON.stringify(model.spec, null, 2)}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
walkNestedRelations(allModels, model, model, nestedRelation)
|
||||||
|
model.imports = [...new Set(model.imports)]
|
||||||
|
/**
|
||||||
|
* To reduce complexity in the exportInterface template, nestedRelations is
|
||||||
|
* set on the property that is the root of the nested relations instead of
|
||||||
|
* setting it on the model.
|
||||||
|
*/
|
||||||
prop.nestedRelations = [nestedRelation]
|
prop.nestedRelations = [nestedRelation]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,17 +68,21 @@ const walkNestedRelations = (
|
|||||||
model: Model,
|
model: Model,
|
||||||
nestedRelation: NestedRelation,
|
nestedRelation: NestedRelation,
|
||||||
parentNestedRelation?: NestedRelation
|
parentNestedRelation?: NestedRelation
|
||||||
) => {
|
): void => {
|
||||||
const prop = ["all-of", "any-of", "one-of"].includes(model.export)
|
const prop = ["all-of", "any-of", "one-of"].includes(model.export)
|
||||||
? findPropInCombination(nestedRelation.field, model, allModels)
|
? findPropInCombination(nestedRelation.field, model, allModels)
|
||||||
: getPropertyByName(nestedRelation.field, model)
|
: getPropertyByName(nestedRelation.field, model)
|
||||||
if (!prop) {
|
if (!prop) {
|
||||||
throw new Error(`x-expanded-relations - field not found
|
throw new Error(`x-expanded-relations - relation not found
|
||||||
Schema: ${rootModel.name}
|
Schema: ${rootModel.name}
|
||||||
NestedRelation: ${JSON.stringify(nestedRelation, null, 2)}
|
NestedRelation: ${JSON.stringify(nestedRelation, null, 2)}
|
||||||
Model: ${JSON.stringify(model.spec, null, 2)}`)
|
Model: ${JSON.stringify(model.spec, null, 2)}`)
|
||||||
}
|
}
|
||||||
if (["all-of", "any-of", "one-of"].includes(prop.export)) {
|
if (["all-of", "any-of", "one-of"].includes(prop.export)) {
|
||||||
|
/**
|
||||||
|
* Root property for nested relations can not use combination strategies.
|
||||||
|
* To use combination, they must be defined in referenced models instead.
|
||||||
|
*/
|
||||||
throw new Error(`x-expanded-relations - unsupported - field referencing multiple models
|
throw new Error(`x-expanded-relations - unsupported - field referencing multiple models
|
||||||
Schema: ${rootModel.name}
|
Schema: ${rootModel.name}
|
||||||
NestedRelation: ${JSON.stringify(nestedRelation, null, 2)}
|
NestedRelation: ${JSON.stringify(nestedRelation, null, 2)}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"include": ["src"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||
@@ -5997,14 +5997,14 @@ __metadata:
|
|||||||
form-data: 4.0.0
|
form-data: 4.0.0
|
||||||
fs-extra: ^10.1.0
|
fs-extra: ^10.1.0
|
||||||
handlebars: ^4.7.7
|
handlebars: ^4.7.7
|
||||||
jest: 26.6.3
|
jest: ^25.5.4
|
||||||
jest-cli: 26.6.3
|
|
||||||
json-schema-ref-parser: ^9.0.9
|
json-schema-ref-parser: ^9.0.9
|
||||||
node-fetch: 2.6.7
|
node-fetch: 2.6.7
|
||||||
pascalcase: ^2.0.0
|
pascalcase: ^2.0.0
|
||||||
qs: 6.10.3
|
qs: 6.10.3
|
||||||
rollup: 3.9.1
|
rollup: 3.9.1
|
||||||
rollup-plugin-terser: 7.0.2
|
rollup-plugin-terser: 7.0.2
|
||||||
|
ts-jest: ^25.5.1
|
||||||
tslib: 2.3.1
|
tslib: 2.3.1
|
||||||
typescript: 4.9.5
|
typescript: 4.9.5
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
@@ -24599,29 +24599,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"jest-cli@npm:26.6.3, jest-cli@npm:^26.6.3":
|
|
||||||
version: 26.6.3
|
|
||||||
resolution: "jest-cli@npm:26.6.3"
|
|
||||||
dependencies:
|
|
||||||
"@jest/core": ^26.6.3
|
|
||||||
"@jest/test-result": ^26.6.2
|
|
||||||
"@jest/types": ^26.6.2
|
|
||||||
chalk: ^4.0.0
|
|
||||||
exit: ^0.1.2
|
|
||||||
graceful-fs: ^4.2.4
|
|
||||||
import-local: ^3.0.2
|
|
||||||
is-ci: ^2.0.0
|
|
||||||
jest-config: ^26.6.3
|
|
||||||
jest-util: ^26.6.2
|
|
||||||
jest-validate: ^26.6.2
|
|
||||||
prompts: ^2.0.1
|
|
||||||
yargs: ^15.4.1
|
|
||||||
bin:
|
|
||||||
jest: bin/jest.js
|
|
||||||
checksum: 3f62c26b300549115bcfc0393d7d49467d414d200bb211a8843fd48d0296ddbfc5e6fe808c64ad2039127657b662e3ba3db44166341bd5db2d089bf09cf82a2c
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"jest-cli@npm:^25.5.4":
|
"jest-cli@npm:^25.5.4":
|
||||||
version: 25.5.4
|
version: 25.5.4
|
||||||
resolution: "jest-cli@npm:25.5.4"
|
resolution: "jest-cli@npm:25.5.4"
|
||||||
@@ -24646,6 +24623,29 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"jest-cli@npm:^26.6.3":
|
||||||
|
version: 26.6.3
|
||||||
|
resolution: "jest-cli@npm:26.6.3"
|
||||||
|
dependencies:
|
||||||
|
"@jest/core": ^26.6.3
|
||||||
|
"@jest/test-result": ^26.6.2
|
||||||
|
"@jest/types": ^26.6.2
|
||||||
|
chalk: ^4.0.0
|
||||||
|
exit: ^0.1.2
|
||||||
|
graceful-fs: ^4.2.4
|
||||||
|
import-local: ^3.0.2
|
||||||
|
is-ci: ^2.0.0
|
||||||
|
jest-config: ^26.6.3
|
||||||
|
jest-util: ^26.6.2
|
||||||
|
jest-validate: ^26.6.2
|
||||||
|
prompts: ^2.0.1
|
||||||
|
yargs: ^15.4.1
|
||||||
|
bin:
|
||||||
|
jest: bin/jest.js
|
||||||
|
checksum: 3f62c26b300549115bcfc0393d7d49467d414d200bb211a8843fd48d0296ddbfc5e6fe808c64ad2039127657b662e3ba3db44166341bd5db2d089bf09cf82a2c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"jest-cli@npm:^27.5.1":
|
"jest-cli@npm:^27.5.1":
|
||||||
version: 27.5.1
|
version: 27.5.1
|
||||||
resolution: "jest-cli@npm:27.5.1"
|
resolution: "jest-cli@npm:27.5.1"
|
||||||
@@ -26298,19 +26298,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"jest@npm:26.6.3, jest@npm:^26.6.3":
|
|
||||||
version: 26.6.3
|
|
||||||
resolution: "jest@npm:26.6.3"
|
|
||||||
dependencies:
|
|
||||||
"@jest/core": ^26.6.3
|
|
||||||
import-local: ^3.0.2
|
|
||||||
jest-cli: ^26.6.3
|
|
||||||
bin:
|
|
||||||
jest: bin/jest.js
|
|
||||||
checksum: 4469f5c426f5b00855e2264dc4fce5ab16c0fab31d2dc6fc829d769ca7ec84a9c74763f7c1d281d085ad55897927a08df2b4778b0df899a66188ff0722e17d29
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"jest@npm:^25.5.2, jest@npm:^25.5.4":
|
"jest@npm:^25.5.2, jest@npm:^25.5.4":
|
||||||
version: 25.5.4
|
version: 25.5.4
|
||||||
resolution: "jest@npm:25.5.4"
|
resolution: "jest@npm:25.5.4"
|
||||||
@@ -26324,6 +26311,19 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"jest@npm:^26.6.3":
|
||||||
|
version: 26.6.3
|
||||||
|
resolution: "jest@npm:26.6.3"
|
||||||
|
dependencies:
|
||||||
|
"@jest/core": ^26.6.3
|
||||||
|
import-local: ^3.0.2
|
||||||
|
jest-cli: ^26.6.3
|
||||||
|
bin:
|
||||||
|
jest: bin/jest.js
|
||||||
|
checksum: 4469f5c426f5b00855e2264dc4fce5ab16c0fab31d2dc6fc829d769ca7ec84a9c74763f7c1d281d085ad55897927a08df2b4778b0df899a66188ff0722e17d29
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"jest@npm:^27.0.6, jest@npm:^27.4.7":
|
"jest@npm:^27.0.6, jest@npm:^27.4.7":
|
||||||
version: 27.5.1
|
version: 27.5.1
|
||||||
resolution: "jest@npm:27.5.1"
|
resolution: "jest@npm:27.5.1"
|
||||||
|
|||||||
Reference in new issue
Block a user