Parcourir la source

Keep pending invariant children behind readiness

Hypatia May il y a 1 mois
Parent
commit
ed41269e04
2 fichiers modifiés avec 51 ajouts et 1 suppressions
  1. 45 0
      scripts/test-invariants.spec.ts
  2. 6 1
      scripts/test-invariants.ts

+ 45 - 0
scripts/test-invariants.spec.ts

@@ -236,6 +236,51 @@ describe('global test invariant host', () => {
     )
   })
 
+  it('holds a child registered externally on a pending target context', async () => {
+    const delayedStarted = deferred()
+    const releaseDelayed = deferred()
+
+    await withFakeCompanions(
+      (_path, index) => async () => ({
+        name: `test-invariant-${index}`,
+        inject: ['invariants'],
+        async apply() {
+          if (index === 0) {
+            delayedStarted.resolve()
+            await releaseDelayed.promise
+          }
+          return () => {}
+        },
+      }),
+      async () => {
+        const ctx = new Context()
+        const targetApply = vi.fn(function targetApply() {})
+        const childApply = vi.fn(function childApply() {})
+
+        const targetFiber = ctx.plugin(targetApply)
+        const childFiber = targetFiber.ctx.plugin(childApply)
+
+        await delayedStarted.promise
+        await Promise.resolve()
+        await Promise.resolve()
+        expect(targetFiber.state).toBe(FiberState.PENDING)
+        expect(childFiber.state).toBe(FiberState.PENDING)
+        expect(targetApply).not.toHaveBeenCalled()
+        expect(childApply).not.toHaveBeenCalled()
+        expect(childFiber.inject).toEqual({
+          [TEST_INVARIANT_READY_SERVICE]: null,
+        })
+
+        releaseDelayed.resolve()
+        await Promise.all([targetFiber, childFiber])
+        expect(targetFiber.state).toBe(FiberState.ACTIVE)
+        expect(childFiber.state).toBe(FiberState.ACTIVE)
+        expect(targetApply).toHaveBeenCalledOnce()
+        expect(childApply).toHaveBeenCalledOnce()
+      },
+    )
+  })
+
   it.each(['load', 'startup'] as const)(
     'rejects a target when a lazy companion fails during %s without starting the target',
     async (phase) => {

+ 6 - 1
scripts/test-invariants.ts

@@ -171,7 +171,12 @@ function startInvariantHost(root: Context): InvariantHost {
 function hasBarrierOwner(host: InvariantHost, ctx: Context): boolean {
   let fiber = ctx.fiber
   while (true) {
-    if (host.barrierOwners.has(fiber)) return true
+    if (
+      host.barrierOwners.has(fiber)
+      && (fiber.state === FiberState.LOADING || fiber.state === FiberState.ACTIVE)
+    ) {
+      return true
+    }
     const parent = fiber.parent.fiber
     if (parent === fiber) return false
     fiber = parent