Tools for developing and testing edge service workers, in particular CloudFlare workers.
edge-mock provides three things:
- Implementations for types used in service-workers, e.g.
Request
,Respones
,FetchEvent
ReadableStream
etc. - A function
makeEdgeEnv
for installing these types into the global namespace for use in unit tests - 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!
[npm/yarn] add edge-mock
edge-mock provides the following types (all available to import from edge-mock
):
EdgeRequest
- implements theRequest
interface of the Fetch API, with the addition of thecf
attribute provided in CloudFlare workers.EdgeResponse
- implements theResponse
interfaceEdgeFetchEvent
- implements theFetchEvent
interface, with many attributes set toundefined
to matchFetchEvent
s in CloudFlare workersEdgeBlob
- implements theBlob
interfaceEdgeFormData
implements theFormData
interfaceEdgeFile
implements theFile
interface as used byFormData
EdgeHeaders
- implements theHeaders
interfaceEdgeReadableStream
- in memory implementation of theReadableStream
interfaceEdgeKVNamespace
- in memory implementation of CloudFlare's KVNamespacestub_fetch
- a very simple mock forfetch
which returns200
for requests tohttps://example.com/
and404
for all other requestsmakeEdgeEnv
- which installs all the above types (exceptEdgeKVNamespace
) intoglobal
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 toglobal
asRequest
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