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

Implicitly call expect(res).toSatisfyApiSpec() on each request and response #237

Open
CameronHudson8 opened this issue Jun 26, 2021 · 2 comments

Comments

@CameronHudson8
Copy link

(Background: Please forgive me if my assumptions below about jest-openapi's existing functionality are incorrect. I'm currently seeking a tool to confirm that my existing API tests match my OpenAPI spec. My suggestion below is based on the functionality described in jest-openapi's README.md.)

At the moment, developers must call expect(res).toSatisfyApiSpec() on each response. However, developers might forget to call this function, and calling this function in every test is not a dry approach.

However, if jest-openapi could intercept each request and response from a particular HTTP client, say axios, then requests and responses could be validated for syntax against an OpenAPI spec implicitly and automatically. This would leave the developer free to write logical API tests ("if I delete a user, then calling GET should return 404"), while simultaneously checking request and response syntax for conformity with the OpenAPI spec in the background.

The configuration for such implicit testing could be placed in the jest.config.ts file for test suite. The config could include the paths to the OpenAPI spec(s), the HTTP client(s) to intercept, and which domain(s) to consider for validation.

This project looks really cool! Keep up the good work!

@CameronHudson8 CameronHudson8 changed the title Implicitly call expect(res).toSatisfyApiSpec() on requests responses Implicitly call expect(res).toSatisfyApiSpec() on each request and response Jun 26, 2021
@rwalle61
Copy link
Collaborator

Hi @CameronHudson8, thanks for raising this :) This reminds me of #55, what do you think about that discussion?

@CameronHudson8
Copy link
Author

CameronHudson8 commented Jun 27, 2021

Hi @CameronHudson8, thanks for raising this :) This reminds me of #55, what do you think about that discussion?

That discussion certainly does touch on some similar ideas. For instance, @blelump says:

So we have, lets call them unit specs, which are all the specs discussed above so you cover the happy paths and you're sure that all endpoints are bug-free (and only this). But we also have more sophisticated specs, closer to acceptance ones, where you follow some common real use case and check against more custom expectations that are important to check.

I think @blelump is mistaken in the first sentence, which he acknowledges in a later post. But he is touching on the distinction I made between syntactic correctness (conformance to the OAS) and logical correctness from a functionality perspective. For requests x, the server is like a function f(x) that returns responses y. The OAS only tells you of the schema of the requests (the domain of x) and the schema of the responses (the range of y). The OAS does not tell you anything about f and how it transforms x to y. This is what integration/e2e/acceptance tests are for.

I agree with @blelump's conclusion that there is not much value in calling the API with the example requests in the OAS, especially because an authentication token or pre-existing [mock] database entries will be needed for most requests.

However, I think we can all agree that each request sent to the server, and each response returned from it, should conform to the API spec. You've already implemented the heavy lifting in this jest-openapi project, which is validating the request/response against the OAS. What I describe in this feature request would require some tooling to intercept the requests and responses of a particular HTTP client library. That's the hard part. After that, the implementation would be pretty easy: call the existing expect(responseObject).toSatisfyApiSpec() assertions against the request and response.

Hold on, I actually just googled a bit about Axios and how to intercept requests, and it already has such a feature built in. This would make the implementation far easier. It might be as simple as calling this code before the test. (As a less dry but simpler alternative, it could be called in the beforeAll block of each test suite.) So I guess I could already accomplish what I describe in this feature request, but it would be even cooler if jest-openapi could call it behind the scenes, so that I didn't even have to call it in each beforeAll block.

// Please consider this to be pseudocode. I don't know the structure of the `config` or the `error` objects.

import axios from 'axios';
import jestOpenAPI from 'jest-openapi';

jestOpenAPI('path/to/openapi.yml');

// Add a request interceptor
axios.interceptors.request.use(function (config) {
    // Do something before request is sent

    // These assertions probably need to be wrapped in try/catch and returned as promises, but you get my meaning.
    expect(config).toSatisfyApiSpec();

    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });

// Add a response interceptor
axios.interceptors.response.use(function (response) {
    // Any status code that lie within the range of 2xx cause this function to trigger
    // Do something with response data

    expect(response).toSatisfyApiSpec();

    return response;
  }, function (error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    // Do something with response error

    expect(error).toSatisfyApiSpec();

    return Promise.reject(error);
  });

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