@@ -16,8 +16,7 @@ import type {
1616import { Pool } from "pg"
1717import type { Jsonifiable } from "type-fest"
1818import type { ExecutionContext } from "ava"
19- import { once } from "node:events"
20- import { createBirpc } from "birpc"
19+ import { BirpcReturn , createBirpc } from "birpc"
2120import { ExecResult } from "testcontainers"
2221import isPlainObject from "lodash/isPlainObject"
2322
@@ -136,57 +135,86 @@ export const getTestPostgresDatabaseFactory = <
136135 }
137136
138137 let rpcCallback : ( data : any ) => void
139- const rpc = createBirpc < SharedWorkerFunctions , TestWorkerFunctions > (
140- {
141- runBeforeTemplateIsBakedHook : async ( connection , params ) => {
142- if ( options ?. beforeTemplateIsBaked ) {
143- const connectionDetails =
144- mapWorkerConnectionDetailsToConnectionDetails ( connection )
145-
146- // Ignore if the pool is terminated by the shared worker
147- // (This happens in CI for some reason even though we drain the pool first.)
148- connectionDetails . pool . on ( "error" , ( error ) => {
149- if (
150- error . message . includes (
151- "terminating connection due to administrator command"
152- )
153- ) {
154- return
155- }
138+ const rpc : BirpcReturn < SharedWorkerFunctions , TestWorkerFunctions > =
139+ createBirpc < SharedWorkerFunctions , TestWorkerFunctions > (
140+ {
141+ runBeforeTemplateIsBakedHook : async ( connection , params ) => {
142+ if ( options ?. beforeTemplateIsBaked ) {
143+ const connectionDetails =
144+ mapWorkerConnectionDetailsToConnectionDetails ( connection )
145+
146+ // Ignore if the pool is terminated by the shared worker
147+ // (This happens in CI for some reason even though we drain the pool first.)
148+ connectionDetails . pool . on ( "error" , ( error ) => {
149+ if (
150+ error . message . includes (
151+ "terminating connection due to administrator command"
152+ )
153+ ) {
154+ return
155+ }
156+
157+ throw error
158+ } )
159+
160+ const createdNestedConnections : ConnectionDetails [ ] = [ ]
161+ const hookResult = await options . beforeTemplateIsBaked ( {
162+ params : params as any ,
163+ connection : connectionDetails ,
164+ containerExec : async ( command ) : Promise < ExecResult > =>
165+ rpc . execCommandInContainer ( command ) ,
166+ // This is what allows a consumer to get a "nested" database from within their beforeTemplateIsBaked hook
167+ beforeTemplateIsBaked : async ( options ) => {
168+ const { connectionDetails, beforeTemplateIsBakedResult } =
169+ await rpc . getTestDatabase ( {
170+ params : options . params ,
171+ databaseDedupeKey : options . databaseDedupeKey ,
172+ } )
156173
157- throw error
158- } )
174+ const mappedConnection =
175+ mapWorkerConnectionDetailsToConnectionDetails (
176+ connectionDetails
177+ )
159178
160- const hookResult = await options . beforeTemplateIsBaked ( {
161- params : params as any ,
162- connection : connectionDetails ,
163- containerExec : async ( command ) : Promise < ExecResult > =>
164- rpc . execCommandInContainer ( command ) ,
165- } )
179+ createdNestedConnections . push ( mappedConnection )
166180
167- await teardownConnection ( connectionDetails )
181+ return {
182+ ...mappedConnection ,
183+ beforeTemplateIsBakedResult,
184+ }
185+ } ,
186+ } )
168187
169- if ( hookResult && ! isSerializable ( hookResult ) ) {
170- throw new TypeError (
171- "Return value of beforeTemplateIsBaked() hook could not be serialized. Make sure it returns only JSON-serializable values."
188+ await Promise . all (
189+ createdNestedConnections . map ( async ( connection ) => {
190+ await teardownConnection ( connection )
191+ await rpc . dropDatabase ( connection . database )
192+ } )
172193 )
173- }
174194
175- return hookResult
176- }
177- } ,
178- } ,
179- {
180- post : async ( data ) => {
181- const worker = await workerPromise
182- await worker . available
183- worker . publish ( data )
184- } ,
185- on : ( data ) => {
186- rpcCallback = data
195+ await teardownConnection ( connectionDetails )
196+
197+ if ( hookResult && ! isSerializable ( hookResult ) ) {
198+ throw new TypeError (
199+ "Return value of beforeTemplateIsBaked() hook could not be serialized. Make sure it returns only JSON-serializable values."
200+ )
201+ }
202+
203+ return hookResult
204+ }
205+ } ,
187206 } ,
188- }
189- )
207+ {
208+ post : async ( data ) => {
209+ const worker = await workerPromise
210+ await worker . available
211+ worker . publish ( data )
212+ } ,
213+ on : ( data ) => {
214+ rpcCallback = data
215+ } ,
216+ }
217+ )
190218
191219 // Automatically cleaned up by AVA since each test file runs in a separate worker
192220 const _messageHandlerPromise = ( async ( ) => {
0 commit comments