From d9766cb5ef1d9bdfb06a76135154fd90644bde6b Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Mon, 29 Jun 2026 17:03:32 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20E2E=20=EB=82=B4=EB=B9=84=EA=B2=8C?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=8B=9C=20Blazor=20Dynamic=20Spinner=20?= =?UTF-8?q?=EA=B0=90=EC=A7=80=20=EB=B0=8F=20MudDialog=20=EA=B3=A0=EC=9C=A0?= =?UTF-8?q?=20=EC=8B=9D=EB=B3=84=EC=9E=90=20=EA=B8=B0=EB=B0=98=20native=20?= =?UTF-8?q?click=20=EC=97=B0=EB=8F=99=EC=9D=84=20=EC=A0=81=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=97=AC=20=EB=B9=84=EB=8F=99=EA=B8=B0=20=ED=81=B4?= =?UTF-8?q?=EB=A6=AD=20=EC=9C=A0=EC=8B=A4=20=EC=9B=90=EC=B2=9C=20=EC=B0=A8?= =?UTF-8?q?=EB=8B=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/e2e/admin-crm-pages.spec.ts | 40 +++++++++++++++++++++++-------- tests/e2e/helpers/admin-auth.ts | 13 ++++++++++ 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/tests/e2e/admin-crm-pages.spec.ts b/tests/e2e/admin-crm-pages.spec.ts index 97b5311..b1e52b9 100644 --- a/tests/e2e/admin-crm-pages.spec.ts +++ b/tests/e2e/admin-crm-pages.spec.ts @@ -6,6 +6,8 @@ const password = process.env.E2E_ADMIN_PASSWORD; const baseUrl = (process.env.E2E_BASE_URL ?? 'http://178.104.200.7/taxbaik').replace(/\/$/, ''); test.describe('admin CRM pages', () => { + test.describe.configure({ mode: 'serial' }); + test.beforeEach(async ({ page }) => { test.skip(!password, 'E2E_ADMIN_PASSWORD is required.'); await loginThroughAdminUi(page, baseUrl, username, password); @@ -124,11 +126,19 @@ test.describe('admin CRM pages', () => { test('TaxProfiles form displays valid business type combo choices', async ({ page }) => { await navigateInBlazor(page, `${baseUrl}/admin/tax-profiles`); - const addButton = page.getByRole('button', { name: /새 프로필 추가/ }); - await addButton.click(); + await expect(page.locator('.admin-grid, .mud-alert')).toBeVisible({ timeout: 15000 }); - // Label을 매개로 인풋 영역 클릭 - await page.getByLabel('사업 유형').first().click(); + const addButton = page.getByRole('button', { name: /새 프로필 추가/ }); + + // JS 네이티브 클릭으로 강제 격발하여 오프셋 씹힘 소멸 + await addButton.evaluate(el => (el as HTMLButtonElement).click()); + + // 대화상자(MudDialog) 자체의 노출 대기 + await expect(page.locator('.mud-dialog')).toBeVisible({ timeout: 5000 }); + + // mud-select 컨테이너 자체 클릭 (이벤트 핸들러 직접 격발) + const select = page.locator('.mud-select').filter({ hasText: '사업 유형' }).first(); + await select.evaluate(el => (el as HTMLDivElement).click()); // 활성화된 팝오버(.mud-popover-open) 내에서 텍스트 노출 검증 const popover = page.locator('.mud-popover-open'); @@ -139,10 +149,15 @@ test.describe('admin CRM pages', () => { test('TaxFilingSchedules form displays filing type combo choices', async ({ page }) => { await navigateInBlazor(page, `${baseUrl}/admin/tax-filing-schedules`); - const addButton = page.getByRole('button', { name: /새 일정 추가/ }); - await addButton.click(); + await expect(page.locator('.admin-grid, .mud-alert')).toBeVisible({ timeout: 15000 }); - await page.getByLabel('신고 유형').first().click(); + const addButton = page.getByRole('button', { name: /새 일정 추가/ }); + await addButton.evaluate(el => (el as HTMLButtonElement).click()); + + await expect(page.locator('.mud-dialog')).toBeVisible({ timeout: 5000 }); + + const select = page.locator('.mud-select').filter({ hasText: '신고 유형' }).first(); + await select.evaluate(el => (el as HTMLDivElement).click()); const popover = page.locator('.mud-popover-open'); await expect(popover.getByText('종합소득세')).toBeVisible({ timeout: 5000 }); @@ -151,10 +166,15 @@ test.describe('admin CRM pages', () => { test('Contracts form displays service type combo choices', async ({ page }) => { await navigateInBlazor(page, `${baseUrl}/admin/contracts`); - const addButton = page.getByRole('button', { name: /새 계약 추가/ }); - await addButton.click(); + await expect(page.locator('.admin-grid, .mud-alert')).toBeVisible({ timeout: 15000 }); - await page.getByLabel('서비스 유형').first().click(); + const addButton = page.getByRole('button', { name: /새 계약 추가/ }); + await addButton.evaluate(el => (el as HTMLButtonElement).click()); + + await expect(page.locator('.mud-dialog')).toBeVisible({ timeout: 5000 }); + + const select = page.locator('.mud-select').filter({ hasText: '서비스 유형' }).first(); + await select.evaluate(el => (el as HTMLDivElement).click()); const popover = page.locator('.mud-popover-open'); await expect(popover.getByText('개인 기장대리')).toBeVisible({ timeout: 5000 }); diff --git a/tests/e2e/helpers/admin-auth.ts b/tests/e2e/helpers/admin-auth.ts index 385c4ec..7dd29b4 100644 --- a/tests/e2e/helpers/admin-auth.ts +++ b/tests/e2e/helpers/admin-auth.ts @@ -58,6 +58,19 @@ export async function navigateInBlazor(page: Page, targetUrl: string) { window.location.href = url; }, targetUrl); + + // Wait until Blazor Server completes connection and hides the loading spinner overlay + await page.locator('#blazor-loading').waitFor({ state: 'hidden', timeout: 15000 }).catch(() => {}); + + // Also wait for MudBlazor's dynamic loading spinners to disappear (ensuring the grid is interactive) + const spinner = page.locator('.mud-progress-circular, .mud-progress-linear-bar'); + try { + if (await spinner.count() > 0) { + await spinner.first().waitFor({ state: 'hidden', timeout: 10000 }); + } + } catch (e) { + // Suppress timeout if the spinner was already gone or never showed up + } } export async function findInquiryByName(