{"id":14971225,"url":"https://github.com/diokuz/teremock","last_synced_at":"2025-10-26T14:31:39.317Z","repository":{"id":38554700,"uuid":"228055615","full_name":"Diokuz/teremock","owner":"Diokuz","description":"Easy to use test request mocker for puppeteer / mocha / karma","archived":false,"fork":false,"pushed_at":"2023-03-31T13:26:47.000Z","size":2146,"stargazers_count":37,"open_issues_count":11,"forks_count":11,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-01-31T20:55:49.178Z","etag":null,"topics":["mock-files","mocker","playwright","puppeteer"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Diokuz.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.md","contributing":"contributing.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2019-12-14T16:45:35.000Z","updated_at":"2024-02-01T19:36:15.000Z","dependencies_parsed_at":"2023-02-18T19:01:24.917Z","dependency_job_id":"23c6d88c-39aa-4bec-b6ce-dd194dec2306","html_url":"https://github.com/Diokuz/teremock","commit_stats":{"total_commits":130,"total_committers":11,"mean_commits":"11.818181818181818","dds":0.5692307692307692,"last_synced_commit":"91461f7be4fd64ef916b2afd3ace966d99bfa7c4"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Diokuz%2Fteremock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Diokuz%2Fteremock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Diokuz%2Fteremock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Diokuz%2Fteremock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Diokuz","download_url":"https://codeload.github.com/Diokuz/teremock/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238347866,"owners_count":19457008,"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":["mock-files","mocker","playwright","puppeteer"],"created_at":"2024-09-24T13:44:53.314Z","updated_at":"2025-10-26T14:31:38.726Z","avatar_url":"https://github.com/Diokuz.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003e Now with Playwright support!\n\n# teremock\n\n## Do I need teremock?\n\nIf you write tests using playwright browser engine, and you want to mock your network responses easily – probably yes.\n\n## How to use\n\n```js\nimport teremock from 'teremock'\n\nawait teremock.start({ page })\n\n// async stuff which is making requests, including redirects\n```\n\n## How it works\n\n\u003cimg src='./assets/excalidraw.png' /\u003e\n\nFirst, `teremock` intercept request (all xhr/fetch requests by default). Then, it looks for the mock file. If mock file exist, you get response from it. If not, request goes to the real backend.\n\nSecond, `teremock` intercepts all responds, and writes them to the **filesystem** as mock files,\n\n### or not.\n\nSometimes it is more convenient to set mocks right in tests, without storing them to the file system. For that cases mocker.add method exist.\n\nExample:\n```js\nmocker.add(interceptor)\n```\nAfter that line, all request, matched `interceptor`, will be mocked with `interceptor.response`.\n\n\u003e Note: dynamically added interceptors have priority over statically added interceptors. Also, latter `mocker.add` interceptors have higher priority. _See [interceptor](#interceptor) below_.\n\n## options\n\n```js\nmocker.start(options)\n```\nAll options are optional (that's why they called so), except `page`.\n\n```js\nconst options = {\n  // Playwright option\n  page: page,\n\n  // Express options\n  app: express(),\n  env: { myApi: 'http://example.com/api' },\n\n  // Common options\n\n  // Named list of request interceptors\n  interceptors: {\n    testpage: {\n      url: 'localhost',\n      pass: true\n    },\n    example_com_api: {\n      url: 'example.com',\n      methods: `get,post`,\n    },\n    my_another_api: {\n      url: '/path/to/my/api',\n      response: async (request) =\u003e ({\n        status: 200,\n        headers: {},\n        body: request.query\n      })\n    },\n    option_requests: {\n      methods: 'option',\n      response: {\n        headers: {\n          'allow-origin': '*'\n        }\n      }\n    },\n  },\n\n  // Absolute path to working directory, where you want to store mocks\n  // path.resolve(process.cwd(), '__teremocks__') by default\n  wd: path.resolve(__dirname, '__teremocks__'),\n\n  // Run as CI if true. In CI mode any non-passable request will not go to the real backend\n  // Default is `process.env.CI` value\n  ci: false,\n\n  // Extends values for any mocked response\n  // You could redefine any response property, including headers, body and ttfb\n  responseOverrides: {\n    // A sequence of ttfb values\n    // Each new request will get the next (looped) ttfb value\n    // Could be usefull when find flaky tests and race conditions\n    // In this example, all requests (first 10) will work as a stack, not as a queue\n    ttfb: [900, 800, 700, 600, 500, 400, 300, 200, 100, 0]\n  },\n\n  onStop: ({ matched }) =\u003e {\n    // `matched` contains data about all urls and matched interceptors since last `start()`\n    // example: Map(1) { interceptorName =\u003e 'http://localhost:3000/api?q=x' }\n  }\n}\n```\n\n## Interceptor\n\nInterceptor – is a big conception in `teremock`. Interceptor is an object, which have two different groups of properties:\n\n1. Matcher group: these properties determine, whether to intercept particular request, or not.\n2. Provider group: what to do with request: 1) pass to real backend 2) respond with inline resoponse 3) try to find response mock on file system.\n\nInterceptor is used, if _all_ matchers are matched against request. So, if one matcher is not matched, given interceptor will not be used.\n\nIt is recommended to have interceptors for all possible (for your test app) requests. All non-covered requests will be aborted.\n\n### Matcher group properties\n\n#### interceptor.`url` [string]\n\nA string, which defines urls to match. It works when `request.url.includes(url) === true` – so, `ample.com` will match both `http://exampe.com` and `https://not-example.com/api?foo-bar`. Note: prefer not to place query params to urls, because they could be randomly sorted in real request.\n\nDefault value: `*`.\n\n#### interceptor.`resourceTypes` [string]\n\nComma-separated list of playwright [request resource types](https://playwright.dev/docs/api/class-request#request-resource-type). By default, only `xhr` and `fetch` request are mockable, but there are many situation where you may want to mock html documents, js files and, for example, the whole page of the facebook auth.\n\nDefault value: `xhr,fetch`.\n\n#### interceptor.`query` [Object]\n\nUnsorted one-level object of query params. Missing params will not affect the interception. Example: `{ foo: 'bar' }` will match `\u003curl\u003e?foo=bar` as well as `\u003curl\u003e?alice=bob\u0026foo=bar\u0026baz=1`.\n\nDuplicated values (e.g. `?foo=bar\u0026foo=baz`) are not supported.\n\nDefault value: `{}`.\n\n#### interceptor.`methods` [string]\n\nComma-separated list of http methods to be matched. Example: `get,post,put`.\n\nDefault value: `*`.\n\n#### interceptor.`headers` [Object]\n\nUnsorted one-level ignore-cased object of _request_ headers.\n\nDefault value: `{}`.\n\n#### interceptor.`body` [Object]\n\nUnsorted deep object to match request body.\n\nDefault value: `{}`.\n\n### Provider group properties\n\n#### interceptor.`pass` [boolean]\n\nIf `true`, pass request to the real backend. It is not recommended to pass any request outside of your app, since your tests became unstable and dependent from backends stability and network availability.\n\nDefault value: `false`.\n\n#### interceptor.`response` [Object | Function]\n\nIf present, it is used instead of file-based mocks. Usefull for testing different responses for the same request, and/or for mocking big-sized data.\n\nFunctional interceptor response must be async (return Promise), which must resolve with full response object (e.g. `{ headers: {}, status: 200, body: ... }`). Use functional interceptors when you need dynamic behaviour (e.g. translate random cookie to random GET param). Dont use functional interceptors for handling too many different requests or as a router between mocks.\n\nDefault value: `null`.\n\n#### interceptor.`naming` [Object]\n\nSee [Change naming rules](https://github.com/Diokuz/teremock#change-naming-rules) below.\n\n[Interceptor examples](./examples/interceptors.js).\n\n## Mock files naming\n\nThe name of mock file is consist of five parts:\n\n#### 1. `options.wd` value\n\n#### 2. named directory\n\nName will be taken from interceptor.name, or from the interceptor key, or from the hostname+path of request.url.\n\n#### 3. lowercased http method\n\ne.g. `post`\n\n#### 4. query or three words\n\nIf request method is `get`, and query is short enough, it is used. Otherwise, three words are used. These words are pseudorandom, and depends on a) request url (without query) b) query params (sorted, deduped) c) body params (sorted).\n\n#### 5. `.json` extension.\n\n@todo examples\n\n### Change naming rules\n\nIn many cases it is important to be independent from some query and body params, which, for example, have random value for each requests (e.g. timestamp). There are four different list for skipping some parameters, when calculating mock filename: whitelist and blacklist for query and body parameters.\n\nFor example, you want to skip `timestamp` GET-parameter, `randomToken` and nested `data.wuid` POST-parameters. Then, you need to construct two lists, and set them to mocker options:\n\n```ts\nconst dynamicQueryParams = [\n  'timestamp'\n]\nconst dynamicBodyParams = [\n  'randomToken',\n  ['data', 'wuid']\n]\n\nconst interceptor = {\n  naming: {\n    query: {\n      blacklist: dynamicQueryParams\n    },\n    body: {\n      blacklist: dynamicBodyParams\n    }\n  }\n})\n```\nNow, when you have a POST request with url and body:\n```\nhttp://example.com/?foo=bar\u0026timestamp=123\n\n{\n  randomToken: 'qweasd',\n  data: {\n    alice: 'bob',\n    wuid: 32\n  }\n}\n```\nthe mock filename will be exact as if it were just\n```\nhttp://example.com/?foo=bar\n\n{\n  data: {\n    alice: 'bob'\n  }\n}\n```\n\nIt is not recommended to use `whitelist`, because you may encounting mocks filenames collision. But in some rare cases (for example, when some keys are random) `whitelist` could be usefull.\n\nIt is not possible to use different lists for different urls simultaneously, but if you really need that, just create an issue!\n\n## API methods\n\n### mocker.start()\n\nStarts the mocker. Mocks for all requests matched `options.capture` will be used, but no mocks used before `mocker.start()` and after `mocker.stop()`\n\nBoth `mocker.start()` and `mocker.stop()` return a `Promise`.\n\n### mocker.stop()\n\nStops teremock, removes all handlers from playwright, disables request interception.\n\n### mocker.add(interceptor)\n\nAdds new interceptor to teremock in the middle of a test. Interceptor have priority over `interceptors`, defined in teremock.start(). To remove it, just call function which was returned:\n\n```ts\nconst remove404 = mocker.add({ url: 'example.com', response: { status: 404 } })\n// ... request for 'example.com' → check 404 behaviour here\nremove404()\n\nconst remove500 = mocker.add({ url: 'example.com', response: { status: 500 } })\n// .. same request for 'example.com' → check 500 behaviour here\nremove500()\n```\n\nNote: in most cases you dont need dynamic interceptors – it is better to write two different tests.\n\n### mocker.spy(interceptor)\n\nExample:\n\n```ts\nconst spy = mocker.spy({ url: 'example.com', query: { id: '123' } })\nawait stuff()\nexpect(spy.calledOnce).toBe(true)\nspy.dismiss()\n```\n\n## Debug\n\n`teremock` uses `debug` library for hidden logs, and `signale` library for warning and error logs.\n\nWarnings and errors are printed unconditionally (all the time).\n\nDebug logs are hidden, but could be switched on with enviroment variable `DEBUG` with valies, started with `teremock...`. For example: `DEBUG=teremock* yarn jest`.\n\n### Trace\n\nUse `DEBUG=teremock:trace ...` for tracing your request. Sample output:\n\n```\nteremock:trace http://localhost:3000/api?foo=bar\u0026baz=1 ← page.on('request') fired +0ms\nteremock:trace http://localhost:3000/api?foo=bar\u0026baz=1 ← handling request +0ms\nteremock:trace http://localhost:3000/api?foo=bar\u0026baz=1 ← mock not found in storage +1ms\nteremock:trace http://localhost:3000/api?foo=bar\u0026baz=1 ← request.continue() +0ms\nteremock:trace http://localhost:3000/api?foo=bar\u0026baz=1 → page.on('response') fired +37ms\nteremock:trace http://localhost:3000/api?foo=bar\u0026baz=1 → handling response +53ms\nteremock:trace http://localhost:3000/api?foo=bar\u0026baz=1 → storing mock basic--get-foo-bar +1ms\nteremock:trace http://localhost:3000/api?foo=bar\u0026baz=1 → finish +1ms\n```\n\n## How to intercept request on a new page (e.g. popup)?\n\nin progress\n\n## Brief review of mockers\n\n### Browser based mockers\n\nThis type of mockers (which teremock belongs to) could mock any client-side request, including xhr, fetch, script, images, redirect pages. But 1) cannot mock websockets 2) cannot mock server-side request 3) cannot mock initial request of new page.\n\n1. Teremock\n\n### Server-side (nodejs) mockers\n\nThis type of mockers have one fundamental limitation: you have to be in the same nodejs process. This type of mockers wont work for you if your app runs in a separate process (including child process), than your testing framework.\n\n1. [Nock](https://github.com/nock/nock#readme) ← simple and powerfull mocker, which decorates native http.request and http.ClientRequest functions.\n\n### Separate mocked real endpoints\n\nThis type of mockers allows you to test your system very close to the real network topology, but only if you could configure all your endpoints (change real urls to your mocked endpoints).\n\n1. [MockIt](https://github.com/boyney123/mockit)  ← allows fastly create stub endpoints. It is better in cases when you have isomorphic applications, and you have requests both – on server and on client-side.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiokuz%2Fteremock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiokuz%2Fteremock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiokuz%2Fteremock/lists"}