Files
gridpilot.gg/tests/smoke/electron-app.smoke.test.ts
2025-11-27 13:26:17 +01:00

163 lines
5.1 KiB
TypeScript

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('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);
});
});