Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discriminator doesn't expect enum values in schemas #482

Closed
ex1st opened this issue Dec 9, 2020 · 2 comments
Closed

Discriminator doesn't expect enum values in schemas #482

ex1st opened this issue Dec 9, 2020 · 2 comments
Assignees

Comments

@ex1st
Copy link
Contributor

ex1st commented Dec 9, 2020

I've extended one.of.2 test for this case:

openapi: '3.0.3'
info:
  version: 1.0.0
  title: Swagger
servers:
  - url: /v1
paths:
  /discriminator_implied:
    post:
      description: Creates a new pet in the store.
      requestBody:
        description: Pet to add to the store
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/CatObject'
                - $ref: '#/components/schemas/DogObject'
              discriminator:
                propertyName: pet_type
      responses:
        '200':
          description: Updated
  /pets:
    post:
      description: Creates a new pet in the store.
      requestBody:
        description: Pet to add to the store
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/CatObject'
                - $ref: '#/components/schemas/DogObject'
              discriminator:
                propertyName: pet_type
                mapping:
                  cat: '#/components/schemas/CatObject'
                  kitty: '#/components/schemas/CatObject'
                  dog: '#/components/schemas/DogObject'
                  puppy: '#/components/schemas/DogObject'
      responses:
        '200':
          description: Updated

  /pets_all:
    post:
      description: Creates a new pet in the store.
      operationId: createPetAll
      x-eov-operation-id: pets#create ## overrides operationId
      x-eov-operation-handler: api/controllers/pets
      requestBody:
        description: Pet to add to the store
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/Cat'
                - $ref: '#/components/schemas/Dog'
              discriminator:
                propertyName: pet_type
      responses:
        '200':
          description: Updated

components:
  schemas:
    DogObject:
      type: object
      required:
        - bark
        - breed
        - pet_type
      properties:
        bark:
          type: boolean
        breed:
          type: string
          enum: [Dingo, Husky, Retriever, Shepherd]
        pet_type:
          type: string
          enum: [dog, puppy]

    CatObject:
      type: object
      required:
        - hunts
        - age
        - pet_type
      properties:
        hunts:
          type: boolean
        age:
          type: integer
        pet_type:
          type: string
          enum: [cat, kitty]

    Pet:
      type: object
      required:
        - pet_type
      properties:
        pet_type:
          type: string
      discriminator:
        propertyName: pet_type

    Dog:     # "Dog" is a value for the pet_type property (the discriminator value)
      allOf: # Combines the main `Pet` schema with `Dog`-specific properties
        - $ref: '#/components/schemas/Pet'
        - type: object
          # all other properties specific to a `Dog`
          properties:
            bark:
              type: boolean
            breed:
              type: string
              enum: [Dingo, Husky, Retriever, Shepherd]
    Cat:     # "Cat" is a value for the pet_type property (the discriminator value)
      allOf: # Combines the main `Pet` schema with `Cat`-specific properties
        - $ref: '#/components/schemas/Pet'
        - type: object
          # all other properties specific to a `Cat`
          properties:
            hunts:
              type: boolean
            age:
              type: integer
import * as path from 'path';
import { expect } from 'chai';
import * as request from 'supertest';
import { createApp } from './common/app';
import * as packageJson from '../package.json';

