import { expect } from "@playwright/test"; import { Timeout, testWithConfig } from "./helpers/test_helper"; import * as fs from "node:fs"; import * as path from "node:path"; testWithConfig({ preLaunchHook: async ({ userDataDir }) => { // Set up a force-close scenario by creating settings with isRunning: true // and lastKnownPerformance data const settingsPath = path.join(userDataDir, "user-settings.json"); const settings = { hasRunBefore: true, isRunning: true, // Simulate force-close enableAutoUpdate: false, releaseChannel: "stable", lastKnownPerformance: { timestamp: Date.now() - 5000, // 5 seconds ago memoryUsageMB: 256, cpuUsagePercent: 45.5, systemMemoryUsageMB: 8192, systemMemoryTotalMB: 16384, systemMemoryPercent: 50.0, systemCpuPercent: 35.2, }, }; fs.mkdirSync(userDataDir, { recursive: true }); fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2)); }, })( "force-close detection shows dialog with performance data", async ({ po }) => { // Wait for the home page to be visible first await expect(po.getHomeChatInputContainer()).toBeVisible({ timeout: Timeout.LONG, }); // Check if the force-close dialog is visible by looking for the heading await expect( po.page.getByRole("heading", { name: "Force Close Detected" }), ).toBeVisible({ timeout: Timeout.MEDIUM }); // Verify the warning message await expect( po.page.getByText( "The app was not closed properly the last time it was running", ), ).toBeVisible(); // Verify performance data is displayed await expect(po.page.getByText("Last Known State:")).toBeVisible(); // Check Process Metrics section await expect(po.page.getByText("Process Metrics")).toBeVisible(); await expect(po.page.getByText("256 MB")).toBeVisible(); await expect(po.page.getByText("45.5%")).toBeVisible(); // Check System Metrics section await expect(po.page.getByText("System Metrics")).toBeVisible(); await expect(po.page.getByText("8192 / 16384 MB")).toBeVisible(); await expect(po.page.getByText("35.2%")).toBeVisible(); // Close the dialog await po.page.getByRole("button", { name: "OK" }).click(); // Verify dialog is closed by checking the heading is no longer visible await expect( po.page.getByRole("heading", { name: "Force Close Detected" }), ).not.toBeVisible(); }, ); testWithConfig({ preLaunchHook: async ({ userDataDir }) => { // Set up scenario without force-close (proper shutdown) const settingsPath = path.join(userDataDir, "user-settings.json"); const settings = { hasRunBefore: true, isRunning: false, // Proper shutdown - no force-close enableAutoUpdate: false, releaseChannel: "stable", lastKnownPerformance: { timestamp: Date.now() - 5000, memoryUsageMB: 256, cpuUsagePercent: 45.5, systemMemoryUsageMB: 8192, systemMemoryTotalMB: 16384, systemMemoryPercent: 50.0, systemCpuPercent: 35.2, }, }; fs.mkdirSync(userDataDir, { recursive: true }); fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2)); }, })("no force-close dialog when app was properly shut down", async ({ po }) => { // Verify the home page loaded normally await expect(po.getHomeChatInputContainer()).toBeVisible({ timeout: Timeout.LONG, }); // Verify that the force-close dialog is NOT shown await expect( po.page.getByRole("heading", { name: "Force Close Detected" }), ).not.toBeVisible(); }); testWithConfig({})( "performance information is being captured during normal operation", async ({ po, electronApp }) => { // Wait for the app to load await expect(po.getHomeChatInputContainer()).toBeVisible({ timeout: Timeout.LONG, }); // Get the user data directory const userDataDir = (electronApp as any).$dyadUserDataDir; const settingsPath = path.join(userDataDir, "user-settings.json"); // Wait a bit to allow performance monitoring to capture at least one data point // Performance monitoring runs every 30 seconds, but we'll wait 35 seconds to be safe await po.page.waitForTimeout(35000); // Read the settings file const settingsContent = fs.readFileSync(settingsPath, "utf-8"); const settings = JSON.parse(settingsContent); // Verify that lastKnownPerformance exists and has all required fields expect(settings.lastKnownPerformance).toBeDefined(); expect(settings.lastKnownPerformance.timestamp).toBeGreaterThan(0); expect(settings.lastKnownPerformance.memoryUsageMB).toBeGreaterThan(0); expect( settings.lastKnownPerformance.cpuUsagePercent, ).toBeGreaterThanOrEqual(0); expect(settings.lastKnownPerformance.systemMemoryUsageMB).toBeGreaterThan( 0, ); expect(settings.lastKnownPerformance.systemMemoryTotalMB).toBeGreaterThan( 0, ); expect( settings.lastKnownPerformance.systemCpuPercent, ).toBeGreaterThanOrEqual(0); // Verify the timestamp is recent (within the last minute) const now = Date.now(); const timeDiff = now - settings.lastKnownPerformance.timestamp; expect(timeDiff).toBeLessThan(60000); // Less than 1 minute old }, );