Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions __mocks__/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,27 @@ definitions:
properties:
unlimited:
type: boolean
OneOfPropertyTest:
type: object
description: test if we can use `oneOf` as an object property
properties:
fields:
oneOf:
- type: object
properties:
foo:
type: string
- type: object
properties:
bar:
type: string
- $ref: "#/definitions/Person"
- type: array
items:
type: object
properties:
name:
type: string
AdditionalPropsTest:
type: object
additionalProperties:
Expand Down
21 changes: 21 additions & 0 deletions __mocks__/openapi_v3/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,27 @@ components:
properties:
unlimited:
type: boolean
OneOfPropertyTest:
type: object
description: test if we can use `oneOf` as an object property
properties:
fields:
oneOf:
- type: object
properties:
foo:
type: string
- type: object
properties:
bar:
type: string
- type: array
items:
type: object
properties:
name:
type: string
- $ref: "#/components/schemas/Person"
AllOfWithOneElementTest:
description: test if we can use allOf with just one element inside
allOf:
Expand Down
42 changes: 42 additions & 0 deletions e2e/src/__tests__/test-api-v3/definitions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,3 +417,45 @@ describe("DisjointUnionsUserTest definition", () => {
expect(E.isLeft(enabledUserTest)).toBe(true);
});
});

describe("OneOfPropertyTest definition", () => {
const variant1 = {
fields: {
foo: "foo"
}
};

const variant2 = {
fields: {
bar: "bar"
}
};

const variant3 = {
fields: [
{
name: "name"
}
]
};

const variant4 = {
fields: {
name: "name",
address: "address"
}
};

it.each`
title | example | expected
${"should decode variant 1"} | ${variant1} | ${true}
${"should decode variant 2"} | ${variant2} | ${true}
${"should decode variant 3"} | ${variant3} | ${true}
${"should decode variant 4"} | ${variant4} | ${true}
`("$title", async ({ example, expected }) => {
const { OneOfPropertyTest } = await loadModule("OneOfPropertyTest");
const result = E.isRight(OneOfPropertyTest.decode(example));

expect(result).toEqual(expected);
});
});
42 changes: 42 additions & 0 deletions e2e/src/__tests__/test-api/definitions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,3 +435,45 @@ describe("DisjointUnionsUserTest definition", () => {
expect(E.isLeft(enabledUserTest)).toBe(true);
});
});

describe("OneOfPropertyTest definition", () => {
const variant1 = {
fields: {
foo: "foo"
}
};

const variant2 = {
fields: {
bar: "bar"
}
};

const variant3 = {
fields: [
{
name: "name"
}
]
};

const variant4 = {
fields: {
name: "name",
address: "address"
}
};

it.each`
title | example | expected
${"should decode variant 1"} | ${variant1} | ${true}
${"should decode variant 2"} | ${variant2} | ${true}
${"should decode variant 3"} | ${variant3} | ${true}
${"should decode variant 4"} | ${variant4} | ${true}
`("$title", async ({ example, expected }) => {
const { OneOfPropertyTest } = await loadModule("OneOfPropertyTest");
const result = E.isRight(OneOfPropertyTest.decode(example));

expect(result).toEqual(expected);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,94 @@ export type OneOfTest = t.TypeOf<typeof OneOfTest>;
"
`;

exports[`Openapi V2 |> gen-api-models should generate an object with a union property when that property has oneOf: oneof-property-test 1`] = `
"/**
* Do not edit this file it is auto-generated by io-utils / gen-api-models.
* See https://github.com/pagopa/io-utils
*/
/* eslint-disable */

import * as t from \\"io-ts\\";
import { Person } from \\"./Person\\";

/**
* test if we can use \`oneOf\` as an object property
*/

// required attributes
const OneOfPropertyTestFields1R = t.interface({});

// optional attributes
const OneOfPropertyTestFields1O = t.partial({
foo: t.string
});

export const OneOfPropertyTestFields1 = t.intersection(
[OneOfPropertyTestFields1R, OneOfPropertyTestFields1O],
\\"OneOfPropertyTestFields1\\"
);

export type OneOfPropertyTestFields1 = t.TypeOf<
typeof OneOfPropertyTestFields1
>;

// required attributes
const OneOfPropertyTestFields2R = t.interface({});

// optional attributes
const OneOfPropertyTestFields2O = t.partial({
bar: t.string
});

export const OneOfPropertyTestFields2 = t.intersection(
[OneOfPropertyTestFields2R, OneOfPropertyTestFields2O],
\\"OneOfPropertyTestFields2\\"
);

export type OneOfPropertyTestFields2 = t.TypeOf<
typeof OneOfPropertyTestFields2
>;

export type OneOfPropertyTestFields4 = t.TypeOf<
typeof OneOfPropertyTestFields4
>;
export const OneOfPropertyTestFields4 = t.readonlyArray(
t.object,
\\"array of object\\"
);

export const OneOfPropertyTestFields = t.union(
[
OneOfPropertyTestFields1,

OneOfPropertyTestFields2,

Person,

OneOfPropertyTestFields4
],
\\"OneOfPropertyTestFields\\"
);

export type OneOfPropertyTestFields = t.TypeOf<typeof OneOfPropertyTestFields>;

// required attributes
const OneOfPropertyTestR = t.interface({});

// optional attributes
const OneOfPropertyTestO = t.partial({
fields: OneOfPropertyTestFields
});

export const OneOfPropertyTest = t.intersection(
[OneOfPropertyTestR, OneOfPropertyTestO],
\\"OneOfPropertyTest\\"
);

export type OneOfPropertyTest = t.TypeOf<typeof OneOfPropertyTest>;
"
`;

exports[`Openapi V2 |> gen-api-models should generate decoder definitions for (get, /test-auth-bearer) 1`] = `
"
/****************************************************************
Expand Down Expand Up @@ -2196,6 +2284,94 @@ export type OneOfTest = t.TypeOf<typeof OneOfTest>;
"
`;

exports[`Openapi V3 |> gen-api-models should generate an object with a union property when that property has oneOf: oneof-property-test 1`] = `
"/**
* Do not edit this file it is auto-generated by io-utils / gen-api-models.
* See https://github.com/pagopa/io-utils
*/
/* eslint-disable */

import * as t from \\"io-ts\\";
import { Person } from \\"./Person\\";

/**
* test if we can use \`oneOf\` as an object property
*/

// required attributes
const OneOfPropertyTestFields1R = t.interface({});

// optional attributes
const OneOfPropertyTestFields1O = t.partial({
foo: t.string
});

export const OneOfPropertyTestFields1 = t.intersection(
[OneOfPropertyTestFields1R, OneOfPropertyTestFields1O],
\\"OneOfPropertyTestFields1\\"
);

export type OneOfPropertyTestFields1 = t.TypeOf<
typeof OneOfPropertyTestFields1
>;

// required attributes
const OneOfPropertyTestFields2R = t.interface({});

// optional attributes
const OneOfPropertyTestFields2O = t.partial({
bar: t.string
});

export const OneOfPropertyTestFields2 = t.intersection(
[OneOfPropertyTestFields2R, OneOfPropertyTestFields2O],
\\"OneOfPropertyTestFields2\\"
);

export type OneOfPropertyTestFields2 = t.TypeOf<
typeof OneOfPropertyTestFields2
>;

export type OneOfPropertyTestFields3 = t.TypeOf<
typeof OneOfPropertyTestFields3
>;
export const OneOfPropertyTestFields3 = t.readonlyArray(
t.object,
\\"array of object\\"
);

export const OneOfPropertyTestFields = t.union(
[
OneOfPropertyTestFields1,

OneOfPropertyTestFields2,

OneOfPropertyTestFields3,

Person
],
\\"OneOfPropertyTestFields\\"
);

export type OneOfPropertyTestFields = t.TypeOf<typeof OneOfPropertyTestFields>;

// required attributes
const OneOfPropertyTestR = t.interface({});

// optional attributes
const OneOfPropertyTestO = t.partial({
fields: OneOfPropertyTestFields
});

export const OneOfPropertyTest = t.intersection(
[OneOfPropertyTestR, OneOfPropertyTestO],
\\"OneOfPropertyTest\\"
);

export type OneOfPropertyTest = t.TypeOf<typeof OneOfPropertyTest>;
"
`;

exports[`Openapi V3 |> gen-api-models should generate decoder definitions for (get, /test-auth-bearer) 1`] = `
"
/****************************************************************
Expand Down
17 changes: 17 additions & 0 deletions src/commands/gen-api-models/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,23 @@ describe.each`
expect(code).toMatchSnapshot("oneof-test");
});

it("should generate an object with a union property when that property has oneOf", async () => {
const definitonName = "OneOfPropertyTest";
const definition = getDefinitionOrFail(spec, definitonName);

const code = await renderDefinitionCode(
definitonName,
getParser(spec).parseDefinition(
// @ts-ignore
definition
),
false
);

expect(code).toContain("t.union");
expect(code).toMatchSnapshot("oneof-property-test");
});

Comment on lines +353 to +369
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added tests in 4c70dee

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing, thanks! In addition to that, could you please include some scenarios where we expect things to go wrong? For example:

  const variant5 = {
    fields: [{ name: 42 }]
  };

it("should generate a type union from allOf when x-one-of is used", async () => {
if (version === 2) {
const definitonName = "AllOfOneOfTest";
Expand Down
Loading