describe('one.of.2.spec', () => {
  let app = null;

  before(async () => {
    const apiSpec = path.join('test', 'resources', 'one.of.2.yaml');
    app = await createApp(
      { apiSpec },
      3005,
      (app) => {
        app.post(`${app.basePath}/discriminator_implied`, (req, res) =>
          res.json(req.body),
        );
        app.post(`${app.basePath}/pets`, (req, res) => {
          res.json(req.body);
        });
        app.post(`${app.basePath}/pets_all`, (req, res) => {
          res.json(req.body);
        });
        app.use((err, req, res, next) => {
          console.error(err);
          res.status(err.status ?? 500).json({
            message: err.message,
            code: err.status ?? 500,
          });
        });
      },
      false,
    );
  });

  after(() => {
    app.server.close();
  });

  describe('/discriminator_implied', () => {
    it('should return 200 for dog', async () =>
      request(app)
        .post(`${app.basePath}/discriminator_implied`)
        .set('content-type', 'application/json')
        .send({
          pet_type: 'DogObject',
          bark: true,
          breed: 'Dingo',
        })
        .expect(200));

    it('should return 400 for dog with cat props', async () =>
      request(app)
        .post(`${app.basePath}/discriminator_implied`)
        .set('content-type', 'application/json')
        .send({
          pet_type: 'DogObject',
          hunts: true,
          age: 3,
        })
        .expect(400)
        .then((r) => {
          expect(r.body.message).to.include("required property 'bark'");
        }));

    it('should return 400 a bad discriminator', async () =>
      request(app)
        .post(`${app.basePath}/discriminator_implied`)
        .set('content-type', 'application/json')
        .send({
          pet_type: 'dog',
          bark: true,
          breed: 'Dingo',
        })
        .expect(400)
        .then((r) => {
          expect(r.body.message).to.include(
            'one of the allowed values: CatObject, DogObject',
          );
        }));
  });

  describe('/pets', () => {
    it('should return 400 a bad discriminator', async () =>
      request(app)
        .post(`${app.basePath}/pets`)
        .set('content-type', 'application/json')
        .send({
          pet_type: 'DogObject',
          bark: true,
          breed: 'Dingo',
        })
        .expect(400)
        .then((r) => {
          const e = r.body;
          expect(e.message).to.include('one of the allowed values: cat, dog');
        }));

    it('should return 200 for dog', async () =>
      request(app)
        .post(`${app.basePath}/pets`)
        .set('content-type', 'application/json')
        .send({
          pet_type: 'dog',
          bark: true,
          breed: 'Dingo',
        })
        .expect(200));

    it('should return 200 for puppy', async () =>
      request(app)
        .post(`${app.basePath}/pets`)
        .set('content-type', 'application/json')
        .send({
          pet_type: 'puppy',
          bark: true,
          breed: 'Dingo',
        })
        .expect(200));

    it('should return 200 for cat', async () =>
      request(app)
        .post(`${app.basePath}/pets`)
        .set('content-type', 'application/json')
        .send({
          pet_type: 'cat',
          hunts: true,
          age: 1,
        })
        .expect(200));

    it('should return 200 for kitty', async () =>
      request(app)
        .post(`${app.basePath}/pets`)
        .set('content-type', 'application/json')
        .send({
          pet_type: 'kitty',
          hunts: true,
          age: 1,
        })
        .expect(200));
  });

  describe('/pets_all', () => {
    it('should return 400 a bad discriminator', async () =>
      request(app)
        .post(`${app.basePath}/pets_all`)
        .set('content-type', 'application/json')
        .send({
          pet_type: 'dog',
          bark: true,
          breed: 'Dingo',
        })
        .expect(400)
        .then((r) => {
          const e = r.body;
          expect(e.message).to.include(
            'to one of the allowed values: Cat, Dog',
          );
        }));

    it('should return 200 for Dog', async () =>
      request(app)
        .post(`${app.basePath}/pets_all`)
        .set('content-type', 'application/json')
        .send({
          pet_type: 'Dog',
          bark: true,
          breed: 'Dingo',
        })
        .expect(200));

    it('should return 200 for Cat', async () =>
      request(app)
        .post(`${app.basePath}/pets_all`)
        .set('content-type', 'application/json')
        .send({
          pet_type: 'Cat',
          hunts: true,
          age: 3,
        })
        .expect(200));
  });
});

Thank you!

@cdimascio
Copy link
Owner

Thanks you. Would u mind submitting a PR. This is great

@cdimascio cdimascio self-assigned this Dec 19, 2020
cdimascio added a commit that referenced this issue Dec 19, 2020
cdimascio added a commit that referenced this issue Dec 19, 2020
@cdimascio
Copy link
Owner

@ex1st thanks again for the tests. this is fixed in v4.9.2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants