// @ts-check /** * 메뉴(mm_link)에 넣은 주요 경로 스모크: 5xx·DB 예외·Whoops 없이 로드되는지 확인. * 실행: 앱이 playwright.config.js 의 baseURL(기본 8045)에서 떠 있어야 함. */ const { test, expect } = require('@playwright/test'); const { login } = require('./helpers/auth'); 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: 30000 }); } /** * @param {import('@playwright/test').Page} page * @param {string} pathWithLeadingSlash '/bag/prices' 형태 */ async function assertNoServerError(page, pathWithLeadingSlash) { const response = await page.goto(pathWithLeadingSlash, { waitUntil: 'domcontentloaded' }); const status = response?.status() ?? 0; expect.soft(status, `${pathWithLeadingSlash} HTTP`).toBeLessThan(500); const html = await page.content(); expect.soft(html, `${pathWithLeadingSlash}`).not.toContain('DatabaseException'); expect.soft(html, `${pathWithLeadingSlash}`).not.toContain('mysqli_sql_exception'); expect.soft(html, `${pathWithLeadingSlash}`).not.toMatch(/Whoops!/i); } const BAG_PATHS = [ '/bag/basic-info', '/bag/prices', '/bag/packaging-units', '/bag/code-kinds', '/bag/code-details/1', '/bag/purchase-inbound', '/bag/issue', '/bag/issue/create', '/bag/inventory', '/bag/inventory/adjust', '/bag/order/create', '/bag/receiving/create', '/bag/sales', '/bag/sales-stats', '/bag/sale/create', '/bag/shop-order/create', '/bag/flow', '/bag/analytics', '/bag/window', '/bag/help', '/bag/waste-suibal-enterprise', '/dashboard', // 메인 사이트 메뉴용 업무 URL (관리자 권한, 사이트 레이아웃) '/bag/managers', '/bag/managers/create', '/bag/sales-agencies', '/bag/sales-agencies/create', '/bag/companies', '/bag/companies/create', '/bag/free-recipients', '/bag/free-recipients/create', '/bag/designated-shops', '/bag/designated-shops/browse', '/bag/designated-shops/status', '/bag/designated-shops/status/export?year=2026&ds_gugun_code=&granularity=gugun', '/bag/designated-shops/district-new-cancel', '/bag/designated-shops/district-new-cancel/export?year=2026', '/bag/designated-shops/barcode', '/bag/bag-prices', '/bag/bag-prices/create', '/bag/packaging-units/manage', '/bag/packaging-units/manage/create', '/bag/bag-orders', '/bag/bag-orders/create', '/bag/bag-receivings', '/bag/bag-receivings/create', '/bag/bag-inventory', '/bag/shop-orders', '/bag/shop-orders/create', '/bag/bag-sales', '/bag/bag-sales/create', '/bag/bag-issues', '/bag/bag-issues/create', '/bag/password-change', '/bag/reports/sales-ledger?start_date=2026-01-01&end_date=2026-12-31', '/bag/reports/daily-summary?date=2026-01-15', '/bag/reports/period-sales?start_date=2026-01-01&end_date=2026-12-31', '/bag/reports/yearly-sales?year=2026', '/bag/reports/shop-sales', '/bag/reports/hometax-export', '/bag/reports/returns', '/bag/reports/supply-demand', '/bag/reports/lot-flow', '/bag/reports/misc-flow', ]; const ADMIN_PATHS = [ '/admin/', ]; test.describe('메뉴 링크 스모크 — Bag (지자체관리자)', () => { test.beforeEach(async ({ page }) => { await login(page, 'local'); }); for (const path of BAG_PATHS) { test(path, async ({ page }) => { await assertNoServerError(page, path); }); } }); test.describe('메뉴 링크 스모크 — Admin (Super Admin + 지자체 선택)', () => { test.beforeEach(async ({ page }) => { await loginAsAdmin(page); }); for (const path of ADMIN_PATHS) { test(path, async ({ page }) => { await assertNoServerError(page, path); }); } });