fetch-mock

repository·main·Indexed 23 days ago

https://github.com/wheresrhys/fetch-mock

A library for mocking HTTP requests made using the fetch API (or isomorphic-fetch), designed to work across various testing frameworks. It supports high-fidelity mocking of the fetch spec, including streaming and aborting, declarative matching, and advanced timing control. The project includes specialized wrappers for Jest (@fetch-mock/jest) and Vitest (@fetch-mock/vitest) to provide aligned naming and expressive assertions, as well as @fetch-mock/core for custom fetch replacements.

Tokens
32.3K
Snippets
61
Records
226
Agent score
77%

What's inside fetch-mock

  1. Overview of fetch-mock features

    main

    fetch-mock is a library designed to mock the fetch API with high fidelity. Key capabilities include:

    • High Fidelity Mocking: Mocks most of the fetch API spec, including advanced behaviors like streaming and aborting.
    • Declarative Matching: Match HTTP requests based on URL, headers, body, and query parameters.
    • Shorthands: Provides easy syntax for common tasks, such as matching specific HTTP methods or limiting a mock to a single fetch call.
    • Advanced Timing Control: Support for delaying responses or using custom async functions to simulate specific race conditions.
    • Spying: Can be used as a spy to observe real network requests without intercepting them.
    • Extensibility: Allows creating custom reusable matchers for both matching fetch calls and inspecting results.
    • Isomorphic Support: Works in both Node.js and browsers, supporting either a global fetch instance or a locally required instance.
  2. Overview of @fetch-mock/vitest

    main

    The @fetch-mock/vitest package is a wrapper for fetch-mock designed to improve the developer experience when using Vitest. It provides three main features:

    1. Aligned Naming: Adds methods to fetchMock that wrap default fetch-mock methods but follow Vitest's naming conventions.
    2. Expressive Assertions: Extends Vitest's expect with convenience matchers, allowing for readable tests like expect(fetchMock).toHavePosted(...).
    3. Global Mock Integration: Can be optionally hooked into Vitest's global mock management methods, such as clearAllMocks(), to automate cleanup.
  3. Use @fetch-mock/jest for improved Jest testing experience

    main

    @fetch-mock/jest is a wrapper for fetch-mock designed to improve developer experience when using Jest. It provides three main features:

    1. Aligned Naming: Adds methods to fetchMock that wrap default fetch-mock methods but follow Jest's naming conventions.
    2. Expressive Assertions: Extends Jest's expect with convenience matchers, allowing for tests like expect(fetchMock).toHavePosted('url', { body }).
    3. Global Mock Management: Can be optionally hooked into Jest's global mock management methods (e.g., clearAllMocks()) to automate cleanup.
  4. Replace `.mock()` with `.route()` and `.mockGlobal()`

    main

    In fetch-mock@12, the .mock() method has been removed. Previously, .mock() both added a route and mocked the global fetch instance. You must now split these into two distinct operations:

    1. Use .route() to define a specific route.
    2. Use .mockGlobal() to mock the global fetch instance.

    Because of this change, routing convenience methods like .once(), .get(), .post(), .getOnce(), and .postOnce() no longer mock the global fetch instance automatically. You must call .mockGlobal() explicitly to ensure the global fetch is intercepted.

  5. Use matchers to decide which requests to mock

    main

    A matcher defines the criteria used to determine if a fetch request should be intercepted by a mock.

    Important Note on Names: If you use matchers that target properties other than the URL string (like headers or bodies), you should add a name to your matcher object. This allows you to:

    1. Define multiple mocks for the same URL that differ only by other properties (e.g., different query strings or headers).
    2. Easier identification when inspecting fetch calls.
  6. Configure mocking behavior with optionsOrName

    main

    When using the legacy mock() API, the first argument can be either a string or an options object:

    • String: A unique name for the route. This is useful for advanced use cases where you need to retrieve references to the calls handled by this specific route later.
    • Object: An object containing configuration options to define how the mock behaves and how it matches requests.

    If you provide a string, you cannot provide other options in that same argument. If you provide an object, you can include properties like response, repeat, delay, and matcher options.

  7. Use explicit route names for reliable filtering and assertions

    main

    In @fetch-mock/core, inferred route names are gone. To reliably retrieve specific calls from the history or to use them with .done(), you should provide an explicit name when creating a route using the third argument of .route().

    When filtering calls, matchers are executed as actual matchers rather than being coerced into strings. Providing explicit names makes your tests more consistent and less confusing when dealing with multiple similar routes.

  8. Use shorthand methods for common mocking patterns

    main

    Instead of using the full .mock(matcher, response, optionsOrName) signature, fetch-mock provides shorthand methods to simplify common use cases. Most shorthands follow the same signature as .mock(), except for any variants which do not take a matcher.

    Common shorthand categories include:

    • Method-specific shorthands: .get(), .post(), .put(), .delete(), .head(), .patch()
    • Single-use shorthands: .once(), .getOnce(), .postOnce(), etc.
    • Catch-all shorthands: .any(), .getAny(), .postAny(), etc.
    • Persistence shorthands: .sticky()
  9. Use URL matchers to define routes

    main

    A matcher determines whether a route should be used to generate a response for a request. You can pass a URL matcher as a standalone value or as the url property within an object to combine it with other criteria like method or headers.

    URL Matching Oddities

    • Trailing slashes: http://thing is treated the same as http://thing/.
    • Dot segments: /path/../other-path matches both the literal path and the resolved path /other-path.
    • Protocol-relative URLs: fetch-mock only matches requests where the protocol is exactly the same as the route. For example, begin://a.com matches //a.com/path but not http://a.com/path.
    • Relative URLs: To support relative URLs (e.g., fetch('image.jpg')) in Node.js, set fetchMock.config.allowRelativeUrls = true or use jsdom to set globalThis.location.
    {
    	url: "begin: https://my.site",
    	method: 'post'
    }
  10. Understand fetch-mock build versions (Legacy API v9 and below)

    main

    In versions 9 and below, fetch-mock provides several builds tailored to different environments and module systems.

    • server vs client: server is designed for Node.js environments, while client is designed for the browser.
    • /cjs: CommonJS modules. Entry points are client.js and server.js. Use this for Node.js environments using require.
    • /esm: ES modules built with Rollup. Entry points are client.js and server.js. Use this for modern environments using import or bundlers like Webpack.
    • /es5: Builds using only ES5 syntax.
      • client.js and server.js: CommonJS modules.
      • client-legacy.js: CommonJS module with Babel polyfill bootstrapping for older environments.
      • client-bundle.js and client-legacy-bundle.js: Standalone UMD bundles for use in the browser via <script> tags.
  11. Match on multiple criteria with .mock()

    main

    For complex matching (e.g., matching on headers in addition to URL), you can use one of four patterns:

    1. Matcher Object: Keep all criteria in the first argument.
      fetchMock.mock({ url, headers }, response);
    2. Options Object: Pass matching criteria in the third argument. This is useful for creating variants of existing URL-only tests.
      fetchMock.mock(url, response, { headers });
    3. Single Configuration Object: Combine everything into one object.
      fetchMock.mock({ url, response, headers });
    4. Function Matcher: Use a custom function for logic not supported by default.
      fetchMock.mock((url, options) => {
        // custom logic
      }, response);