{"id":15012852,"url":"https://github.com/hltech/mockiavelli","last_synced_at":"2025-04-09T06:10:56.104Z","repository":{"id":38175101,"uuid":"256466897","full_name":"HLTech/mockiavelli","owner":"HLTech","description":"HTTP request mocking library for Puppeteer and Playwright","archived":false,"fork":false,"pushed_at":"2024-09-17T18:15:38.000Z","size":1437,"stargazers_count":144,"open_issues_count":18,"forks_count":10,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-02T02:08:25.465Z","etag":null,"topics":["functional-testing","mocks","playwright","puppeteer","testing","typescript"],"latest_commit_sha":null,"homepage":"","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/HLTech.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-17T10:00:57.000Z","updated_at":"2024-09-17T18:15:40.000Z","dependencies_parsed_at":"2024-06-19T13:33:18.194Z","dependency_job_id":"416b2028-066f-4517-8ad4-3fd138e20a25","html_url":"https://github.com/HLTech/mockiavelli","commit_stats":{"total_commits":72,"total_committers":7,"mean_commits":"10.285714285714286","dds":0.3055555555555556,"last_synced_commit":"88560959e81314c2503471e02584aa1f0a39df15"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HLTech%2Fmockiavelli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HLTech%2Fmockiavelli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HLTech%2Fmockiavelli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HLTech%2Fmockiavelli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HLTech","download_url":"https://codeload.github.com/HLTech/mockiavelli/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247987285,"owners_count":21028895,"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":["functional-testing","mocks","playwright","puppeteer","testing","typescript"],"created_at":"2024-09-24T19:43:19.645Z","updated_at":"2025-04-09T06:10:56.053Z","avatar_url":"https://github.com/HLTech.png","language":"TypeScript","readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=\"./mockiavelli-logo.png\" alt=\"Mockiavelli\"\u003e\n\u003c/p\u003e\n\u003ch2 align=\"center\"\u003e\n    Request mocking for Puppeteer and Playwright\n\u003c/h2\u003e\n\n[![npm](https://img.shields.io/npm/v/mockiavelli)](https://www.npmjs.com/package/mockiavelli) [![Node.js CI](https://github.com/HLTech/mockiavelli/actions/workflows/node.js.yml/badge.svg)](https://github.com/HLTech/mockiavelli/actions/workflows/node.js.yml)\n\nMockiavelli is HTTP request mocking library for [Puppeteer](http://pptr.dev/) and [Playwright](https://playwright.dev/). It was created to enable effective testing of Single Page Apps in isolation and independently from API services.\n\nMain features\n\n-   simple, minimal API\n-   mock network requests directly in the test case\n-   inspect and assert requests payload\n-   match request by method, url, path parameters and query strings\n-   support for cross-origin requests\n-   works with every testing framework running in node.js\n-   fully typed in Typescript and well tested\n-   lightweight - only 4 total dependencies (direct and indirect)\n\n## Docs\n\n-   [Installation](#installation)\n-   [Getting started](#getting-started)\n-   [Full example](#full-example)\n-   [Usage guide](#guide)\n    -   [URL and method matching](#url-and-method-matching)\n    -   [Path parameters matching](#path-parameters-matching)\n    -   [Query params matching](#query-parameters-matching)\n    -   [Request assertion](#request-assertion)\n    -   [One-time mocks](#one-time-mocks)\n    -   [Matching order](#matching-order)\n    -   [Matching priority](#matching-priority)\n    -   [Specifying API base url](#base-url)\n    -   [Cross-origin (cross-domain) API requests](#cors)\n    -   [Stop mocking](#stop-mocking)\n    -   [Dynamic responses](#dynamic-responses)\n    -   [Not matched requests](#not-matched-requests)\n    -   [Debug mode](#debug-mode)\n-   [API](#api)\n\n    -   [`Mockiavelli`](#Mockiavelli)\n    -   [`Mock`](#Mock)\n\n## Installation \u003ca name=\"installation\"/\u003e\n\n```bash\nnpm install mockiavelli -D\n```\n\nor if you are using yarn:\n\n```bash\nyarn add mockiavelli -D\n```\n\n-   Mockiavelli requires one of the following to be installed separately:\n    -   [Puppeteer](https://pptr.dev/) (in versions 2.x - 8.x)\n    -   [Playwright](https://playwright.dev/) (in version 1.x)\n-   If you're using [jest](jestjs.io/) we also recommend to install [jest-puppeteer](https://github.com/smooth-code/jest-puppeteer) or [jest-playwright](https://www.npmjs.com/package/jest-playwright-preset)\n\n## Getting started \u003ca name=\"getting-started\"/\u003e\n\nTo start using Mockiavelli, you need to instantiate it by providing it a `page` - instance of [Puppeteer Page](https://pptr.dev/#?product=Puppeteer\u0026show=api-class-page) or [Playwright Page](https://playwright.dev/docs/api/class-page)\n\n```typescript\nimport { Mockiavelli } from 'mockiavelli';\nimport puppeteer from 'puppeteer';\n\nconst browser = await puppeteer.launch();\nconst page = await browser.newPage();\nconst mockiavelli = await Mockiavelli.setup(page);\n```\n\nMockiavelli will start to intercept all HTTP requests issued from this page.\n\nTo define response for a given request, call `mockiavelli.mock\u003cHTTP_METHOD\u003e` with request URL and response object:\n\n```typescript\nconst getUsersMock = mockiavelli.mockGET('/api/users', {\n    status: 200,\n    body: [\n        { id: 123, name: 'John Doe' },\n        { id: 456, name: 'Mary Jane' },\n    ],\n});\n```\n\nNow every `GET /api/users` request issued from this page will receive `200 OK` response with provided body.\n\n```typescript\nconst users = await page.evaluate(() =\u003e {\n    return fetch('/api/users').then((res) =\u003e res.json());\n});\nconsole.log(users); // [{id: 123, name: 'John Doe' }, {id: 456, name: 'Mary Jane'}]\n```\n\n## Full example \u003ca name=\"full-example\"/\u003e\n\nThe example below is a [Jest](https://jestjs.io/en) test case (with [jest-puppeteer preset](https://github.com/smooth-code/jest-puppeteer)) verifies a sign-up form in a locally running application.\n\nMockiavelli is used to mock and assert request that the app makes to REST API upon form submission.\n\n```typescript\nimport { Mockiavelli } from 'mockiavelli';\n\ntest('Sign-up form', async () =\u003e {\n    // Enable mocking on instance of puppeteer Page (provided by jest-puppeteer)\n    const mockiavelli = await Mockiavelli.setup(page);\n\n    // Navigate to application\n    await page.goto('http://localhost:8000/');\n\n    // Configure mocked response\n    const postUserMock = mockiavelli.mockPOST('/api/user', {\n        status: 201,\n        body: {\n            userId: '123',\n        },\n    });\n\n    // Perform interaction\n    await page.type('input.name', 'John Doe');\n    await page.type('input.email', 'email@example.com');\n    await page.click('button.submit');\n\n    // Verify request payload\n    const postUserRequest = await postUserMock.waitForRequest();\n    expect(postUserRequest.body).toEqual({\n        user_name: 'John Doe',\n        user_email: 'email@example.com',\n    });\n\n    // Verify message shown on the screen\n    await expect(page).toMatch('Created account ID: 123');\n});\n```\n\n## Usage guide \u003ca name=\"guide\"/\u003e\n\n### URL and method matching \u003ca name=\"url-and-method-matching\"/\u003e\n\nRequest can be matched by:\n\n-   providing URL string to `mockiavelli.mock\u003cHTTP_METHOD\u003e` method:\n\n    ```typescript\n    mockiavelli.mockGET('/api/users?age=30', {status: 200, body: [....]})\n    ```\n\n-   providing matcher object to `mockiavelli.mock\u003cHTTP_METHOD\u003e` method\n\n    ```typescript\n    mockiavelli.mockGET({\n        url: '/api/users',\n        query: { age: '30' }\n    }, {status: 200, body: [....]})\n    ```\n\n-   providing full matcher object `mockiavelli.mock` method\n\n    ```typescript\n    mockiavelli.mock({\n        method: 'GET',\n        url: '/api/users',\n        query: { age: '30' }\n    }, {status: 200, body: [...]})\n    ```\n\n### Path parameters matching \u003ca name=\"path-parameters-matching\"/\u003e\n\nPath parameters in the URL can be matched using `:param` notation, thanks to [path-to-regexp](https://www.npmjs.com/package/path-to-regexp) library.\n\nIf mock matches the request, those params are exposed in `request.params` property.\n\n```typescript\nconst getUserMock = mockiavelli.mockGET('/api/users/:userId', { status: 200 });\n\n// GET /api/users/1234 =\u003e 200\n// GET /api/users =\u003e 404\n// GET /api/users/1234/categories =\u003e 404\n\nconsole.log(await getUserMock.waitForRequest());\n// { params: {userId : \"12345\"}, path: \"/api/users/12345\", ... }\n```\n\nMockiavelli uses\n\n### Query params matching \u003ca name=\"query-parameters-matching\"/\u003e\n\nMockiavelli supports matching requests by query parameters. All defined params are then required to match the request, but excess params are ignored:\n\n```typescript\nmockiavelli.mockGET('/api/users?city=Warsaw\u0026sort=asc', { status: 200 });\n\n// GET /api/users?city=Warsaw\u0026sort=asc            =\u003e 200\n// GET /api/users?city=Warsaw\u0026sort=asc\u0026limit=10   =\u003e 200\n// GET /api/users?city=Warsaw                     =\u003e 404\n```\n\nIt is also possible to define query parameters as object. This notation works great for matching array query params:\n\n```typescript\nmockiavelli.mockGET(\n    { url: '/api/users', query: { status: ['active', 'blocked'] } },\n    { status: 200 }\n);\n\n// GET /api/users?status=active\u0026status=blocked  =\u003e 200\n```\n\n### Request assertion \u003ca name=\"request-assertion\"/\u003e\n\n`mockiavelli.mock\u003cHTTP_METHOD\u003e` and `mockiavelli.mock` methods return an instance of `Mock` class that records all requests the matched given mock.\n\nTo assert details of request made by application use async `mock.waitForRequest()` method. It will throw an error if no matching request was made.\n\n```typescript\nconst postUsersMock = mockiavelli.mockPOST('/api/users', { status: 200 });\n\n// ... perform interaction on tested page ...\n\nconst postUserRequest = await postUsersMock.waitForRequest(); // Throws if POST /api/users request was not made\nexpect(postUserRequest.body).toBe({\n    name: 'John',\n    email: 'john@example.com',\n});\n```\n\n### One-time mocks \u003ca name=\"one-time-mocks\"/\u003e\n\nBy default mock are persistent, meaning that they will respond to multiple matching requests:\n\n```typescript\nmockiavelli.mockGET('/api/users', { status: 200 });\n\n// GET /api/users =\u003e 200\n// GET /api/users =\u003e 200\n```\n\nTo change this behaviour and disable mock once it matched a request use `once` option:\n\n```typescript\nmockiavelli.mockGET('/api/users', { status: 200 }, { once: true });\n\n// GET /api/users =\u003e 200\n// GET /api/users =\u003e 404\n```\n\n### Matching order \u003ca name=\"matching-order\"/\u003e\n\nMocks are matched in the \"newest first\" order. To override previously defined mock simply define new one:\n\n```typescript\nmockiavelli.mockGET('/api/users', { status: 200 });\nmockiavelli.mockGET('/api/users', { status: 401 });\n\n// GET /api/users =\u003e 401\n\nmockiavelli.mockGET('/api/users', { status: 500 });\n\n// GET /api/users =\u003e 500\n```\n\n### Matching priority \u003ca name=\"matching-priority\"/\u003e\n\nTo change the default \"newest first\" matching order, you define mocks with combination of `once` and `priority` parameters:\n\n```typescript\nmockiavelli.mockGET(\n    '/api/users',\n    { status: 404 },\n    { once: true, priority: 10 }\n);\nmockiavelli.mockGET('/api/users', { status: 500 }, { once: true, priority: 5 });\nmockiavelli.mockGET('/api/users', { status: 200 });\n\n// GET /api/users =\u003e 404\n// GET /api/users =\u003e 500\n// GET /api/users =\u003e 200\n```\n\n### Specifying API base url \u003ca name=\"base-url\"/\u003e\n\nIt is possible to initialize Mockiavelli instance with specified API base url.\nThis API base url is added to every mocked request url.\n\n```typescript\nconst mockiavelli = await Mockiavelli.setup(page, { baseUrl: '/api/v1' });\n\nmockiavelli.mockGET('/users', { status: 200 });\n\n// GET /api/v1/users =\u003e 200\n```\n\n### Cross-origin (cross-domain) API requests \u003ca name=\"cors\"/\u003e\n\nMockiavelli has built-in support for cross-origin requests. If application and API are not on the same origin (domain) just provide the full request URL to `mockiavelli.mock\u003cHTTP_METHOD\u003e`\n\n```typescript\nmockiavelli.mockGET('http://api.example.com/api/users', { status: 200 });\n\n// GET http://api.example.com/api/users =\u003e 200\n// GET http://another-domain.example.com/api/users =\u003e 404\n```\n\n### Stop mocking \u003ca name=\"stop-mocking\"\u003e\n\nTo stop intercept requests you can call `mockiavelli.disable` method (all requests will send to real services).\nThen you can enable mocking again by `mockiavelli.enable` method.\n\n```typescript\nmockiavelli.mockGET('/api/users/:userId', {\n    status: 200,\n    body: { name: 'John Doe' },\n});\n\n// GET /api/users/1234 =\u003e 200 { name: 'John Doe' }\n\nmockiavelli.disable();\n\n// GET /api/users/1234 =\u003e 200 { name: 'Jacob Kowalski' } \u003c- real data from backend\n\nmockiavelli.enable();\n\n// GET /api/users/1234 =\u003e 200 { name: 'John Doe' }\n```\n\n### Dynamic responses \u003ca name=\"dynamic-responses\"/\u003e\n\nIt is possible to define mocked response in function of incoming request. This is useful if you need to use some information from request URL or body in the response:\n\n```typescript\nmockiavelli.mockGET('/api/users/:userId', (request) =\u003e {\n    return {\n        status: 200,\n        body: {\n            id: request.params.userId,\n            name: 'John',\n            email: 'john@example.com',\n            ...\n        },\n    };\n});\n\n// GET /api/users/123 =\u003e 200 {\"id\": \"123\", ... }\n```\n\n### Not matched requests \u003ca name=\"not-matched-requests\" /\u003e\n\nIn usual scenarios, you should mock all requests done by your app.\n\nAny XHR or fetched request done by the page not matched by any mock will be responded with `404 Not Found`. Mockiavelli will also log this event to console:\n\n```typescript\nMock not found for request: type=fetch method=GET url=http://example.com\n```\n\n### Debug mode \u003ca name=\"debug-mode\"/\u003e\n\nPassing `{debug: true}` to `Mockiavelli.setup` enables rich debugging in console:\n\n```typescript\nawait Mockiavelli.setup(page, { debug: true });\n```\n\n## API \u003ca name=\"api\"/\u003e\n\n### `class Mockiavelli` \u003ca name=\"Mockiavelli\"/\u003e\n\n#### `Mockiavelli.setup(page, options): Promise\u003cMockiavelli\u003e`\n\nFactory method used to set-up request mocking on provided Puppeteer or Playwright Page. It creates and returns an instance of [Mockiavelli](#Mockiavelli)\n\nOnce created, mockiavelli will intercept all requests made by the page and match them with defined mocks.\n\nIf request does not match any mocks, it will be responded with `404 Not Found`.\n\n###### Arguments\n\n-   `page` _(Page)_ instance of [Puppeteer Page](https://pptr.dev/#?product=Puppeteer\u0026show=api-class-page) or [Playwright Page](https://playwright.dev/docs/api/class-page)\n-   `options` _(object)_ configuration options\n    -   `baseUrl: string` specify the API base url, which will be added to every mocked request url\n    -   `debug: boolean` turns debug mode with logging to console (default: `false`)\n\n###### Example\n\n```typescript\nimport { puppeteer } from 'puppeteer';\nimport { Mockiavelli } from 'mockiavelli';\n\nconst browser = await puppeteer.launch();\nconst page = await browser.newPage();\nconst mockiavelli = await Mockiavelli.setup(page);\n```\n\n###### Returns\n\nPromise resolved with instance of `Mockiavelli` once request mocking is established.\n\n#### `mockiavelli.mock(matcher, response, options?)`\n\nRespond all requests of matching `matcher` with provided `response`.\n\n###### Arguments\n\n-   `matcher` _(object)_ matches request with mock.\n    -   `method: string` - any valid HTTP method\n    -   `url: string` - can be provided as path (`/api/endpoint`) or full URL (`http://example.com/endpoint`) for CORS requests. Supports path parameters (`/api/users/:user_id`)\n    -   `query?: object` object literal which accepts strings and arrays of strings as values, transformed to queryString\n-   `response` _(object | function)_ content of mocked response. Can be a object or a function returning object with following properties:\n    -   `status: number`\n    -   `headers?: object`\n    -   `body?: any`\n-   `options?` _(object)_ optional config object\n    -   `prority` _(number)_ when intercepted request matches multiple mock, mockiavelli will use the one with highest priority\n    -   `once` _(boolean)_ _(default: false)_ when set to true intercepted request will be matched only once\n\n###### Returns\n\nInstance of [`Mock`](#Mock).\n\n###### Example\n\n```typescript\nmockiavelli.mock(\n    {\n        method: 'GET',\n        url: '/api/clients',\n        query: {\n            city: 'Bristol',\n            limit: 10,\n        },\n    },\n    {\n        status: 200,\n        headers: {...},\n        body: [{...}],\n    }\n);\n```\n\n#### `mockiavelli.mock\u003cHTTP_METHOD\u003e(matcher, response, options?)`\n\nShorthand method for `mockiavelli.mock`. Matches all request with `HTTP_METHOD` method. In addition to matcher object, it also accepts URL string as first argument.\n\n-   `matcher: (string | object)` URL string or object with following properties:\n    -   `url: string` - can be provided as path (`/api/endpoint`) or full URL (`http://example.com/endpoint`) for CORS requests. Supports path parameters (`/api/users/:user_id`)\n    -   `query?: object` object literal which accepts strings and arrays of strings as values, transformed to queryString\n-   `response: (object | function)` content of mocked response. Can be a object or a function returning object with following properties:\n    -   `status: number`\n    -   `headers?: object`\n    -   `body?: any`\n-   `options?: object` optional config object\n    -   `prority?: number` when intercepted request matches multiple mock, mockiavelli will use the one with highest priority. Default: `0`\n    -   `once: boolean` when set to true intercepted request will be matched only once. Default: `false`\n\nAvailable methods are:\n\n-   `mockiavelli.mockGET`\n-   `mockiavelli.mockPOST`\n-   `mockiavelli.mockDELETE`\n-   `mockiavelli.mockPUT`\n-   `mockiavelli.mockPATCH`\n\n###### Examples\n\n```typescript\n// Basic example\nmockiavelli.mockPOST('/api/clients', {\n    status: 201,\n    body: {...},\n});\n```\n\n```typescript\n// Match by query parameters passed in URL\nmockiavelli.mockGET('/api/clients?city=Bristol\u0026limit=10', {\n    status: 200,\n    body: [{...}],\n});\n```\n\n```typescript\n// Match by path params\nmockiavelli.mockGET('/api/clients/:clientId', {\n    status: 200,\n    body: [{...}],\n});\n```\n\n```typescript\n// CORS requests\nmockiavelli.mockGET('http://example.com/api/clients/', {\n    status: 200,\n    body: [{...}],\n});\n```\n\n#### `mockiavelli.disable()`\n\nStop mocking of requests by Mockiavelli.\nAfter that all requests pass to real endpoints.\nThis method does not reset set mocks or possibility to set mocks, so when we then enable again mocking by `mockiavelli.enable()`, all set mocks works again.\n\n#### `mockiavelli.enable()`\n\nTo enable mocking of requests by Mockiavelli when previously `mockiavelli.diable()` was called.\n\n---\n\n### `class Mock` \u003ca name=\"Mock\"/\u003e\n\n#### `waitForRequest(index?: number): Promise\u003cMatchedRequest\u003e`\n\nRetrieve n-th request matched by the mock. The method is async - it will wait 100ms for requests to be intercepted to avoid race condition issue. Throws if mock was not matched by any request.\n\n###### Arguments\n\n-   `index` _(number)_ index of request to return. Default: 0.\n\n###### Returns\n\nPromise resolved with `MatchedRequest` - object representing request that matched the mock:\n\n-   `method: string` - request's method (GET, POST, etc.)\n-   `url: string` - request's full URL. Example: `http://example.com/api/clients?name=foo`\n-   `hostname: string` - request protocol and host. Example: `http://example.com`\n-   `headers: object` - object with HTTP headers associated with the request. All header names are lower-case.\n-   `path: string` - request's url path, without query string. Example: `'/api/clients'`\n-   `query: object` - request's query object, as returned from [`querystring.parse`](https://nodejs.org/docs/latest/api/querystring.html#querystring_querystring_parse_str_sep_eq_options). Example: `{name: 'foo'}`\n-   `body: any` - JSON deserialized request's post body, if any\n-   `type: string` - request's resource type. Possible values are `xhr` and `fetch`\n-   `params: object` - object with path parameters specified in `url`\n\n###### Example\n\n```typescript\nconst patchClientMock = mockiavelli.mockPATCH('/api/client/:clientId', { status: 200 });\n\n// .. send request from page ...\n\nconst patchClientRequest = await patchClientMock.waitForRequest();\n\nexpect(patchClientRequest).toEqual({\n    method: 'PATCH',\n    url: 'http://example.com/api/client/1020',\n    hostname: 'http://example.com',\n    headers: {...},\n    path: '/api/client/1020',\n    query: {},\n    body: {name: 'John', email: 'john@example.com'}\n    rawBody: '{\\\"name\\\":\\\"John\\\",\\\"email\\\":\\\"john@example.com\\\"}',\n    type: 'fetch',\n    params: { clientId: '' }\n})\n```\n\n#### `waitForRequestCount(n: number): Promise\u003cvoid\u003e`\n\nWaits until mock is matched my `n` requests. Throws error when timeout (equal to 100ms) is exceeded.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhltech%2Fmockiavelli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhltech%2Fmockiavelli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhltech%2Fmockiavelli/lists"}