edge-mock

types for testing an developer edge applications

Usage no npm install needed!

<script type="module">
  import edgeMock from 'https://cdn.skypack.dev/edge-mock';
</script>

README

edge-mock

ci codecov

Tools for developing and testing edge service workers, in particular CloudFlare workers.

edge-mock provides three things:

  1. Implementations for types used in service-workers, e.g. Request, Respones, FetchEvent ReadableStream etc.
  2. A function makeEdgeEnv for installing these types into the global namespace for use in unit tests
  3. A simple HTTP server based on express.js which lets you run your service-worker based app locally for development

You can consider edge-mock as implementing the most commonly used types declare in the @cloudflare/workers-types typescript types package.

While edge-mock is designed to be useful when developing CloudFlare worker applications, it should be usable while developing any service-worker app including for (future) alternative edge worker implementations.

edge-mock is written in TypeScript and while you may be able to use it from vanilla javascript projects, you'd be better off writing your code in TypeScript!

Install

[npm/yarn] add edge-mock

Usage

edge-mock provides the following types (all available to import from edge-mock):

  • EdgeRequest - implements the Request interface of the Fetch API, with the addition of the cf attribute provided in CloudFlare workers.
  • EdgeResponse - implements the Response interface
  • EdgeFetchEvent - implements the FetchEvent interface, with many attributes set to undefined to match FetchEvents in CloudFlare workers
  • EdgeBlob - implements the Blob interface
  • EdgeFormData implements the FormData interface
  • EdgeFile implements the File interface as used by FormData
  • EdgeHeaders - implements the Headers interface
  • EdgeReadableStream - in memory implementation of the ReadableStream interface
  • EdgeKVNamespace - in memory implementation of CloudFlare's KVNamespace
  • stub_fetch - a very simple mock for fetch which returns 200 for requests to https://example.com/ and 404 for all other requests
  • makeEdgeEnv - which installs all the above types (except EdgeKVNamespace) into global so they can be used in worker scripts; types are installed into global by the name of the type they shadow, e.g. EdgeRequest is assigned to global as Request

There's also fetch_live (import with import live_fetch from 'edge-mock/live_fetch') which is an implementation of fetch which makes actual http requests using node-fetch. It is installed by default instead of stub_fetch in the dev server, see below.

Please Note: all the above types are designed for use with node while testing and are vanilla in-memory only implementations. They are not designed for production use or with large payloads.

Example of Usage for unit testing

edge-mock works well with jest to make writing unit tests for edge workers delightful.

Let's say you have the following handler.ts with a function handleRequest that you want to test:

export async function handleRequest(event: FetchEvent): Promise<Response> {
  const {request} = event
  const method = request.method
  let body: string | null = null
  if (method == 'POST') {
    body = await request.text()
  }
  const url = new URL(request.url)
  const response_info = {
    method,
    headers: Object.fromEntries(request.headers.entries()),
    searchParams: Object.fromEntries(url.searchParams.entries()),
    body,
  }
  const headers = {'content-type': 'application/json'}
  return new Response(JSON.stringify(response_info, null, 2), {headers})
}

(To see how this would be deployed to cloudflare, see the cloudflare worker TypeScript template)

To test the above handleRequest function, you could use the following:

import {makeEdgeEnv} from 'edge-mock'
import {handleRequest} from '../src/handle.ts'

describe('handleRequest', () => {
  beforeEach(() => {
    makeEdgeEnv()
    jest.resetModules()
  })

  test('post', async () => {
    // Request is available here AND in handleRequest because makeEdgeEnv installed
    // the proxy EdgeRequest into global under that name
    const request = new Request('/?foo=1', {method: 'POST', body: 'hello'})
    // same with FetchEvent, Response etc.
    const event = new FetchEvent('fetch', {request})
    const response = await handleRequest(event)
    expect(response.status).toEqual(200)
    expect(await response.json()).toStrictEqual({
      method: 'POST',
      headers: {accept: '*/*'},
      searchParams: {foo: '1'},
      body: 'hello',
    })
  })
})

Development Server

The development server relies on webpack and uses webpack-watch to reload the server on code changes.

To run the server, add the following to the scripts section of package.json:

  ...
  "scripts": {
    "dev": "edge-mock-server",
    ...
  },
  ...

TODO: explain how edge-mock-config.js works.

You can then run the dev server with:

yarn dev

(or npm run dev if you use npm rather than yarn)

Documentation

KV store

TODO

Wrangler sites integration

TODO

Request Payload

TODO

JSON

TODO

FormData

TODO

Binary Data, ArrayBuffer

TODO

Request.cf

TODO

fetch mocking

TODO