Event in c.event is undefined when testing
Here is my jest config:
import dotenv from 'dotenv'
dotenv.config({
path: '.env.test'
})
export default {
testEnvironment: 'miniflare',
moduleFileExtensions: ['js', 'jsx', 'mjs'],
coverageThreshold: {
global: {
branches: 70,
functions: 70,
lines: 70,
statements: 70,
},
},
coverageReporters: ['json-summary', 'html'],
testTimeout: 10000,
testRegex: '(\/tests\/.*|(.|\/))test.(mjs?|jsx?|js?|tsx?|ts?)$',
testEnvironmentOptions: {
kvNamespaces: ['PRESALE_API']
}
}
The test is pretty basic I call an endpoint that calls event.waituntil and it inputs something into cloudflare kv cache. Here is the context.event when running locally using miniflare which works fine locally and in cloudflare:
event: FetchEvent {
type: 'fetch',
defaultPrevented: false,
cancelable: false,
timeStamp: 4124.764995008707
}
But when I run it using jest:
Context {
_status: 200,
_pretty: false,
_prettySpace: 2,
req: Request {
[Symbol(realm)]: { settingsObject: {} },
[Symbol(state)]: {
method: 'GET',
localURLsOnly: false,
unsafeRequest: false,
body: null,
client: {},
reservedClient: null,
replacesClientId: '',
window: 'client',
keepalive: false,
serviceWorkers: 'all',
initiator: '',
destination: '',
priority: null,
origin: 'client',
policyContainer: 'client',
referrer: 'client',
referrerPolicy: '',
mode: 'cors',
useCORSPreflightFlag: false,
credentials: 'same-origin',
useCredentials: false,
cache: 'default',
redirect: 'follow',
integrity: '',
cryptoGraphicsNonceMetadata: '',
parserMetadata: '',
reloadNavigation: false,
historyNavigation: false,
userActivation: false,
taintedOrigin: false,
redirectCount: 0,
responseTainting: 'basic',
preventNoCacheCacheControlHeaderModification: false,
done: false,
timingAllowFailed: false,
headersList: [HeadersList],
urlList: [Array],
url: [URL]
},
[Symbol(signal)]: AbortSignal { aborted: false },
[Symbol(headers)]: HeadersList {
[Symbol(headers map)]: [Map],
[Symbol(headers map sorted)]: null
}
},
env: {},
executionCtx: undefined,
notFoundHandler: [Function (anonymous)],
finalized: false,
_map: {
projectId: 'dev',
payload: {
user: '12345678',
role: 'user',
exp: 1659969502,
projectId: 'dev',
signupDate: 1659967702,
purchased: false,
type: 'access',
iat: 1659967702
}
}
}
Event isn't defined anywhere.
What am I doing wrong? I am using Hono 1.6.4, I can upgrade if it would help.
Updated to latest and issue still occurs.
Hi @tokenhousetopdev !
An instance of FetchEvent (event) does not include an ExecutionContext object. So, we have to mock it. In the test of Cache Middleware, we make the mock object like this:
https://github.com/honojs/hono/blob/6d306b821873130938808cdc97a6754f29bc4998/src/middleware/cache/index.test.ts#L5-L12
And, make an instance of ExecutionContext , call app.fetch method:
const ctx = new Context()
const doSomething = async() => console.log('foo')
ctx.waitUntil(doSomething())
const res = await app.fetch(new Request('http://localhost/'), undefined, ctx)
This is mock but actually works. Although it will execute asynchronously, the waitUntil may work in your test.
Please try this, and tell me if it will work or not.
Hey! Thanks for the reply but unfortunately I am still struggling with this a little.
Above my tests I have:
class Context {
passThroughOnException() {
throw new Error('Method not implemented.')
}
async waitUntil(promise) {
await promise
}
}
(Please bear in mind I am not using typescript)
And in my test I am doing:
const ctx = new Context()
const req = new Request(formattedUrl, options)
return app.request(req, undefined, ctx)
Upon running this I get the error This context has no FetchEvent. Where am I going wrong? I tried extending FetchEvent but ran into more issues as I don't really know what I should be setting etc.
Hi @tokenhousetopdev !
Use app.fetch instead of app.request. app.request handles only Request object. To test ExecutionContext, we should use app.fetch. Here is all of the test code that really works:
import { Hono } from 'hono'
const app = new Hono()
class Context implements ExecutionContext {
passThroughOnException(): void {
throw new Error('Method not implemented.')
}
async waitUntil(promise: Promise<any>): Promise<void> {
await promise
}
}
app.get('/', (c) => {
const doSomething = async () => console.log('foo')
c.executionCtx.waitUntil(doSomething())
return c.text('bar')
})
describe('Test the application', () => {
it('Should return 200 response', async () => {
const ctx = new Context()
const req = new Request('http://localhost/')
const res = await app.fetch(req, undefined, ctx)
expect(res.status).toBe(200)
})
})
Ahh I am using the service worker syntax so what should I do e.g. instead of the below
app.get('/', (c) => {
const doSomething = async () => console.log('foo')
c.executionCtx.waitUntil(doSomething())
return c.text('bar')
})
I would do:
app.get('/', (c) => {
const doSomething = async () => console.log('foo')
c.event.waitUntil(doSomething())
return c.text('bar')
})
Thanks!
Hi @tokenhousetopdev, The problem is solved?
Addition:
Wouldn't below work?
c.executionCtx.waitUntil(doSomething())
c.executionCtx is designed to work in both Service Workers and Module Workers mode. So, it should work on your code above.
It seems OK to close this.