Tools for developing and testing edge service workers, in particular CloudFlare workers.
edge-mock provides three things:
Request
, Respones
, FetchEvent
ReadableStream
etc.makeEdgeEnv
for installing these types into the global namespace for use in unit testsexpress.js
which lets you run your service-worker based app locally for developmentYou 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!
[npm/yarn] add edge-mock
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
interfaceEdgeFetchEvent
- implements the FetchEvent
interface,
with many attributes set to undefined
to match FetchEvent
s in CloudFlare workersEdgeBlob
- implements the Blob
interfaceEdgeFormData
implements the FormData
interfaceEdgeFile
implements the File
interface as used by FormData
EdgeHeaders
- implements the Headers
interfaceEdgeReadableStream
- in memory implementation of the
ReadableStream
interfaceEdgeKVNamespace
- in memory implementation of CloudFlare's
KVNamespacestub_fetch
- a very simple mock for
fetch
which returns 200
for requests to https://example.com/
and 404
for all other requestsmakeEdgeEnv
- 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.
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',
})
})
})
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
)
import {EdgeKVNamespace as KVNamespace} from 'edge-mock';
describe('edge-mock', () => {
test('put and get kv', async() => {
const kv = new KVNamespace();
await kv.put('foo','bar');
const value = await kv.get('foo');
expect(value).toBe('bar');
});
});
TODO
TODO
TODO
TODO
TODO
TODO
TODO