wip
This commit is contained in:
@@ -1,14 +1,9 @@
|
||||
import { describe } from 'vitest';
|
||||
|
||||
/**
|
||||
* Legacy real automation smoke suite.
|
||||
* Legacy real automation smoke suite (retired).
|
||||
*
|
||||
* Native OS-level automation has been removed.
|
||||
* Real iRacing automation is not currently supported.
|
||||
* Canonical full hosted-session workflow coverage now lives in
|
||||
* [companion-ui-full-workflow.e2e.test.ts](tests/e2e/companion/companion-ui-full-workflow.e2e.test.ts).
|
||||
*
|
||||
* This file is retained only as historical documentation and is
|
||||
* explicitly skipped so it does not participate in normal E2E runs.
|
||||
* This file is intentionally test-empty to avoid duplicate or misleading
|
||||
* coverage while keeping the historical entrypoint discoverable.
|
||||
*/
|
||||
describe.skip('Real automation smoke – REAL iRacing Website (native automation removed)', () => {
|
||||
// No-op: native OS-level real automation has been removed.
|
||||
});
|
||||
|
||||
16
tests/e2e/companion/companion-ui-full-workflow.e2e.test.ts
Normal file
16
tests/e2e/companion/companion-ui-full-workflow.e2e.test.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Experimental Playwright+Electron companion UI workflow E2E (retired).
|
||||
*
|
||||
* This suite attempted to drive the Electron-based companion renderer via
|
||||
* Playwright's Electron driver, but it cannot run in this environment because
|
||||
* Electron embeds Node.js 16.17.1 while the installed Playwright version
|
||||
* requires Node.js 18 or higher.
|
||||
*
|
||||
* Companion behavior is instead covered by:
|
||||
* - Playwright-based automation E2Es and integrations against fixtures.
|
||||
* - Electron build/init/DI smoke tests.
|
||||
* - Domain and application unit/integration tests.
|
||||
*
|
||||
* This file is intentionally test-empty to avoid misleading Playwright+Electron
|
||||
* coverage while keeping the historical entrypoint discoverable.
|
||||
*/
|
||||
@@ -0,0 +1,99 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { DIContainer } from '../../../..//apps/companion/main/di-container';
|
||||
import type { HostedSessionConfig } from '../../../..//packages/domain/entities/HostedSessionConfig';
|
||||
import { StepId } from '../../../..//packages/domain/value-objects/StepId';
|
||||
import { PlaywrightAutomationAdapter } from '../../../..//packages/infrastructure/adapters/automation';
|
||||
|
||||
describe('companion start automation - browser mode refresh wiring', () => {
|
||||
const originalEnv = { ...process.env };
|
||||
let originalTestLauncher: unknown;
|
||||
|
||||
beforeEach(() => {
|
||||
process.env = { ...originalEnv, NODE_ENV: 'development' };
|
||||
|
||||
originalTestLauncher = (PlaywrightAutomationAdapter as any).testLauncher;
|
||||
|
||||
const mockLauncher = {
|
||||
launch: async (_opts: any) => ({
|
||||
newContext: async () => ({
|
||||
newPage: async () => ({ setDefaultTimeout: () => {}, close: async () => {} }),
|
||||
close: async () => {},
|
||||
}),
|
||||
newPage: async () => ({ setDefaultTimeout: () => {}, close: async () => {} }),
|
||||
close: async () => {},
|
||||
}),
|
||||
launchPersistentContext: async (_userDataDir: string, _opts: any) => ({
|
||||
pages: () => [{ setDefaultTimeout: () => {}, close: async () => {} }],
|
||||
newPage: async () => ({ setDefaultTimeout: () => {}, close: async () => {} }),
|
||||
close: async () => {},
|
||||
}),
|
||||
};
|
||||
|
||||
(PlaywrightAutomationAdapter as any).testLauncher = mockLauncher;
|
||||
|
||||
DIContainer.resetInstance();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
const container = DIContainer.getInstance();
|
||||
await container.shutdown();
|
||||
DIContainer.resetInstance();
|
||||
(PlaywrightAutomationAdapter as any).testLauncher = originalTestLauncher;
|
||||
process.env = originalEnv;
|
||||
});
|
||||
|
||||
it('uses refreshed browser automation for connection and step execution after mode change', async () => {
|
||||
const container = DIContainer.getInstance();
|
||||
|
||||
const loader = container.getBrowserModeConfigLoader();
|
||||
expect(loader.getDevelopmentMode()).toBe('headed');
|
||||
|
||||
const preStart = container.getStartAutomationUseCase();
|
||||
const preEngine: any = container.getAutomationEngine();
|
||||
const preAutomation = container.getBrowserAutomation() as any;
|
||||
|
||||
expect(preAutomation).toBe(preEngine.browserAutomation);
|
||||
|
||||
loader.setDevelopmentMode('headless');
|
||||
container.refreshBrowserAutomation();
|
||||
|
||||
const postStart = container.getStartAutomationUseCase();
|
||||
const postEngine: any = container.getAutomationEngine();
|
||||
const postAutomation = container.getBrowserAutomation() as any;
|
||||
|
||||
expect(postAutomation).toBe(postEngine.browserAutomation);
|
||||
expect(postAutomation).not.toBe(preAutomation);
|
||||
expect(postStart).not.toBe(preStart);
|
||||
|
||||
const connectionResult = await container.initializeBrowserConnection();
|
||||
expect(connectionResult.success).toBe(true);
|
||||
|
||||
const config: HostedSessionConfig = {
|
||||
sessionName: 'Companion browser-mode refresh wiring',
|
||||
trackId: 'test-track',
|
||||
carIds: ['car-1'],
|
||||
};
|
||||
|
||||
const dto = await postStart.execute(config);
|
||||
|
||||
await postEngine.executeStep(StepId.create(1), config);
|
||||
|
||||
const sessionRepository: any = container.getSessionRepository();
|
||||
const session = await sessionRepository.findById(dto.sessionId);
|
||||
|
||||
expect(session).toBeDefined();
|
||||
|
||||
const state = session!.state.value as string;
|
||||
const errorMessage = session!.errorMessage as string | undefined;
|
||||
|
||||
if (errorMessage) {
|
||||
expect(errorMessage).not.toContain('Browser not connected');
|
||||
}
|
||||
|
||||
const automationFromConnection = container.getBrowserAutomation() as any;
|
||||
const automationFromEngine = (container.getAutomationEngine() as any).browserAutomation;
|
||||
|
||||
expect(automationFromConnection).toBe(automationFromEngine);
|
||||
expect(automationFromConnection).toBe(postAutomation);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,98 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { DIContainer } from '../../../..//apps/companion/main/di-container';
|
||||
import type { HostedSessionConfig } from '../../../..//packages/domain/entities/HostedSessionConfig';
|
||||
import { StepId } from '../../../..//packages/domain/value-objects/StepId';
|
||||
import { PlaywrightAutomationAdapter } from '../../../..//packages/infrastructure/adapters/automation';
|
||||
|
||||
describe('companion start automation - browser not connected at step 1', () => {
|
||||
const originalEnv = { ...process.env };
|
||||
let originalTestLauncher: unknown;
|
||||
|
||||
beforeEach(() => {
|
||||
process.env = { ...originalEnv, NODE_ENV: 'production' };
|
||||
|
||||
originalTestLauncher = (PlaywrightAutomationAdapter as any).testLauncher;
|
||||
|
||||
const mockLauncher = {
|
||||
launch: async (_opts: any) => ({
|
||||
newContext: async () => ({
|
||||
newPage: async () => ({ setDefaultTimeout: () => {}, close: async () => {} }),
|
||||
close: async () => {},
|
||||
}),
|
||||
newPage: async () => ({ setDefaultTimeout: () => {}, close: async () => {} }),
|
||||
close: async () => {},
|
||||
}),
|
||||
launchPersistentContext: async (_userDataDir: string, _opts: any) => ({
|
||||
pages: () => [{ setDefaultTimeout: () => {}, close: async () => {} }],
|
||||
newPage: async () => ({ setDefaultTimeout: () => {}, close: async () => {} }),
|
||||
close: async () => {},
|
||||
}),
|
||||
};
|
||||
|
||||
(PlaywrightAutomationAdapter as any).testLauncher = mockLauncher;
|
||||
|
||||
DIContainer.resetInstance();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
const container = DIContainer.getInstance();
|
||||
await container.shutdown();
|
||||
DIContainer.resetInstance();
|
||||
(PlaywrightAutomationAdapter as any).testLauncher = originalTestLauncher;
|
||||
process.env = originalEnv;
|
||||
});
|
||||
|
||||
it('marks the session as FAILED with Step 1 (LOGIN) browser-not-connected error', async () => {
|
||||
const container = DIContainer.getInstance();
|
||||
const startAutomationUseCase = container.getStartAutomationUseCase();
|
||||
const sessionRepository: any = container.getSessionRepository();
|
||||
const automationEngine = container.getAutomationEngine();
|
||||
|
||||
const connectionResult = await container.initializeBrowserConnection();
|
||||
expect(connectionResult.success).toBe(true);
|
||||
|
||||
const browserAutomation = container.getBrowserAutomation() as any;
|
||||
if (browserAutomation.disconnect) {
|
||||
await browserAutomation.disconnect();
|
||||
}
|
||||
|
||||
const config: HostedSessionConfig = {
|
||||
sessionName: 'Companion integration browser-not-connected',
|
||||
trackId: 'test-track',
|
||||
carIds: ['car-1'],
|
||||
};
|
||||
|
||||
const dto = await startAutomationUseCase.execute(config);
|
||||
|
||||
await automationEngine.executeStep(StepId.create(1), config);
|
||||
|
||||
const session = await waitForFailedSession(sessionRepository, dto.sessionId);
|
||||
expect(session).toBeDefined();
|
||||
expect(session.state.value).toBe('FAILED');
|
||||
const error = session.errorMessage as string | undefined;
|
||||
expect(error).toBeDefined();
|
||||
expect(error).toContain('Step 1 (LOGIN)');
|
||||
expect(error).toContain('Browser not connected');
|
||||
});
|
||||
});
|
||||
|
||||
async function waitForFailedSession(
|
||||
sessionRepository: { findById: (id: string) => Promise<any> },
|
||||
sessionId: string,
|
||||
timeoutMs = 5000,
|
||||
): Promise<any> {
|
||||
const start = Date.now();
|
||||
let last: any = null;
|
||||
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
last = await sessionRepository.findById(sessionId);
|
||||
if (last && last.state && last.state.value === 'FAILED') {
|
||||
return last;
|
||||
}
|
||||
if (Date.now() - start >= timeoutMs) {
|
||||
return last;
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||
import { DIContainer } from '../../../..//apps/companion/main/di-container';
|
||||
import type { HostedSessionConfig } from '../../../..//packages/domain/entities/HostedSessionConfig';
|
||||
import { PlaywrightAutomationAdapter } from '../../../..//packages/infrastructure/adapters/automation';
|
||||
|
||||
describe('companion start automation - browser connection failure before steps', () => {
|
||||
const originalEnv = { ...process.env };
|
||||
let originalTestLauncher: unknown;
|
||||
|
||||
beforeEach(() => {
|
||||
process.env = { ...originalEnv, NODE_ENV: 'production' };
|
||||
|
||||
originalTestLauncher = (PlaywrightAutomationAdapter as any).testLauncher;
|
||||
|
||||
const failingLauncher = {
|
||||
launch: async () => {
|
||||
throw new Error('Simulated browser launch failure');
|
||||
},
|
||||
launchPersistentContext: async () => {
|
||||
throw new Error('Simulated persistent context failure');
|
||||
},
|
||||
};
|
||||
|
||||
(PlaywrightAutomationAdapter as any).testLauncher = failingLauncher;
|
||||
|
||||
DIContainer.resetInstance();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
const container = DIContainer.getInstance();
|
||||
await container.shutdown();
|
||||
DIContainer.resetInstance();
|
||||
(PlaywrightAutomationAdapter as any).testLauncher = originalTestLauncher;
|
||||
process.env = originalEnv;
|
||||
});
|
||||
|
||||
it('fails browser connection and aborts before executing step 1', async () => {
|
||||
const container = DIContainer.getInstance();
|
||||
const startAutomationUseCase = container.getStartAutomationUseCase();
|
||||
const sessionRepository: any = container.getSessionRepository();
|
||||
const automationEngine = container.getAutomationEngine();
|
||||
|
||||
const connectionResult = await container.initializeBrowserConnection();
|
||||
expect(connectionResult.success).toBe(false);
|
||||
expect(connectionResult.error).toBeDefined();
|
||||
|
||||
const executeStepSpy = vi.spyOn(automationEngine, 'executeStep' as any);
|
||||
|
||||
const config: HostedSessionConfig = {
|
||||
sessionName: 'Companion integration connection failure',
|
||||
trackId: 'test-track',
|
||||
carIds: ['car-1'],
|
||||
};
|
||||
|
||||
let sessionId: string | null = null;
|
||||
|
||||
try {
|
||||
const dto = await startAutomationUseCase.execute(config);
|
||||
sessionId = dto.sessionId;
|
||||
} catch (error) {
|
||||
expect((error as Error).message).toBeDefined();
|
||||
}
|
||||
|
||||
expect(executeStepSpy).not.toHaveBeenCalled();
|
||||
|
||||
if (sessionId) {
|
||||
const session = await sessionRepository.findById(sessionId);
|
||||
if (session) {
|
||||
const message = session.errorMessage as string | undefined;
|
||||
if (message) {
|
||||
expect(message).not.toContain('Step 1 (LOGIN) failed: Browser not connected');
|
||||
expect(message.toLowerCase()).toContain('browser');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('treats successful adapter connect without a page as connection failure', async () => {
|
||||
const container = DIContainer.getInstance();
|
||||
const browserAutomation = container.getBrowserAutomation();
|
||||
|
||||
expect(browserAutomation).toBeInstanceOf(PlaywrightAutomationAdapter);
|
||||
|
||||
const originalConnect = (PlaywrightAutomationAdapter as any).prototype.connect;
|
||||
|
||||
(PlaywrightAutomationAdapter as any).prototype.connect = async function () {
|
||||
return { success: true };
|
||||
};
|
||||
|
||||
try {
|
||||
const connectionResult = await container.initializeBrowserConnection();
|
||||
expect(connectionResult.success).toBe(false);
|
||||
expect(connectionResult.error).toBeDefined();
|
||||
expect(String(connectionResult.error).toLowerCase()).toContain('browser');
|
||||
} finally {
|
||||
(PlaywrightAutomationAdapter as any).prototype.connect = originalConnect;
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { DIContainer } from '../../../..//apps/companion/main/di-container';
|
||||
import type { HostedSessionConfig } from '../../../..//packages/domain/entities/HostedSessionConfig';
|
||||
import { StepId } from '../../../..//packages/domain/value-objects/StepId';
|
||||
|
||||
describe('companion start automation - happy path', () => {
|
||||
const originalEnv = { ...process.env };
|
||||
|
||||
beforeEach(() => {
|
||||
process.env = { ...originalEnv, NODE_ENV: 'test' };
|
||||
DIContainer.resetInstance();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
const container = DIContainer.getInstance();
|
||||
await container.shutdown();
|
||||
DIContainer.resetInstance();
|
||||
process.env = originalEnv;
|
||||
});
|
||||
|
||||
it('creates a non-failed session and does not report browser-not-connected', async () => {
|
||||
const container = DIContainer.getInstance();
|
||||
const startAutomationUseCase = container.getStartAutomationUseCase();
|
||||
const sessionRepository = container.getSessionRepository();
|
||||
const automationEngine = container.getAutomationEngine();
|
||||
|
||||
const connectionResult = await container.initializeBrowserConnection();
|
||||
expect(connectionResult.success).toBe(true);
|
||||
|
||||
const config: HostedSessionConfig = {
|
||||
sessionName: 'Companion integration happy path',
|
||||
trackId: 'test-track',
|
||||
carIds: ['car-1'],
|
||||
};
|
||||
|
||||
const dto = await startAutomationUseCase.execute(config);
|
||||
|
||||
const sessionBefore = await sessionRepository.findById(dto.sessionId);
|
||||
expect(sessionBefore).toBeDefined();
|
||||
|
||||
await automationEngine.executeStep(StepId.create(1), config);
|
||||
|
||||
const session = await sessionRepository.findById(dto.sessionId);
|
||||
expect(session).toBeDefined();
|
||||
|
||||
const state = session!.state.value as string;
|
||||
expect(state).not.toBe('FAILED');
|
||||
|
||||
const errorMessage = session!.errorMessage as string | undefined;
|
||||
if (errorMessage) {
|
||||
expect(errorMessage).not.toContain('Browser not connected');
|
||||
}
|
||||
});
|
||||
});
|
||||
16
tests/smoke/companion-boot.smoke.test.ts
Normal file
16
tests/smoke/companion-boot.smoke.test.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Experimental Playwright+Electron companion boot smoke test (retired).
|
||||
*
|
||||
* This suite attempted to launch the Electron-based companion app via
|
||||
* Playwright's Electron driver, but it cannot run in this environment because
|
||||
* Electron embeds Node.js 16.17.1 while the installed Playwright version
|
||||
* requires Node.js 18 or higher.
|
||||
*
|
||||
* Companion behavior is instead covered by:
|
||||
* - Playwright-based automation E2Es and integrations against fixtures.
|
||||
* - Electron build/init/DI smoke tests.
|
||||
* - Domain and application unit/integration tests.
|
||||
*
|
||||
* This file is intentionally test-empty to avoid misleading Playwright+Electron
|
||||
* coverage while keeping the historical entrypoint discoverable.
|
||||
*/
|
||||
@@ -1,163 +1,9 @@
|
||||
import { describe, test, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { ElectronTestHarness } from './helpers/electron-test-harness';
|
||||
import { ConsoleMonitor } from './helpers/console-monitor';
|
||||
import { IPCVerifier } from './helpers/ipc-verifier';
|
||||
|
||||
/**
|
||||
* Electron App Smoke Test Suite
|
||||
*
|
||||
* Purpose: Catch ALL runtime errors before they reach production
|
||||
*
|
||||
* Critical Detections:
|
||||
* 1. Browser context violations (Node.js modules in renderer)
|
||||
* 2. Console errors during app lifecycle
|
||||
* 3. IPC channel communication failures
|
||||
* 4. React rendering failures
|
||||
*
|
||||
* RED Phase Expectation:
|
||||
* This test MUST FAIL due to current browser context errors:
|
||||
* - "Module 'path' has been externalized for browser compatibility"
|
||||
* - "ReferenceError: __dirname is not defined"
|
||||
*/
|
||||
|
||||
describe.skip('Electron App Smoke Tests', () => {
|
||||
let harness: ElectronTestHarness;
|
||||
let monitor: ConsoleMonitor;
|
||||
|
||||
beforeEach(async () => {
|
||||
harness = new ElectronTestHarness();
|
||||
monitor = new ConsoleMonitor();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await harness.close();
|
||||
});
|
||||
|
||||
test('should launch Electron app without errors', async () => {
|
||||
// Given: Fresh Electron app launch
|
||||
await harness.launch();
|
||||
const page = harness.getMainWindow();
|
||||
|
||||
// When: Monitor console during startup
|
||||
monitor.startMonitoring(page);
|
||||
|
||||
// Wait for app to fully initialize
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Then: No console errors should be present
|
||||
expect(monitor.hasErrors(), monitor.formatErrors()).toBe(false);
|
||||
});
|
||||
|
||||
test('should render main React UI without browser context errors', async () => {
|
||||
// Given: Electron app is launched
|
||||
await harness.launch();
|
||||
const page = harness.getMainWindow();
|
||||
monitor.startMonitoring(page);
|
||||
|
||||
// When: Waiting for React to render
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Then: No browser context errors (externalized modules, __dirname, require)
|
||||
expect(
|
||||
monitor.hasBrowserContextErrors(),
|
||||
'Browser context errors detected - Node.js modules imported in renderer process:\n' +
|
||||
monitor.formatErrors()
|
||||
).toBe(false);
|
||||
|
||||
// And: React root should be present
|
||||
const appRoot = await page.locator('#root').count();
|
||||
expect(appRoot).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('should have functional IPC channels', async () => {
|
||||
// Given: Electron app is running
|
||||
await harness.launch();
|
||||
const page = harness.getMainWindow();
|
||||
monitor.startMonitoring(page);
|
||||
|
||||
// When: Testing core IPC channels
|
||||
const app = harness.getApp();
|
||||
const verifier = new IPCVerifier(app);
|
||||
const results = await verifier.verifyAllChannels();
|
||||
|
||||
// Then: All IPC channels should respond
|
||||
const failedChannels = results.filter(r => !r.success);
|
||||
expect(
|
||||
failedChannels.length,
|
||||
`IPC channels failed:\n${IPCVerifier.formatResults(results)}`
|
||||
).toBe(0);
|
||||
|
||||
// And: No console errors during IPC operations
|
||||
expect(monitor.hasErrors(), monitor.formatErrors()).toBe(false);
|
||||
});
|
||||
|
||||
test('should handle console errors gracefully', async () => {
|
||||
// Given: Electron app is launched
|
||||
await harness.launch();
|
||||
const page = harness.getMainWindow();
|
||||
monitor.startMonitoring(page);
|
||||
|
||||
// When: App runs through full initialization
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Then: Capture and report any console errors
|
||||
const errors = monitor.getErrors();
|
||||
const warnings = monitor.getWarnings();
|
||||
|
||||
// This assertion WILL FAIL in RED phase
|
||||
expect(
|
||||
errors.length,
|
||||
`Console errors detected:\n${monitor.formatErrors()}`
|
||||
).toBe(0);
|
||||
|
||||
// Log warnings for visibility (non-blocking)
|
||||
if (warnings.length > 0) {
|
||||
console.log('⚠️ Warnings detected:', warnings);
|
||||
}
|
||||
});
|
||||
|
||||
test('should not have uncaught exceptions during startup', async () => {
|
||||
// Given: Fresh Electron launch
|
||||
await harness.launch();
|
||||
const page = harness.getMainWindow();
|
||||
|
||||
// When: Monitor for uncaught exceptions
|
||||
const uncaughtExceptions: Error[] = [];
|
||||
page.on('pageerror', (error) => {
|
||||
uncaughtExceptions.push(error);
|
||||
});
|
||||
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.waitForTimeout(1500);
|
||||
|
||||
// Then: No uncaught exceptions
|
||||
expect(
|
||||
uncaughtExceptions.length,
|
||||
`Uncaught exceptions:\n${uncaughtExceptions.map(e => e.message).join('\n')}`
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
test('should complete full app lifecycle without crashes', async () => {
|
||||
// Given: Electron app launches successfully
|
||||
await harness.launch();
|
||||
const page = harness.getMainWindow();
|
||||
monitor.startMonitoring(page);
|
||||
|
||||
// When: Running through complete app lifecycle
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Simulate user interaction
|
||||
const appVisible = await page.isVisible('#root');
|
||||
expect(appVisible).toBe(true);
|
||||
|
||||
// Then: No errors throughout lifecycle
|
||||
expect(monitor.hasErrors(), monitor.formatErrors()).toBe(false);
|
||||
|
||||
// And: App can close cleanly
|
||||
await harness.close();
|
||||
|
||||
// Verify clean shutdown (no hanging promises)
|
||||
expect(monitor.hasErrors()).toBe(false);
|
||||
});
|
||||
});
|
||||
* Legacy Electron app smoke suite (superseded).
|
||||
*
|
||||
* Canonical boot coverage now lives in
|
||||
* [companion-boot.smoke.test.ts](tests/smoke/companion-boot.smoke.test.ts).
|
||||
*
|
||||
* This file is intentionally test-empty to avoid duplicate or misleading
|
||||
* coverage while keeping the historical entrypoint discoverable.
|
||||
*/
|
||||
17
tests/smoke/helpers/companion-boot-harness.ts
Normal file
17
tests/smoke/helpers/companion-boot-harness.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Experimental Playwright+Electron companion boot harness (retired).
|
||||
*
|
||||
* This harness attempted to launch the Electron-based companion app via
|
||||
* Playwright's Electron driver, but it cannot run in this environment because
|
||||
* Electron embeds Node.js 16.17.1 while the installed Playwright version
|
||||
* requires Node.js 18 or higher.
|
||||
*
|
||||
* Companion behavior is instead covered by:
|
||||
* - Playwright-based automation E2Es and integrations against fixtures.
|
||||
* - Electron build/init/DI smoke tests.
|
||||
* - Domain and application unit/integration tests.
|
||||
*
|
||||
* This file is intentionally implementation-empty to avoid misleading
|
||||
* Playwright+Electron coverage while keeping the historical entrypoint
|
||||
* discoverable.
|
||||
*/
|
||||
Reference in New Issue
Block a user