d3ro-voice/apps/desktop/test-results/launch_readiness-Launch-Re-e1129-AdBanner-and-Support-button/error-context.md
Yun Chan 708e20f747
Some checks failed
CI Pipeline / Code Quality & Typecheck (push) Waiting to run
CI Pipeline / Test Suite (macos-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (ubuntu-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (windows-latest) (push) Blocked by required conditions
CI Pipeline / Build Validation (admin) (push) Blocked by required conditions
CI Pipeline / Build Validation (desktop) (push) Blocked by required conditions
Deploy Landing Page / deploy (push) Blocked by required conditions
Deploy Landing Page / build (push) Waiting to run
Release & Packaging Pipeline / Build & Publish Admin Docker Image (push) Failing after 8s
Release & Code Signing CA Pipeline / build-and-sign-windows (push) Failing after 1m51s
Build macOS / Build & Package (macOS) (push) Failing after 4s
Build macOS / Build & Package (macOS)-1 (push) Failing after 5s
Release & Code Signing CA Pipeline / build-and-sign-macos (push) Failing after 3s
Release & Packaging Pipeline / Package macOS Desktop App (push) Failing after 4s
Release & Packaging Pipeline / Package Windows Desktop App (push) Failing after 2m28s
Release & Packaging Pipeline / Publish Official GitHub Release (push) Has been skipped
feat: complete release preparation, 10+ ad mediation, CI/CD, and docker deployment
2026-08-20 11:12:05 +09:00

6.7 KiB

Instructions

  • Following Playwright test failed.
  • Explain why, be concise, respect Playwright best practices.
  • Provide a snippet of code with the fix, if possible.

Test info

  • Name: launch_readiness.spec.ts >> Launch Readiness E2E & Visual Verification >> 01. Should render desktop app with Free Tier AdBanner and Support button
  • Location: tests\e2e\launch_readiness.spec.ts:72:7

Error details

TimeoutError: electronApplication.firstWindow: Timeout 30000ms exceeded while waiting for event "window"
"afterAll" hook timeout of 60000ms exceeded.

Test source

  1   | import * as fs from 'fs';
  2   | import * as path from 'path';
  3   | import { test, expect, _electron as electron } from '@playwright/test';
  4   | 
  5   | const SCREENSHOT_DIR = 'C:/Users/encep/.gemini/antigravity-cli/brain/3ab7ae82-5634-41d5-93a7-3c12c22503e2/screenshots';
  6   | 
  7   | test.describe('Launch Readiness E2E & Visual Verification', () => {
  8   |   test.describe.configure({ mode: 'serial' });
  9   |   let electronApp: any;
  10  |   let window: any;
  11  | 
  12  |   test.beforeAll(async () => {
  13  |     if (!fs.existsSync(SCREENSHOT_DIR)) {
  14  |       fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
  15  |     }
  16  | 
  17  |     electronApp = await electron.launch({
  18  |       args: [
  19  |         'out/main/index.js',
  20  |         '--disable-gpu',
  21  |         '--no-sandbox',
  22  |         '--user-data-dir=C:/Users/encep/AppData/Local/Temp/playwright-d3ro-launch-test-' + Date.now(),
  23  |       ],
  24  |       env: {
  25  |         ...process.env,
  26  |         NODE_ENV: 'test',
  27  |       },
  28  |     });
  29  | 
  30  |     // Poll for main window (excluding popup windows)
  31  |     for (let i = 0; i < 40; i++) {
  32  |       for (const w of electronApp.windows()) {
  33  |         try {
  34  |           const url = w.url();
  35  |           if (url && url.includes('index.html') && !url.includes('popups/')) {
  36  |             window = w;
  37  |             break;
  38  |           }
  39  |         } catch {
  40  |           // ignore
  41  |         }
  42  |       }
  43  |       if (window) break;
  44  |       await new Promise((r) => setTimeout(r, 500));
  45  |     }
  46  | 
  47  |     if (!window) {
  48  |       window = electronApp.windows()[0] || await electronApp.firstWindow();
  49  |     }
  50  |     await window.waitForLoadState('domcontentloaded');
  51  | 
  52  |     // Bypass onboarding via IPC config set
  53  |     await window.evaluate(async () => {
  54  |       if (window.electronAPI && window.electronAPI.config) {
  55  |         await window.electronAPI.config.set({ key: 'onboardingCompleted', value: true });
  56  |         await window.electronAPI.config.set({ key: 'appUsageMode', value: 'online' });
  57  |       }
  58  |     });
  59  | 
  60  |     await window.waitForTimeout(500);
  61  |     await window.reload();
  62  |     await window.waitForLoadState('domcontentloaded');
  63  |     await window.waitForTimeout(1500);
  64  |   });
  65  | 
> 66  |   test.afterAll(async () => {
      |        ^ "afterAll" hook timeout of 60000ms exceeded.
  67  |     if (electronApp) {
  68  |       await electronApp.close();
  69  |     }
  70  |   });
  71  | 
  72  |   test('01. Should render desktop app with Free Tier AdBanner and Support button', async () => {
  73  |     // Check if sidebar has Customer Support button
  74  |     const supportBtn = window.locator('text=/^(Customer Support|고객지원)$/').first();
  75  |     await expect(supportBtn).toBeVisible({ timeout: 10000 });
  76  | 
  77  |     // Check if Free Tier AdBanner is visible
  78  |     const adBanner = window.locator('text=/Cursor AI/').first();
  79  |     await expect(adBanner).toBeVisible({ timeout: 10000 });
  80  | 
  81  |     // Take screenshot of main window with AdBanner and sidebar
  82  |     await window.screenshot({ path: path.join(SCREENSHOT_DIR, '01_desktop_main_with_adbanner.png') });
  83  |   });
  84  | 
  85  |   test('02. Should open SupportModal and interact with AI Customer Assistant', async () => {
  86  |     // Click Customer Support in sidebar
  87  |     await window.locator('text=/^(Customer Support|고객지원)$/').first().click();
  88  |     await window.waitForTimeout(500);
  89  | 
  90  |     // Verify modal header is visible
  91  |     await expect(window.locator('text=/D3RO Voice Customer Assistance/').first()).toBeVisible();
  92  | 
  93  |     // Click quick prompt "🎤 마이크 인식 오류"
  94  |     const micPrompt = window.locator('text=/마이크 인식/').first();
  95  |     if (await micPrompt.isVisible()) {
  96  |       await micPrompt.click();
  97  |       await window.waitForTimeout(800);
  98  |     }
  99  | 
  100 |     // Capture screenshot of SupportModal with AI chat
  101 |     await window.screenshot({ path: path.join(SCREENSHOT_DIR, '02_support_modal_ai_chat.png') });
  102 | 
  103 |     // Switch to 7-Day Refund Tab (tab 3)
  104 |     const refundTab = window.locator('text=/7일 자동 환불/').first();
  105 |     await refundTab.click();
  106 |     await window.waitForTimeout(500);
  107 | 
  108 |     // Click "환불 자격 자동 조회하기"
  109 |     const checkRefundBtn = window.locator('button:has-text("환불 자격 자동 조회하기")').first();
  110 |     if (await checkRefundBtn.isVisible()) {
  111 |       await checkRefundBtn.click();
  112 |       await window.waitForTimeout(1000);
  113 |     }
  114 | 
  115 |     // Capture screenshot of refund eligibility result
  116 |     await window.screenshot({ path: path.join(SCREENSHOT_DIR, '03_support_modal_refund_check.png') });
  117 | 
  118 |     // Close Support Modal
  119 |     await window.keyboard.press('Escape');
  120 |     await window.waitForTimeout(500);
  121 |   });
  122 | 
  123 |   test('03. Should open CheckoutModal and display Toss Payments / Stripe options', async () => {
  124 |     // Trigger checkout via "Remove ads with Pro" link in AdBanner
  125 |     const removeAdsLink = window.locator('text=/Remove ads with Pro/').first();
  126 |     if (await removeAdsLink.isVisible()) {
  127 |       await removeAdsLink.click();
  128 |       await window.waitForTimeout(600);
  129 | 
  130 |       // Verify Checkout Modal is visible
  131 |       await expect(window.locator('text=/D3RO Voice Secure Checkout/').first()).toBeVisible();
  132 | 
  133 |       // Capture screenshot of CheckoutModal
  134 |       await window.screenshot({ path: path.join(SCREENSHOT_DIR, '04_checkout_modal_toss_stripe.png') });
  135 | 
  136 |       // Close modal
  137 |       await window.keyboard.press('Escape');
  138 |       await window.waitForTimeout(400);
  139 |     }
  140 |   });
  141 | });
  142 |