Mount the @data harness inside Refine, and stop the bundle leaking globals
The harness builds its bundles with a classic script tag, so an unwrapped bundle publishes every top-level declaration as a global. Bundling Refine brought in @tanstack/query-core, whose exported MutationObserver class then shadowed the DOM one for Playwright's injected script, and every waitForFunction died on defaultMutationOptions. --format=iife keeps the bundle's declarations to itself. The harness also mounted the data context outside <Refine> and called the previous bootstrapWallet signature; it now mirrors the app's provider order and seeds through the context, so tests and app write events by one path.
This commit is contained in:
@@ -325,13 +325,24 @@ async function ensureAuth(): Promise<void> {
|
||||
BeforeAll({ timeout: 10 * 60 * 1000 }, async function () {
|
||||
console.log('Starting Festipod BDD tests...');
|
||||
|
||||
// `--format=iife` IS LOad-BEARING, not tidiness. Both bundles are loaded as
|
||||
// CLASSIC scripts (`<script src="/harness.js">` for the NG harness,
|
||||
// `addScriptTag({path})` for the mock one), so every top-level declaration in
|
||||
// an unwrapped bundle becomes a GLOBAL binding. `@tanstack/query-core` — pulled
|
||||
// in by Refine — exports a class named `MutationObserver`, which then shadows
|
||||
// the DOM's for anything that runs afterwards in that page. Playwright's own
|
||||
// injected script does `new MutationObserver(...)`, so it got TanStack's and
|
||||
// every `waitForFunction` died with "defaultMutationOptions is not a function".
|
||||
// The IIFE wrapper keeps the bundle's declarations to itself; `window.__testData`
|
||||
// is still published explicitly, so the bridge is unaffected.
|
||||
|
||||
// Build the mock harness (always needed for non-@data or fallback)
|
||||
execSync(`bun build ${HARNESS_ENTRY} --outfile ${HARNESS_OUT} --bundle`, { stdio: 'pipe' });
|
||||
execSync(`bun build ${HARNESS_ENTRY} --outfile ${HARNESS_OUT} --bundle --format=iife`, { stdio: 'pipe' });
|
||||
console.log(`[Harness] Built mock (${(fs.statSync(HARNESS_OUT).size / 1024).toFixed(0)} KB)`);
|
||||
|
||||
// Try to build the real broker harness
|
||||
try {
|
||||
execSync(`bun build ${HARNESS_NG_ENTRY} --outfile ${HARNESS_NG_OUT} --bundle`, { stdio: 'pipe' });
|
||||
execSync(`bun build ${HARNESS_NG_ENTRY} --outfile ${HARNESS_NG_OUT} --bundle --format=iife`, { stdio: 'pipe' });
|
||||
console.log(`[Harness] Built NG (${(fs.statSync(HARNESS_NG_OUT).size / 1024).toFixed(0)} KB)`);
|
||||
|
||||
// Ensure wallet exists in persistent profile (opens browser if needed)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { NextGraphProvider, useNextGraph } from '../context/NextGraphContext';
|
||||
import { RefineProvider } from '../refine/RefineProvider';
|
||||
import { FestipodDataProvider, useFestipodData } from '../context/FestipodDataContext';
|
||||
import { useShape } from '@ng-org/orm/react';
|
||||
import { ng } from '@ng-org/web';
|
||||
@@ -21,7 +22,6 @@ import {
|
||||
} from '../shapes/orm/festipodShapes.shapeTypes';
|
||||
import type { FpEvent, FpUserProfile, FpParticipation } from '../shapes/orm/festipodShapes.typings';
|
||||
import { seedEvents, seedUsers, seedParticipations } from '../data/seedData';
|
||||
import { bootstrapWallet } from '../utils/ngBootstrap';
|
||||
import { ensureGraphNuri } from '../utils/ngGraph';
|
||||
|
||||
// ============================================================================
|
||||
@@ -31,9 +31,13 @@ import { ensureGraphNuri } from '../utils/ngGraph';
|
||||
function DataHarnessNG() {
|
||||
return (
|
||||
<NextGraphProvider>
|
||||
<FestipodDataProvider>
|
||||
<HarnessRouter />
|
||||
</FestipodDataProvider>
|
||||
{/* Same order as the real app (app/App.tsx): the data context reads events
|
||||
through Refine's hooks, so it cannot mount outside <Refine>. */}
|
||||
<RefineProvider>
|
||||
<FestipodDataProvider>
|
||||
<HarnessRouter />
|
||||
</FestipodDataProvider>
|
||||
</RefineProvider>
|
||||
</NextGraphProvider>
|
||||
);
|
||||
}
|
||||
@@ -148,9 +152,18 @@ function ConnectedHarness() {
|
||||
}
|
||||
},
|
||||
|
||||
/** Load the app's default seed data into the wallet */
|
||||
/**
|
||||
* Load the app's default seed data into the wallet.
|
||||
*
|
||||
* Delegates to the data context instead of calling `bootstrapWallet`
|
||||
* directly: seeding events now goes through Refine's `create` (one
|
||||
* document per event), and the callback that does it lives in the
|
||||
* context. Calling the bootstrap from here with raw ORM sets would seed
|
||||
* by a DIFFERENT path than the app's — which is the divergence this
|
||||
* harness exists to avoid.
|
||||
*/
|
||||
loadTestData() {
|
||||
return bootstrapWallet(events as any, users as any, participations as any);
|
||||
return appData.loadTestData();
|
||||
},
|
||||
|
||||
// --- Stopgap multi-store validation (see brief_2026-06-15_shared-wallet-shim) ---
|
||||
|
||||
Reference in New Issue
Block a user