{"id":16012551,"url":"https://github.com/pinkyjie/cypress-auto-stub-example","last_synced_at":"2025-03-17T16:30:31.447Z","repository":{"id":34765200,"uuid":"145270198","full_name":"PinkyJie/cypress-auto-stub-example","owner":"PinkyJie","description":"Example project to demonstrate how to record/replay API with Cypress.","archived":false,"fork":false,"pushed_at":"2022-12-10T17:16:31.000Z","size":1674,"stargazers_count":56,"open_issues_count":16,"forks_count":11,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-28T01:36:37.481Z","etag":null,"topics":["cypress","e2e-testing","mocking","typescript"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PinkyJie.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-08-19T03:31:17.000Z","updated_at":"2024-08-30T15:22:21.000Z","dependencies_parsed_at":"2023-01-15T09:15:14.875Z","dependency_job_id":null,"html_url":"https://github.com/PinkyJie/cypress-auto-stub-example","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PinkyJie%2Fcypress-auto-stub-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PinkyJie%2Fcypress-auto-stub-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PinkyJie%2Fcypress-auto-stub-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PinkyJie%2Fcypress-auto-stub-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PinkyJie","download_url":"https://codeload.github.com/PinkyJie/cypress-auto-stub-example/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243871267,"owners_count":20361321,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cypress","e2e-testing","mocking","typescript"],"created_at":"2024-10-08T14:04:00.877Z","updated_at":"2025-03-17T16:30:30.820Z","avatar_url":"https://github.com/PinkyJie.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cypress-auto-stub-example [![CI](https://github.com/PinkyJie/cypress-auto-stub-example/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/PinkyJie/cypress-auto-stub-example/actions/workflows/ci.yml) ![cypress version](https://img.shields.io/badge/cypress-7.1.0-brightgreen) [![cypress-auto-stub-example](https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/simple/nf8wkk/master\u0026style=flat\u0026logo=cypress)](https://dashboard.cypress.io/projects/nf8wkk/runs)\n\nThis is an example project to demonstrate how to automatically stub all API requests happened in your [Cypress](https://www.cypress.io/) test and how to record/replay them.\n\n\u003e We are available on [Cypress Dashboard](https://www.cypress.io/dashboard/), go [there](https://dashboard.cypress.io/#/projects/nf8wkk/runs) to check the running results. (Registration required)\n\n## Problems to solve\n\n**_1. E2E tests take a long time to run, they are too slow._**\n\nOne concern of running E2E tests is that it takes long time to run, which makes sense because all your API calls are targeted to the real server. To resolve this issue, a single solution is to use mock API in your E2E tests. That's good, but here comes another question: you need to manually update your mocking data according to the API change regularly.\n\nA better solution is:\n\n- Use real API response when you write E2E tests, and **Record these responses and write them into files**.\n- Use the recorded API response to run your tests in future.\n\nThis project demonstrates how to make this process more smoothly and automatically with Cypress.\n\n**_2. E2E tests are too flaky, how many seconds do I need to wait?_**\n\nThough Cypress already ships with a unique mechanism to automatically block your test and retry until your expectation meets, but sometimes you still need to explicitly wait for all network API calls to be finished. In this example we implement a new command called `waitUntilAllAPIFinished` to solve this problem. Thanks to Cypress's full network control ability, now it's easier to know how many network API calls are still pending, so that we can wait for them to be finished first before you do any assertion.\n\n## Try it\n\n- Clone this project.\n- Install all dependencies by running `yarn install` or `npm install`.\n- Build the website by running `yarn build` or `npm run build`.\n- Launch the website by running `yarn serve` or `npm run serve`.\n- Open Cypress byr running `yarn cy:open`, then run the test `network.spec.ts`: (the same mechanism as Jest snapshot testing)\n  - If a snapshot file does not exist inside the `fixture` folder, tests will be running with the real API, and after all tests are passed, a snapshot file containing all API responses will be generated in the `fixture` folder.\n  - If a snapshot file does exist inside the `fixture` folder, but fixture data for this test case does not exist (e.g. there is no key with the same name as the test case name existing inside that snapshot file), tests will be running with the real API, then the snapshot file will be updated with the recorded API responses.\n  - If a snapshot file in the `fixture` folder already exists and has the mocking data for this test case, the test should run very fast, because all API responses are stubbed and use the snapshot file as responses.\n- If you want to update the snapshot file regardless of the existing fixture file existence, use `yarn cy:open:record`. When using this command, all tests will run against the real API, and all returned API responses will override the existing snapshot file if it exists.\n- You can also use `yarn cy:run` to run all Cypress tests in headless mode.\n\n## More details for demo [![Edit cypress-auto-stub-example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/PinkyJie/cypress-auto-stub-example/tree/master/)\n\nThe website page we are testing in this project contains 3 examples for XHR and Fetch:\n\n- Example 1:\n  - Click a button to call API (GET https://reqres.in/api/users) using XHR. API response JSON will be displayed below after it returns.\n- Example 2:\n  - Click a button to call API (POST https://reqres.in/api/users) using Fetch. API response JSON will be displayed below after it returns.\n  - To demonstrate Fetch can be supported here.\n- Example 3:\n  - Click a button to call 30 **sequential** API (GET https://reqres.in/api/users/1 to https://reqres.in/api/users/10 for 3 times) using Fetch. API response JSON (`userId: 10`) will be displayed below after it returns. **sequential** here mean the 2nd API call will file only after the 1st API call returns.\n  - To demonstrate the usage of a new custom command `cy.waitUntilAllAPIFinished()` which will make sure the testing is blocked until all API calls are finished.\n\nIt also includes 2 examples for GraphQL:\n\n\u003e \u003cdel\u003eCurrently when you use `cy.route()` to mock API response with fixtures, Cypress only match the URL and HTTP method you provided, for most of the cases, this is enough for mocking purpose. However, if you use libraries like `GraphQL`, all API requests are using the same URL with different request body, for this case, you need to mock different responses based on different request bodies, which is not possible before Cypress fixes [#687](https://github.com/cypress-io/cypress/issues/687).\u003c/del\u003e **Note: Cypress's `cy.intercept()` introduced after v6 already has full support to monitor request body, but the follow solution is still handy and faster.** A simple workaround is: use `md5` or other hash library to hash your request body into a string, and put this string as a query parameter in your URL, like `?_md5=xxxx`, now your URL contains the request body information: different request bodies result in different md5 hash string, thus you can rely on URL and HTTP method to do API mocking with request body in consideration.\n\n- Example 1:\n  - Click a button to query all users (Query https://api.spacex.land/) using GraphQL query. API response JSON will be displayed below after it returns.\n- Example 2:\n  - Click a button to insert a new user (Mutation https://api.spacex.land/) using GraphQL mutation. API response JSON will be displayed below after it returns.\n\n## More detail for implementation\n\n\u003e Inspired by [this article](https://medium.com/ax2-inc/dynamic-xhr-responses-recording-stubbing-with-cypress-9257d4f730cd) and Jest snapshot testing.\n\n- Check the main implementation in [`cypress/support/utils/auto-stub.ts`](cypress/support/utils/auto-stub.ts)\n\n  1. use `cy.intercept` to monitor all API requests\n  2. use `cy.writeFile` to write all recorded API responses in a fixture file\n  3. while replaying, use `cy.fixture` to load API responses from the fixture file\n\n- Check the implementation for custom command `cy.waitUntilAllAPIFinished` in [`cypress/support/commands.ts`](cypress/support/commands.ts#L11)\n\n  1. maintain an internal counter for API calls: increase 1 when filing a new API request, decrease 1 when receiving a API response\n  2. use Cypress's [Automatic Retry Assertion](https://docs.cypress.io/guides/core-concepts/introduction-to-cypress.html#Asserting-in-English) to regularly check this counter, block the testing until it equals to 0\n\n- Check the custom URI configuration(adding `?md5=xxx`) for GraphQL in [`src/App.js`](src/App.js#L13)\n\nThere are 4 new configuration parameters introduced in this example:\n\n\u003e All configuration parameters are defined under `env` as environment variables because:\n\u003e\n\u003e - It's easier for overriding by `cypress open --env foo=bar`\n\u003e - All existing configurations provided by Cypress are strongly typed, you can't add new configuration type when you use Typescript.\n\n| Parameter         | Type                                                                          | Description                                                                                             | Required           | Default Value |\n| ----------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------ | ------------- |\n| forceAPIRecording | boolean                                                                       | force enabling auto record (used to update api mocking data)                                            |                    | false         |\n| apiHosts          | string (multiple host separated by `,`)                                       | URL for API endpoint                                                                                    | :white_check_mark: |               |\n| stubAPIPatterns   | string (multiple pattern separated by `,`, will be used in `new RegExp(xxx)`) | API pattern needs to be stubbed                                                                         | :white_check_mark: |               |\n| apiMaxWaitingTime | number (in milliseconds)                                                      | used by `cy.waitUntilAllAPIFinished`, the maximum time when we wait for all API requests to be finished |                    | 60000 (60s)   |\n\n\u003e Note: `apiHosts` and `stubAPIPatterns` must be aligned with each others.\n\nThe generated recording file inside `cypress/fixtures` folder has the following format.\n\n```javascript\n{\n  \"Test case name\": {\n    \"timestamp\": \"2018-08-26T07:27:00.582Z\",\n    \"records\": [\n      \"url\": \"xxx\",\n      \"method\": \"xxx\",\n      \"request\": {\n        \"body\": {},\n      },\n      \"response\": {\n        \"body\": {},\n      },\n      // this means which host/pattern this API matches\n      \"matchHostIndex\": 0,\n    ]\n  }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpinkyjie%2Fcypress-auto-stub-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpinkyjie%2Fcypress-auto-stub-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpinkyjie%2Fcypress-auto-stub-example/lists"}