Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FetchEvent#waitUntil in Jest context #202

Closed
jamesarosen opened this issue Mar 3, 2022 · 6 comments · Fixed by #345
Closed

FetchEvent#waitUntil in Jest context #202

jamesarosen opened this issue Mar 3, 2022 · 6 comments · Fixed by #345
Labels
enhancement New feature or request quick win
Milestone

Comments

@jamesarosen
Copy link

jamesarosen commented Mar 3, 2022

Problem

The promises passed to FetchEvent.prototype.waitUntil cannot be retrieved via Response.prototype.waitUntil(). There doesn't seem to be any other way to access them either, but if there is, the Writing and Running Tests docs don't mention it.

Configuration

// jest.config.js
module.exports = {
  testEnvironment: 'miniflare',
}

Example Code

describe('waitUntil', () => {
  it('caches things', async () => {
    async function myHandler(fetchEvent) {
      const { url } = fetchEvent.request
      fetchEvent.waitUntil(caches.default.put(url, new Response('written to cache')))
      return new Response('returned from worker')
    }

    // build a FetchEvent:
    const url = 'https://example.com/cache-something'
    const request = new Request(url)
    const fetchEvent = new FetchEvent('fetch', { request })

    // get a response for it:
    const response = await myHandler(fetchEvent)

    // the response should have the Promises from `fetchEvent.waitUntil`:
    const awaited = await response.waitUntil()
    expect(awaited[0]).toBeTruthy() // this fails; awaited is []
    expect(await awaited[0].text()).toBe('written to cache')

    // and the cache-write should have completed:
    const cachedResponse = await caches.default.match(url)
    expect(cachedResponse).toBeTruthy()
    expect(await cachedResponse.text()).toBe('written to cache')
  })
})
@jamesarosen jamesarosen changed the title FetchEvent.waitUntil in Jest context FetchEvent#waitUntil in Jest context Mar 3, 2022
@jamesarosen
Copy link
Author

jamesarosen commented Mar 4, 2022

The implementation of FetchEvent.prototype.waitUntil stores the promises, but they're locked away behind a Symbol:

waitUntil(promise: Awaitable<any>): void {
if (!(this instanceof FetchEvent)) {
throw new TypeError("Illegal invocation");
}
this[kWaitUntil].push(Promise.resolve(promise));
}

@mrbbot
Copy link
Contributor

mrbbot commented Mar 4, 2022

Hey! 👋 Thanks for raising this. Will try get a getWaitUntil(event) method added and exposed to tests soon. 🙂

@mrbbot mrbbot added the enhancement New feature or request label Mar 4, 2022
@mrbbot mrbbot added this to the 2.4.0 milestone Mar 8, 2022
@mrbbot mrbbot modified the milestones: 2.4.0, 2.5.0 Apr 2, 2022
@mrbbot mrbbot modified the milestones: 2.5.0, 2.6.0 May 27, 2022
@mrbbot mrbbot modified the milestones: 2.6.0, 2.7.0 Jul 9, 2022
@jamesarosen
Copy link
Author

@mrbbot any news on this? Can I help?

@mrbbot
Copy link
Contributor

mrbbot commented Aug 13, 2022

Hey! 👋 Apologies for the delayed response. I've recently returned from a long holiday and am catching up on issues now.

@jamesarosen I'd be very happy to accept a pull-request for this, otherwise I can do it. You'll need to add a getMiniflareWaitUntil method here...

global.getMiniflareBindings = () => bindings;
global.getMiniflareDurableObjectStorage = async (id: DurableObjectId) => {
const plugin = (await mf.getPlugins()).DurableObjectsPlugin;
const storage = mf.getPluginStorage("DurableObjectsPlugin");
const state = await plugin.getObject(storage, id);
return state.storage;
};
global.flushMiniflareDurableObjectAlarms = async (
ids?: DurableObjectId[]
): Promise<void> => {
const plugin = (await mf.getPlugins()).DurableObjectsPlugin;
const storage = mf.getPluginStorage("DurableObjectsPlugin");
return plugin.flushAlarms(storage, ids);
};

...that accesses the [kWaitUntil] field of FetchEvent | ScheduledEvent. You'll probably want to export a getWaitUntil helper from this file, as kWaitUntil shouldn't be exported.

const kWaitUntil = Symbol("kWaitUntil");

@CraigglesO
Copy link
Contributor

Just want to add a note that when using cache.put a max-age must be provided otherwise the cache tosses it out immediately:

function testResponse(body) {
  return new Response(body, { headers: { "Cache-Control": "max-age=3600" } });
}

...

event.waitUntil(caches.default.put(url, testResponse("example cache")));

@jamesarosen
Copy link
Author

jamesarosen commented Sep 7, 2022

@CraigglesO I poked at this a bit. I'm glad you did it because your #345 looks much better than what I had!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request quick win
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants