Playwright E2E 테스트 환경 구성 및 테스터 계정 생성

- Playwright + Chromium 브라우저 테스트 환경 세팅
- 테스터 계정 4개 생성 (admin/local/shop/user, pw: test1234!)
  - seed SQL + Node.js 시더 스크립트 포함
- E2E 테스트 23개 작성 (전체 통과):
  - auth: 로그인/로그아웃/실패/회원가입 (9개)
  - admin: 지자체관리자/Super Admin 패널 접근 (10개)
  - public: 홈/로그인/회원가입/404 (4개)
- CLAUDE.md: 테스트 섹션을 Playwright 기반으로 업데이트
- jobs.md: 테스트 작업 완료 기록

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
javamon1174
2026-03-25 15:18:57 +09:00
parent 17d61b3ee8
commit e318c5e042
12 changed files with 649 additions and 15 deletions

35
e2e/helpers/auth.js Normal file
View File

@@ -0,0 +1,35 @@
/**
* 공통 인증 헬퍼
*/
const TEST_ACCOUNTS = {
admin: { id: 'tester_admin', password: 'test1234!', level: 4 },
local: { id: 'tester_local', password: 'test1234!', level: 3 },
shop: { id: 'tester_shop', password: 'test1234!', level: 2 },
user: { id: 'tester_user', password: 'test1234!', level: 1 },
};
/**
* 로그인 수행
* @param {import('@playwright/test').Page} page
* @param {'admin'|'local'|'shop'|'user'} role
*/
async function login(page, role = 'admin') {
const acct = TEST_ACCOUNTS[role];
await page.goto('/login');
await page.fill('input[name="login_id"]', acct.id);
await page.fill('input[name="password"]', acct.password);
await page.click('button[type="submit"]');
// 로그인 후 리다이렉트 대기
await page.waitForURL(url => !url.pathname.includes('/login'), { timeout: 10000 });
}
/**
* 로그아웃 수행
* @param {import('@playwright/test').Page} page
*/
async function logout(page) {
await page.goto('/logout');
}
module.exports = { TEST_ACCOUNTS, login, logout };

68
e2e/helpers/db-seed.js Normal file
View File

@@ -0,0 +1,68 @@
/**
* DB 시더: 테스터 계정 생성
* 실행: node e2e/helpers/db-seed.js
*/
const mysql = require('mysql2/promise');
const bcrypt = require('bcryptjs');
const DB_CONFIG = {
host: '3.36.27.239',
port: 3306,
user: 'root',
password: 'ssadm!#@$',
database: 'jongryangje_dev',
};
const TEST_PASSWORD = 'test1234!';
const TEST_ACCOUNTS = [
{ id: 'tester_admin', name: '테스터관리자', email: 'tester_admin@test.com', phone: '010-0000-0001', level: 4, lg_idx: null },
{ id: 'tester_local', name: '테스터지자체', email: 'tester_local@test.com', phone: '010-0000-0002', level: 3, lg_idx: 1 },
{ id: 'tester_shop', name: '테스터판매소', email: 'tester_shop@test.com', phone: '010-0000-0003', level: 2, lg_idx: null },
{ id: 'tester_user', name: '테스터사용자', email: 'tester_user@test.com', phone: '010-0000-0004', level: 1, lg_idx: null },
];
async function seed() {
const conn = await mysql.createConnection(DB_CONFIG);
const hash = bcrypt.hashSync(TEST_PASSWORD, 10).replace('$2b$', '$2y$');
console.log('테스터 계정 시딩 시작...');
for (const acct of TEST_ACCOUNTS) {
// Upsert member
await conn.execute(
`INSERT INTO member (mb_id, mb_passwd, mb_name, mb_email, mb_phone, mb_lang, mb_level, mb_group, mb_lg_idx, mb_state, mb_regdate)
VALUES (?, ?, ?, ?, ?, 'ko', ?, '', ?, 1, NOW())
ON DUPLICATE KEY UPDATE mb_passwd = VALUES(mb_passwd), mb_state = 1, mb_level = VALUES(mb_level)`,
[acct.id, hash, acct.name, acct.email, acct.phone, acct.level, acct.lg_idx]
);
// Ensure approval request exists (approved)
const [rows] = await conn.execute(
'SELECT mb_idx FROM member WHERE mb_id = ?', [acct.id]
);
if (rows.length > 0) {
const mbIdx = rows[0].mb_idx;
const [existing] = await conn.execute(
'SELECT mar_idx FROM member_approval_request WHERE mb_idx = ?', [mbIdx]
);
if (existing.length === 0) {
await conn.execute(
`INSERT INTO member_approval_request (mb_idx, mar_requested_level, mar_status, mar_request_note, mar_requested_at, mar_processed_at)
VALUES (?, ?, 'approved', '테스트 계정 자동 승인', NOW(), NOW())`,
[mbIdx, acct.level]
);
}
}
console.log(`${acct.id} (Level ${acct.level})`);
}
await conn.end();
console.log('시딩 완료!');
}
seed().catch(err => {
console.error('시딩 실패:', err.message);
process.exit(1);
});