This commit is contained in:
2025-12-12 21:39:48 +01:00
parent ddbd99b747
commit cae81b1088
49 changed files with 777 additions and 269 deletions

View File

@@ -1,6 +1,8 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { describe, it, expect, beforeEach, afterEach, beforeAll, afterAll } from 'vitest';
import * as fs from 'fs';
import * as path from 'path';
import type { LoggerPort } from '@gridpilot/automation/application/ports/LoggerPort';
import type { LogContext } from '@gridpilot/automation/application/ports/LoggerContext';
/**
* Integration tests for Browser Mode in PlaywrightAutomationAdapter - GREEN PHASE
@@ -27,7 +29,12 @@ describe('Browser Mode Integration - GREEN Phase', () => {
beforeEach(() => {
process.env = { ...originalEnv };
delete process.env.NODE_ENV;
Object.defineProperty(process.env, 'NODE_ENV', {
value: undefined,
writable: true,
enumerable: true,
configurable: true
});
});
beforeAll(() => {
@@ -53,7 +60,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
afterAll(() => {
if (unhandledRejectionHandler) {
process.removeListener('unhandledRejection', unhandledRejectionHandler);
(process as any).removeListener('unhandledRejection', unhandledRejectionHandler);
unhandledRejectionHandler = null;
}
});
@@ -72,7 +79,12 @@ describe('Browser Mode Integration - GREEN Phase', () => {
describe('Headless Mode Launch (NODE_ENV=production/test)', () => {
it('should launch browser with headless: true when NODE_ENV=production', async () => {
process.env.NODE_ENV = 'production';
Object.defineProperty(process.env, 'NODE_ENV', {
value: 'production',
writable: true,
enumerable: true,
configurable: true
});
const { PlaywrightAutomationAdapter } = await import(
'packages/automation/infrastructure/adapters/automation'
@@ -80,8 +92,8 @@ describe('Browser Mode Integration - GREEN Phase', () => {
adapter = new PlaywrightAutomationAdapter({
mode: 'mock',
});
}, undefined, undefined);
const result = await adapter.connect();
expect(result.success).toBe(true);
@@ -91,7 +103,12 @@ describe('Browser Mode Integration - GREEN Phase', () => {
});
it('should launch browser with headless: true when NODE_ENV=test', async () => {
process.env.NODE_ENV = 'test';
Object.defineProperty(process.env, 'NODE_ENV', {
value: 'test',
writable: true,
enumerable: true,
configurable: true
});
const { PlaywrightAutomationAdapter } = await import(
'packages/automation/infrastructure/adapters/automation'
@@ -99,8 +116,8 @@ describe('Browser Mode Integration - GREEN Phase', () => {
adapter = new PlaywrightAutomationAdapter({
mode: 'mock',
});
}, undefined, undefined);
const result = await adapter.connect();
expect(result.success).toBe(true);
@@ -110,7 +127,12 @@ describe('Browser Mode Integration - GREEN Phase', () => {
});
it('should default to headless when NODE_ENV is not set', async () => {
delete process.env.NODE_ENV;
Object.defineProperty(process.env, 'NODE_ENV', {
value: undefined,
writable: true,
enumerable: true,
configurable: true
});
const { PlaywrightAutomationAdapter } = await import(
'packages/automation/infrastructure/adapters/automation'
@@ -118,8 +140,8 @@ describe('Browser Mode Integration - GREEN Phase', () => {
adapter = new PlaywrightAutomationAdapter({
mode: 'mock',
});
}, undefined, undefined);
await adapter.connect();
expect(adapter.getBrowserMode()).toBe('headless');
@@ -134,7 +156,12 @@ describe('Browser Mode Integration - GREEN Phase', () => {
});
it('should report NODE_ENV as source in production mode', async () => {
process.env.NODE_ENV = 'production';
Object.defineProperty(process.env, 'NODE_ENV', {
value: 'production',
writable: true,
enumerable: true,
configurable: true
});
const { PlaywrightAutomationAdapter } = await import(
'packages/automation/infrastructure/adapters/automation'
@@ -142,7 +169,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
adapter = new PlaywrightAutomationAdapter({
mode: 'mock',
});
}, undefined, undefined);
await adapter.connect();
@@ -150,7 +177,12 @@ describe('Browser Mode Integration - GREEN Phase', () => {
});
it('should report NODE_ENV as source in test mode', async () => {
process.env.NODE_ENV = 'test';
Object.defineProperty(process.env, 'NODE_ENV', {
value: 'test',
writable: true,
enumerable: true,
configurable: true
});
const { PlaywrightAutomationAdapter } = await import(
'packages/automation/infrastructure/adapters/automation'
@@ -158,7 +190,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
adapter = new PlaywrightAutomationAdapter({
mode: 'mock',
});
}, undefined);
await adapter.connect();
@@ -173,22 +205,26 @@ describe('Browser Mode Integration - GREEN Phase', () => {
});
it('should log browser mode configuration with NODE_ENV source in production', async () => {
process.env.NODE_ENV = 'production';
(process.env as any).NODE_ENV = 'production';
const logSpy: Array<{ level: string; message: string; context?: Record<string, unknown> }> = [];
type LoggerLike = {
debug: (msg: string, ctx?: Record<string, unknown>) => void;
info: (msg: string, ctx?: Record<string, unknown>) => void;
warn: (msg: string, ctx?: Record<string, unknown>) => void;
error: (msg: string, ctx?: Record<string, unknown>) => void;
child: () => LoggerLike;
debug: (message: string, context?: Record<string, unknown>) => void;
info: (message: string, context?: Record<string, unknown>) => void;
warn: (message: string, context?: Record<string, unknown>) => void;
error: (message: string, error?: Error, context?: Record<string, unknown>) => void;
fatal: (message: string, error?: Error, context?: Record<string, unknown>) => void;
child: (context: Record<string, unknown>) => LoggerLike;
flush: () => Promise<void>;
};
const mockLogger: LoggerLike = {
debug: (msg: string, ctx?: Record<string, unknown>) => logSpy.push({ level: 'debug', message: msg, context: ctx }),
info: (msg: string, ctx?: Record<string, unknown>) => logSpy.push({ level: 'info', message: msg, context: ctx }),
warn: (msg: string, ctx?: Record<string, unknown>) => logSpy.push({ level: 'warn', message: msg, context: ctx }),
error: (msg: string, ctx?: Record<string, unknown>) => logSpy.push({ level: 'error', message: msg, context: ctx }),
child: () => mockLogger,
debug: (message: string, context?: Record<string, unknown>) => logSpy.push({ level: 'debug', message, ...(context ? { context } : {}) }),
info: (message: string, context?: Record<string, unknown>) => logSpy.push({ level: 'info', message, ...(context ? { context } : {}) }),
warn: (message: string, context?: Record<string, unknown>) => logSpy.push({ level: 'warn', message, ...(context ? { context } : {}) }),
error: (message: string, error?: Error, context?: Record<string, unknown>) => logSpy.push({ level: 'error', message, ...(context ? { context } : {}) }),
fatal: (message: string, error?: Error, context?: Record<string, unknown>) => logSpy.push({ level: 'fatal', message, ...(context ? { context } : {}) }),
child: (context: Record<string, unknown>) => mockLogger,
flush: () => Promise.resolve(),
};
const { PlaywrightAutomationAdapter } = await import(
@@ -215,7 +251,12 @@ describe('Browser Mode Integration - GREEN Phase', () => {
describe('Persistent Context', () => {
it('should apply browser mode to persistent browser context', async () => {
process.env.NODE_ENV = 'production';
Object.defineProperty(process.env, 'NODE_ENV', {
value: 'production',
writable: true,
enumerable: true,
configurable: true
});
const { PlaywrightAutomationAdapter } = await import(
'packages/automation/infrastructure/adapters/automation'
@@ -226,8 +267,8 @@ describe('Browser Mode Integration - GREEN Phase', () => {
adapter = new PlaywrightAutomationAdapter({
mode: 'real',
userDataDir,
});
}, undefined, undefined);
await adapter.connect();
expect(adapter.getBrowserMode()).toBe('headless');
@@ -242,7 +283,12 @@ describe('Browser Mode Integration - GREEN Phase', () => {
describe('Runtime loader re-read instrumentation (test-only)', () => {
it('reads mode from injected loader and passes headless flag to launcher accordingly', async () => {
process.env.NODE_ENV = 'development';
Object.defineProperty(process.env, 'NODE_ENV', {
value: 'development',
writable: true,
enumerable: true,
configurable: true
});
const { PlaywrightAutomationAdapter } = await import(
'packages/automation/infrastructure/adapters/automation'
);
@@ -293,7 +339,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
const r1 = await adapter.connect();
expect(r1.success).toBe(true);
expect(launches.length).toBeGreaterThan(0);
expect(launches[0].opts.headless).toBe(false);
expect((launches[0] as any).opts.headless).toBe(false);
// Disconnect and change loader to headless
await adapter.disconnect();
@@ -305,10 +351,10 @@ describe('Browser Mode Integration - GREEN Phase', () => {
// The second recorded launch may be at index 1 if both calls used the same launcher path
const secondLaunch = launches.slice(1).find(l => l.type === 'launch' || l.type === 'launchPersistent');
expect(secondLaunch).toBeDefined();
expect(secondLaunch!.opts.headless).toBe(true);
expect(secondLaunch!.opts?.headless).toBe(true);
// Cleanup test hook
AdapterWithTestLauncher.testLauncher = undefined;
(AdapterWithTestLauncher as any).testLauncher = undefined;
await adapter.disconnect();
});
});