diff --git a/crates/trusted-server-js/lib/test/fixtures/paths.ts b/crates/trusted-server-js/lib/test/fixtures/paths.ts new file mode 100644 index 000000000..199b105c1 --- /dev/null +++ b/crates/trusted-server-js/lib/test/fixtures/paths.ts @@ -0,0 +1,17 @@ +import { resolve } from 'node:path'; + +/** + * Absolute path to the edge-injected `gpt_bootstrap.js` that several suites + * evaluate verbatim. + * + * Resolved from `import.meta.dirname`, which Node defines as a platform-native + * directory path. A `file:` URL pathname is not a filesystem path, because on + * Windows it carries a leading slash before the drive letter, so reading it + * directly makes Node resolve it against the current drive and the drive + * segment doubles. Resolving from this module's own directory also keeps the + * path independent of the working directory the suite is launched from. + */ +export const GPT_BOOTSTRAP_PATH = resolve( + import.meta.dirname, + '../../../../trusted-server-core/src/integrations/gpt_bootstrap.js' +); diff --git a/crates/trusted-server-js/lib/test/integrations/gpt/ad_init.test.ts b/crates/trusted-server-js/lib/test/integrations/gpt/ad_init.test.ts index b7186518b..51d8cabbf 100644 --- a/crates/trusted-server-js/lib/test/integrations/gpt/ad_init.test.ts +++ b/crates/trusted-server-js/lib/test/integrations/gpt/ad_init.test.ts @@ -1,11 +1,10 @@ import { readFileSync } from 'node:fs'; import { readFile } from 'node:fs/promises'; -import path from 'node:path'; -import { resolve } from 'node:path'; import { describe, it, expect, vi, beforeEach, afterEach, afterAll } from 'vitest'; import envelope from '../../fixtures/aps-renderer-v1.json'; +import { GPT_BOOTSTRAP_PATH } from '../../fixtures/paths'; import type { AuctionBidData, TsjsApi } from '../../../src/core/types'; import { APS_PREBID_CREATIVE_RUNNER_URL, @@ -120,20 +119,7 @@ type TestWindow = Omit & { }; async function runGptBootstrapWithGoogleTag(googletag: object): Promise { - const bootstrapUrl = new URL( - '../../../../../trusted-server-core/src/integrations/gpt_bootstrap.js', - import.meta.url - ); - const urlPath = decodeURIComponent(bootstrapUrl.pathname); - let bootstrapPath: string; - if (urlPath.startsWith('/@fs/')) { - bootstrapPath = urlPath.slice('/@fs'.length); - } else if (bootstrapUrl.protocol === 'file:') { - bootstrapPath = urlPath; - } else { - bootstrapPath = path.resolve(process.cwd(), `.${urlPath}`); - } - const bootstrap = await readFile(bootstrapPath, 'utf8'); + const bootstrap = await readFile(GPT_BOOTSTRAP_PATH, 'utf8'); const runBootstrap = new Function('window', 'googletag', bootstrap) as ( window: Window, googletag: object @@ -145,10 +131,7 @@ type HandoffImplementation = 'bootstrap' | 'bundle'; async function installHandoff(implementation: HandoffImplementation): Promise { if (implementation === 'bootstrap') { - const bootstrap = readFileSync( - resolve(process.cwd(), '../../trusted-server-core/src/integrations/gpt_bootstrap.js'), - 'utf8' - ); + const bootstrap = readFileSync(GPT_BOOTSTRAP_PATH, 'utf8'); window.eval(bootstrap); return; } @@ -201,10 +184,7 @@ function appendResponsiveSlotElement( } function runGptBootstrap(): void { - const bootstrap = readFileSync( - resolve(process.cwd(), '../../trusted-server-core/src/integrations/gpt_bootstrap.js'), - 'utf8' - ); + const bootstrap = readFileSync(GPT_BOOTSTRAP_PATH, 'utf8'); window.eval(bootstrap); } @@ -1150,10 +1130,7 @@ describe('installTsAdInit', () => { gptSlotHandoffs: { 'div-ts-fallback': handoff }, }; - const bootstrap = readFileSync( - resolve(process.cwd(), '../../trusted-server-core/src/integrations/gpt_bootstrap.js'), - 'utf8' - ); + const bootstrap = readFileSync(GPT_BOOTSTRAP_PATH, 'utf8'); window.eval(bootstrap); expect(() => diff --git a/crates/trusted-server-js/lib/test/integrations/gpt/gpt_bootstrap.test.ts b/crates/trusted-server-js/lib/test/integrations/gpt/gpt_bootstrap.test.ts index ab6d646f2..e9ed4a169 100644 --- a/crates/trusted-server-js/lib/test/integrations/gpt/gpt_bootstrap.test.ts +++ b/crates/trusted-server-js/lib/test/integrations/gpt/gpt_bootstrap.test.ts @@ -1,9 +1,9 @@ import { readFileSync } from 'node:fs'; -import path from 'node:path'; import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import type { TsjsApi } from '../../../src/core/types'; +import { GPT_BOOTSTRAP_PATH } from '../../fixtures/paths'; /** * Executable coverage for the edge-injected `gpt_bootstrap.js` — the @@ -12,15 +12,8 @@ import type { TsjsApi } from '../../../src/core/types'; * `crates/trusted-server-core/src/integrations/gpt_bootstrap.js` and is * evaluated here verbatim, so the degradation path (fallback `adInit` and * fallback `scheduleInitialAdInit`) is executed, not string-matched. - * - * Vitest runs with the lib directory as cwd (the vitest.config.ts root), so - * the bootstrap is resolved relative to it rather than via import.meta.url, - * which the jsdom environment rewrites to a non-file scheme. */ -const BOOTSTRAP_SOURCE = readFileSync( - path.resolve(process.cwd(), '../../trusted-server-core/src/integrations/gpt_bootstrap.js'), - 'utf8' -); +const BOOTSTRAP_SOURCE = readFileSync(GPT_BOOTSTRAP_PATH, 'utf8'); // The command queue the bootstrap pushes into: a real array once GPT has // loaded, or the bare `push`-only stub GPT installs before then. diff --git a/crates/trusted-server-js/lib/test/integrations/gpt/schedule_initial_ad_init.test.ts b/crates/trusted-server-js/lib/test/integrations/gpt/schedule_initial_ad_init.test.ts index 727300aa1..6ca610547 100644 --- a/crates/trusted-server-js/lib/test/integrations/gpt/schedule_initial_ad_init.test.ts +++ b/crates/trusted-server-js/lib/test/integrations/gpt/schedule_initial_ad_init.test.ts @@ -1,9 +1,9 @@ import { readFileSync } from 'node:fs'; -import path from 'node:path'; import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import type { TsjsApi } from '../../../src/core/types'; +import { GPT_BOOTSTRAP_PATH } from '../../fixtures/paths'; type TestWindow = Window & { googletag?: unknown; @@ -12,10 +12,7 @@ type TestWindow = Window & { const originalPushState = history.pushState.bind(history); const originalReplaceState = history.replaceState.bind(history); -const BOOTSTRAP_SOURCE = readFileSync( - path.resolve(process.cwd(), '../../trusted-server-core/src/integrations/gpt_bootstrap.js'), - 'utf8' -); +const BOOTSTRAP_SOURCE = readFileSync(GPT_BOOTSTRAP_PATH, 'utf8'); function runBootstrap(): void { new Function(BOOTSTRAP_SOURCE)(); diff --git a/crates/trusted-server-js/lib/test/integrations/gpt/spa_hook.test.ts b/crates/trusted-server-js/lib/test/integrations/gpt/spa_hook.test.ts index 314348fa8..24ed04431 100644 --- a/crates/trusted-server-js/lib/test/integrations/gpt/spa_hook.test.ts +++ b/crates/trusted-server-js/lib/test/integrations/gpt/spa_hook.test.ts @@ -1,9 +1,9 @@ import { readFileSync } from 'node:fs'; -import { resolve } from 'node:path'; import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import type { TsjsApi } from '../../../src/core/types'; +import { GPT_BOOTSTRAP_PATH } from '../../fixtures/paths'; type TestWindow = Window & { googletag?: unknown; @@ -148,10 +148,7 @@ describe('installSpaAuctionHook', () => { }; if (implementation === 'bootstrap') { - const bootstrap = readFileSync( - resolve(process.cwd(), '../../trusted-server-core/src/integrations/gpt_bootstrap.js'), - 'utf8' - ); + const bootstrap = readFileSync(GPT_BOOTSTRAP_PATH, 'utf8'); window.eval(bootstrap); } await importGptModule();