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

Error import Specmatic in Cypress tests #139

Open
tkrisztian95 opened this issue Jan 31, 2024 · 3 comments
Open

Error import Specmatic in Cypress tests #139

tkrisztian95 opened this issue Jan 31, 2024 · 3 comments
Assignees
Labels
question Further information is requested

Comments

@tkrisztian95
Copy link
Contributor

Describe the bug
I'm trying to import Specmatic in a Cypress test, like

import { setHttpStubExpectations } from "specmatic";

and I'm getting the following error while running the tests by npx cypress run --browser electron:

TypeError: The following error originated from your test code, not from Cypress.   > _fs.default.existsSync is not a function

Desktop:

  • OS: Windows 10
  • Node version: 18.12.
  • Specmatic Version: 1.2.14
  • "cypress": "^13.2.0",

Additional context
I'm trying to achieve that from a Cypress test, using the cy.intercept() and cy.reply() functions, the tests are backed with the Specmatic stub and it returns the example/transient stubs always verified against the API specification.

For example:

    cy.intercept("/api/v1/foo/list", async (req) => {
      // fetch test data from Specmatic stub
      const data = await fetch("http://localhost:35337" + req.url, {
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
          Authorization: "Bearer token"
        }
      });
      req.reply(data);
    });

Should this work?

@harikrishnan83 harikrishnan83 self-assigned this Jan 31, 2024
@harikrishnan83 harikrishnan83 added the question Further information is requested label Jan 31, 2024
@harikrishnan83
Copy link
Member

harikrishnan83 commented Jan 31, 2024

@tkrisztian95 Thank for sharing the details. This seems like an interesting use case.

I am wondering why Cypress has to intercept the request and then pass it on to the Specmatic stub server. Can we not have the system under test directly talk to the Specmatic stub server?

Can you please elaborate the test setup in below format, as per the component test anatomy? Can you please update the question sections highlighted as question marks?

Test    -> SUT -> Dependency
Cypress -> <?> -> <?>

This will help me first understand the context before I answer your quiestion.

@tkrisztian95
Copy link
Contributor Author

Hi @harikrishnan83!

This is basically a use case with Cypress end-to-end tests, where we are rendering the UI in a headless browser and there is no actual backend running on the host. In tests we use cy.intercept and cy.reply to manipulate the response and return with a stub from various APIs. These stubs at the moment are static JS objects and in json files. But, there is nothing that could guarantee that the stubbed responses in our test code good with the API specification of the stubbed services.

For example:

describe("Home page", () => {

  beforeEach(() => {
    cy.viewport("macbook-13");
    cy.visit("localhost:5179");
   
   let json = {
     links: {},
     data: {
        foo: "bar"
     }
    };
   // we set the response to be the json fixture
   cy.intercept("api/v1/foo", {
      statusCode: 200,
      body: json
   });
...

See also docs about Cypress stub responses.

So, instead of the static stubs baked in the tests, Specmatic could be there and provide the transient expectations for a functioning FE that Cypress can click and navigate through.

Cypress -> SUT -> Specmatic (Stub)

I think it solves the downside mentioned in the Cypress documentation itself:

No guarantee your stubbed responses match the actual data the server sends

But, the original problem is with the import, I cannot import the Specmatic NPM in the test files because of the error. So from the test file scope I don't have programmatic control over the Specmatic stub server. I need to start the stub server before all test manually, etc.

And to answer your questions:

Can we not have the system under test directly talk to the Specmatic stub server?

I don't know, the existing tests that we have use this approach. It might be configurable to route all requests to the http stub directly.

Thank you for helping!

@tkrisztian95
Copy link
Contributor Author

tkrisztian95 commented Feb 13, 2024

I think I misunderstand the way how to work with Cypress and using the cy.intercept() and cy.reply() functions.

So, the additional await fetch() in the cy.intercept() should be simply avoided. Basically, we just replace/modify the request url in the intercepted request object in order to direct them to the Specmatic stub server.

For example this worked for me:

cy.intercept("/api/v1/foo/list", (req) => {
      // Replacing the server url to connect to the Specmatic Stub server instead
      req.url = req.url.replace("localhost:5173", "localhost:9000");
      // Adding the missing Authorization header to the outgoing request
      req.headers['Authorization'] = 'Bearer token'
      // Let send the request to the destination server (Specmatic)
      req.reply();
    });

Also for stub out responses in tests I put canned response files in a _data folder and I start Specmatic by java -jar specmatic.jar stub --data cypress/stubs before the Cypress tests. Note the --data flag you can use to specify the folder, similar to the _data suffix and Specmaitc load the stubs.

PS: Still not sure, if you want to import Specmatic in the testfile for dynamic stubbing using the setHttpStubExpectations function from the Node package, its not working.

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

No branches or pull requests

2 participants