사이트 메뉴 /bag/* 10개 페이지 구현 + E2E 테스트 timeout 보강

- Bag 컨트롤러 신규 (기본정보/발주입고/불출/재고/판매/판매현황/수불/통계/창/도움말)
- 사이트 공통 레이아웃 bag/layout/main.php 추출
- /bag/* 라우트 10개 등록 (Routes.php)
- bag-site.spec.js E2E 테스트 11개 추가
- Playwright timeout 30s→60s, waitForURL 15s→30s
- P4 지자체관리자 접근 테스트 3개로 분리

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
javamon1174
2026-03-26 14:30:45 +09:00
parent 466f6fe085
commit a0103eb95d
27 changed files with 951 additions and 18 deletions

View File

@@ -63,7 +63,7 @@ test.describe('관리자 패널 — Super Admin', () => {
await page.click('button[type="submit"]');
// 선택 후 관리자 대시보드로 이동
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 15000 });
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 30000 });
await page.goto('/admin');
await expect(page).not.toHaveURL(/\/select-local-government/);
});
@@ -74,7 +74,7 @@ test.describe('관리자 패널 — Super Admin', () => {
const radio = page.locator('input[name="lg_idx"]').first();
await radio.check();
await page.click('button[type="submit"]');
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 15000 });
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 30000 });
await page.goto('/admin/local-governments');
await expect(page).toHaveURL(/\/admin\/local-governments/);

View File

@@ -49,7 +49,7 @@ test.describe('인증 시스템', () => {
test('로그아웃', async ({ page }) => {
await login(page, 'local');
await page.goto('/logout');
await page.waitForURL(/\/login/, { timeout: 10000 });
await page.waitForURL(/\/login/, { timeout: 30000 });
await expect(page).toHaveURL(/\/login/);
// 로그아웃 후 관리자 접근 불가 확인
await page.goto('/admin');

View File

@@ -6,7 +6,7 @@ async function loginAsAdmin(page) {
await login(page, 'admin');
await page.locator('input[name="lg_idx"]').first().check();
await page.click('button[type="submit"]');
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 15000 });
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 30000 });
}
test.describe('P2-03/04: 봉투 단가 관리', () => {

80
e2e/bag-site.spec.js Normal file
View File

@@ -0,0 +1,80 @@
// @ts-check
const { test, expect } = require('@playwright/test');
const { login } = require('./helpers/auth');
test.describe('사이트 메뉴 (/bag/*) 페이지 접근', () => {
test.beforeEach(async ({ page }) => {
await login(page, 'local');
});
test('기본정보관리', async ({ page }) => {
await page.goto('/bag/basic-info');
await expect(page).toHaveURL(/\/bag\/basic-info/);
await expect(page.locator('text=기본코드 종류')).toBeVisible();
});
test('발주 입고 관리', async ({ page }) => {
await page.goto('/bag/purchase-inbound');
await expect(page).toHaveURL(/\/bag\/purchase-inbound/);
await expect(page.locator('text=발주 현황')).toBeVisible();
});
test('불출 관리', async ({ page }) => {
await page.goto('/bag/issue');
await expect(page).toHaveURL(/\/bag\/issue/);
await expect(page.locator('th:has-text("불출일")')).toBeVisible();
});
test('재고 관리', async ({ page }) => {
await page.goto('/bag/inventory');
await expect(page).toHaveURL(/\/bag\/inventory/);
await expect(page.locator('th:has-text("현재재고")')).toBeVisible();
});
test('판매 관리', async ({ page }) => {
await page.goto('/bag/sales');
await expect(page).toHaveURL(/\/bag\/sales/);
await expect(page.locator('text=주문 접수')).toBeVisible();
});
test('판매 현황', async ({ page }) => {
await page.goto('/bag/sales-stats');
await expect(page).toHaveURL(/\/bag\/sales-stats/);
await expect(page.locator('th:has-text("봉투코드")')).toBeVisible();
});
test('봉투 수불 관리', async ({ page }) => {
await page.goto('/bag/flow');
await expect(page).toHaveURL(/\/bag\/flow/);
await expect(page.locator('th:has-text("현재재고")')).toBeVisible();
});
test('통계 분석 관리', async ({ page }) => {
await page.goto('/bag/analytics');
await expect(page).toHaveURL(/\/bag\/analytics/);
await expect(page.locator('main >> text=Phase 6에서 구현 예정')).toBeVisible();
});
test('창', async ({ page }) => {
await page.goto('/bag/window');
await expect(page).toHaveURL(/\/bag\/window/);
await expect(page.locator('text=창 관리')).toBeVisible();
});
test('도움말', async ({ page }) => {
await page.goto('/bag/help');
await expect(page).toHaveURL(/\/bag\/help/);
await expect(page.locator('text=시스템 개요')).toBeVisible();
});
});
test.describe('홈페이지 네비게이션 메뉴 링크', () => {
test('메뉴 클릭으로 각 페이지 이동', async ({ page }) => {
await login(page, 'local');
await page.goto('/');
// 발주 입고 관리 메뉴 클릭
await page.click('a:has-text("발주 입고 관리")');
await expect(page).toHaveURL(/\/bag\/purchase-inbound/);
});
});

View File

@@ -8,7 +8,7 @@ async function loginAsAdmin(page) {
const radio = page.locator('input[name="lg_idx"]').first();
await radio.check();
await page.click('button[type="submit"]');
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 15000 });
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 30000 });
}
test.describe('P2-01: 기본코드 종류 관리', () => {

View File

@@ -15,10 +15,10 @@ async function run() {
await page.fill('input[name="login_id"]', 'tester_admin');
await page.fill('input[name="password"]', 'test1234!');
await page.click('button[type="submit"]');
await page.waitForURL(url => !url.pathname.includes('/login'), { timeout: 15000 });
await page.waitForURL(url => !url.pathname.includes('/login'), { timeout: 30000 });
await page.locator('input[name="lg_idx"]').first().check();
await page.click('button[type="submit"]');
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 15000 });
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 30000 });
const pages = [
// Phase 2

View File

@@ -20,7 +20,7 @@ async function login(page, account) {
await page.fill('input[name="login_id"]', account.id);
await page.fill('input[name="password"]', account.password);
await page.click('button[type="submit"]');
await page.waitForURL(url => !url.pathname.includes('/login'), { timeout: 15000 });
await page.waitForURL(url => !url.pathname.includes('/login'), { timeout: 30000 });
}
async function screenshot(page, name, url) {
@@ -52,7 +52,7 @@ async function run() {
const radio = page.locator('input[name="lg_idx"]').first();
await radio.check();
await page.click('button[type="submit"]');
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 15000 });
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 30000 });
console.log('\n=== 관리자 패널 (Super Admin) ===');
await screenshot(page, '05_admin_dashboard', `${BASE_URL}/admin`);

View File

@@ -6,7 +6,7 @@ async function loginAsAdmin(page) {
await login(page, 'admin');
await page.locator('input[name="lg_idx"]').first().check();
await page.click('button[type="submit"]');
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 15000 });
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 30000 });
}
test.describe('P2-05/06: 포장 단위 관리', () => {

View File

@@ -6,7 +6,7 @@ async function loginAsAdmin(page) {
await login(page, 'admin');
await page.locator('input[name="lg_idx"]').first().check();
await page.click('button[type="submit"]');
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 15000 });
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 30000 });
}
async function loginAsLocal(page) {

View File

@@ -6,7 +6,7 @@ async function loginAsAdmin(page) {
await login(page, 'admin');
await page.locator('input[name="lg_idx"]').first().check();
await page.click('button[type="submit"]');
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 15000 });
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 30000 });
}
test.describe('P2-19: 지자체 수정/삭제', () => {
@@ -42,7 +42,7 @@ test.describe('P2-21: 로그인 실패 lock', () => {
await page.fill('input[name="login_id"]', 'tester_user');
await page.fill('input[name="password"]', 'wrong_password');
await page.click('button[type="submit"]');
await page.waitForURL(/\/login/, { timeout: 15000 });
await page.waitForURL(/\/login/, { timeout: 30000 });
await page.waitForTimeout(500);
}
// 3회 이후 실패 카운트 표시 확인

View File

@@ -6,7 +6,7 @@ async function loginAsAdmin(page) {
await login(page, 'admin');
await page.locator('input[name="lg_idx"]').first().check();
await page.click('button[type="submit"]');
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 15000 });
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 30000 });
}
test.describe('P3: 발주 관리', () => {

View File

@@ -6,7 +6,7 @@ async function loginAsAdmin(page) {
await login(page, 'admin');
await page.locator('input[name="lg_idx"]').first().check();
await page.click('button[type="submit"]');
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 15000 });
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 30000 });
}
test.describe('P4: 주문 접수 관리', () => {
@@ -49,12 +49,18 @@ test.describe('P4: 무료용 불출 관리', () => {
});
test.describe('P4: 지자체관리자 접근', () => {
test('주문/판매/불출 접근 가능', async ({ page }) => {
test.beforeEach(async ({ page }) => {
await login(page, 'local');
});
test('주문 접수 접근 가능', async ({ page }) => {
await page.goto('/admin/shop-orders');
await expect(page).toHaveURL(/\/admin\/shop-orders/);
});
test('판매 접근 가능', async ({ page }) => {
await page.goto('/admin/bag-sales');
await expect(page).toHaveURL(/\/admin\/bag-sales/);
});
test('불출 접근 가능', async ({ page }) => {
await page.goto('/admin/bag-issues');
await expect(page).toHaveURL(/\/admin\/bag-issues/);
});

View File

@@ -6,7 +6,7 @@ async function loginAsAdmin(page) {
await login(page, 'admin');
await page.locator('input[name="lg_idx"]').first().check();
await page.click('button[type="submit"]');
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 15000 });
await page.waitForURL(url => !url.pathname.includes('select-local-government'), { timeout: 30000 });
}
test.describe('P5: 판매 대장', () => {