@@ -6,65 +6,22 @@ import type {
66} from "@jest/environment" ;
77import { LegacyFakeTimers , ModernFakeTimers } from "@jest/fake-timers" ;
88import type { Circus , Config , Global } from "@jest/types" ;
9- import { CachePlugin } from "@miniflare/cache" ;
10- import {
11- BindingsPlugin ,
12- CorePlugin ,
13- MiniflareCore ,
14- createFetchMock ,
15- } from "@miniflare/core" ;
16- import {
17- DurableObjectId ,
18- DurableObjectStorage ,
19- DurableObjectsPlugin ,
20- } from "@miniflare/durable-objects" ;
21- import { HTMLRewriterPlugin } from "@miniflare/html-rewriter" ;
22- import { KVPlugin } from "@miniflare/kv" ;
23- import { R2Plugin } from "@miniflare/r2" ;
9+ import { MiniflareCore } from "@miniflare/core" ;
2410import { VMScriptRunner , defineHasInstances } from "@miniflare/runner-vm" ;
25- import { Context , NoOpLog } from "@miniflare/shared" ;
26- import { SitesPlugin } from "@miniflare/sites" ;
27- import { WebSocketPlugin } from "@miniflare/web-sockets" ;
11+ import {
12+ PLUGINS ,
13+ StackedMemoryStorageFactory ,
14+ createMiniflareEnvironment ,
15+ } from "@miniflare/shared-test-environment" ;
2816import { ModuleMocker } from "jest-mock" ;
2917import { installCommonGlobals } from "jest-util" ;
30- import { MockAgent } from "undici" ;
31- import { StackedMemoryStorageFactory } from "./storage" ;
32-
33- declare global {
34- function getMiniflareBindings < Bindings = Context > ( ) : Bindings ;
35- function getMiniflareDurableObjectStorage (
36- id : DurableObjectId
37- ) : Promise < DurableObjectStorage > ;
38- function getMiniflareFetchMock ( ) : MockAgent ;
39- function flushMiniflareDurableObjectAlarms (
40- ids : DurableObjectId [ ]
41- ) : Promise < void > ;
42- }
43-
44- // MiniflareCore will ensure CorePlugin is first and BindingsPlugin is last,
45- // so help it out by doing it ourselves so it doesn't have to. BuildPlugin
46- // is intentionally omitted as the worker should only be built once per test
47- // run, as opposed to once per test suite. The user is responsible for this.
48- const PLUGINS = {
49- CorePlugin,
50- KVPlugin,
51- R2Plugin,
52- DurableObjectsPlugin,
53- CachePlugin,
54- SitesPlugin,
55- HTMLRewriterPlugin,
56- WebSocketPlugin,
57- BindingsPlugin,
58- } ;
5918
6019export type Timer = {
6120 id : number ;
6221 ref : ( ) => Timer ;
6322 unref : ( ) => Timer ;
6423} ;
6524
66- const log = new NoOpLog ( ) ;
67-
6825// Adapted from jest-environment-node:
6926// https://github.com/facebook/jest/blob/8f2cdad7694f4c217ac779d3f4e3a150b5a3d74d/packages/jest-environment-node/src/index.ts
7027export default class MiniflareEnvironment implements JestEnvironment < Timer > {
@@ -81,7 +38,7 @@ export default class MiniflareEnvironment implements JestEnvironment<Timer> {
8138
8239 private readonly storageFactory = new StackedMemoryStorageFactory ( ) ;
8340 private readonly scriptRunner : VMScriptRunner ;
84- private readonly mockAgent : MockAgent ;
41+ private mf ?: MiniflareCore < typeof PLUGINS > ;
8542
8643 constructor (
8744 config :
@@ -102,8 +59,6 @@ export default class MiniflareEnvironment implements JestEnvironment<Timer> {
10259 defineHasInstances ( this . context ) ;
10360 this . scriptRunner = new VMScriptRunner ( this . context ) ;
10461
105- this . mockAgent = createFetchMock ( ) ;
106-
10762 const global = ( this . global = vm . runInContext ( "this" , this . context ) ) ;
10863 global . global = global ;
10964 global . self = global ;
@@ -162,93 +117,30 @@ export default class MiniflareEnvironment implements JestEnvironment<Timer> {
162117
163118 async setup ( ) : Promise < void > {
164119 const global = this . global as any ;
165-
166- const mf = new MiniflareCore (
167- PLUGINS ,
120+ const [ mf , mfGlobalScope ] = await createMiniflareEnvironment (
168121 {
169- log,
170122 storageFactory : this . storageFactory ,
171123 scriptRunner : this . scriptRunner ,
172- // Only run the script if we're using Durable Objects and need to have
173- // access to the exported classes. This means we're only running the
174- // script in modules mode, so we don't need to worry about
175- // addEventListener being called twice (once when the script is run, and
176- // again when the user imports the worker in Jest tests).
177- scriptRunForModuleExports : true ,
178124 } ,
125+ this . config . testEnvironmentOptions ,
179126 {
180- // Autoload configuration files from default locations by default,
181- // like the CLI (but allow the user to disable this/customise locations)
182- wranglerConfigPath : true ,
183- packagePath : true ,
184- envPathDefaultFallback : true ,
185-
186- // Apply user's custom Miniflare options
187- ...this . config . testEnvironmentOptions ,
188-
189- globals : {
190- ...( this . config . testEnvironmentOptions ?. globals as any ) ,
191-
192- // Make sure fancy jest console and faked timers are included
193- console : global . console ,
194- setTimeout : global . setTimeout ,
195- setInterval : global . setInterval ,
196- clearTimeout : global . clearTimeout ,
197- clearInterval : global . clearInterval ,
198- } ,
199-
200- // These options cannot be overwritten:
201- // - We get the global scope once, so watch mode wouldn't do anything,
202- // apart from stopping Jest exiting
203- watch : false ,
204- // - Persistence must be disabled for stacked storage to work
205- kvPersist : false ,
206- cachePersist : false ,
207- durableObjectsPersist : false ,
208- // - Allow all global operations, tests will be outside of a request
209- // context, but we definitely want to allow people to access their
210- // namespaces, perform I/O, etc.
211- globalAsyncIO : true ,
212- globalTimers : true ,
213- globalRandom : true ,
214- // - Use the actual `Date` class. We'll be operating outside a request
215- // context, so we'd be returning the actual time anyway, and this
216- // might mess with Jest's own mocking.
217- actualTime : true ,
218- // - We always want getMiniflareFetchMock() to return this MockAgent
219- fetchMock : this . mockAgent ,
127+ // Make sure fancy jest console and faked timers are included
128+ console : global . console ,
129+ setTimeout : global . setTimeout ,
130+ setInterval : global . setInterval ,
131+ clearTimeout : global . clearTimeout ,
132+ clearInterval : global . clearInterval ,
220133 }
221134 ) ;
135+ this . mf = mf ;
222136
223- const mfGlobalScope = await mf . getGlobalScope ( ) ;
224- mfGlobalScope . global = global ;
225- mfGlobalScope . self = global ;
226137 // Make sure Miniflare's global scope is assigned to Jest's global context,
227138 // even if we didn't run a script because we had no Durable Objects
228139 Object . assign ( global , mfGlobalScope ) ;
229-
230- // Add a way of getting bindings in modules mode to allow seeding data.
231- // These names are intentionally verbose so they don't collide with anything
232- // else in scope.
233- const bindings = await mf . getBindings ( ) ;
234- global . getMiniflareBindings = ( ) => bindings ;
235- global . getMiniflareDurableObjectStorage = async ( id : DurableObjectId ) => {
236- const plugin = ( await mf . getPlugins ( ) ) . DurableObjectsPlugin ;
237- const storage = mf . getPluginStorage ( "DurableObjectsPlugin" ) ;
238- const state = await plugin . getObject ( storage , id ) ;
239- return state . storage ;
240- } ;
241- global . getMiniflareFetchMock = ( ) => this . mockAgent ;
242- global . flushMiniflareDurableObjectAlarms = async (
243- ids ?: DurableObjectId [ ]
244- ) : Promise < void > => {
245- const plugin = ( await mf . getPlugins ( ) ) . DurableObjectsPlugin ;
246- const storage = mf . getPluginStorage ( "DurableObjectsPlugin" ) ;
247- return plugin . flushAlarms ( storage , ids ) ;
248- } ;
249140 }
250141
251142 async teardown ( ) : Promise < void > {
143+ await this . mf ?. dispose ( ) ;
252144 this . fakeTimers ?. dispose ( ) ;
253145 this . fakeTimersModern ?. dispose ( ) ;
254146 this . context = null ;
0 commit comments