diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..59f7af2 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,44 @@ +name: CI + +on: + push: + branches: [ main, master ] + pull_request: + +jobs: + test: + runs-on: [macos, host] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install deps + run: npm ci + + - name: Unit/Component tests (Vitest) + run: npm test + env: + CI: true + + - name: Install Playwright browsers + run: npx playwright install --with-deps + + - name: E2E tests (Playwright) + run: npm run test:e2e -- --reporter=line + env: + CI: true + + - name: Upload Playwright report + if: always() + uses: actions/upload-artifact@v4 + with: + name: playwright-report + path: playwright-report + if-no-files-found: ignore + retention-days: 3 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb0b1e0..04a4d8b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: jobs: test: - runs-on: ubuntu-latest + runs-on: [macos, host] steps: - name: Checkout uses: actions/checkout@v4 diff --git a/messages/en.json b/messages/en.json index e83f3b0..e2e4df2 100644 --- a/messages/en.json +++ b/messages/en.json @@ -1,27 +1,39 @@ { - "app.title": "Landing Page Builder", - "builder.title": "Landing Page Builder", - "builder.preview": "Preview (static)", - "builder.field.title": "Title", - "builder.field.locale": "Locale", - "builder.field.primaryColor": "Primary Color", - "builder.field.fontFamily": "Font Family", - "builder.upload.hero": "Hero Image Upload", - "builder.action.addHero": "Add Hero", - "builder.action.addFAQ": "Add FAQ", - "builder.action.addCTA": "Add CTA", - "builder.action.export": "Export ZIP", - "builder.action.addText": "Add Text", - "builder.action.addEmail": "Add Email", - "builder.action.addTel": "Add Tel", - "builder.action.addDate": "Add Date", - "builder.action.addTextarea": "Add Textarea", - "builder.action.addCheckbox": "Add Checkbox", - "builder.action.addSelect": "Add Select", - "builder.action.addRadio": "Add Radio", - "builder.sections": "Sections", - "builder.form.fields": "Form Fields", - "builder.form.actionUrl": "Action URL", - "builder.form.honeypot": "Honeypot Field", - "builder.form.minSeconds": "Min Submit Seconds" + "app": { + "title": "Landing Page Builder" + }, + "builder": { + "title": "Landing Page Builder", + "preview": "Preview (static)", + "field": { + "title": "Title", + "locale": "Locale", + "primaryColor": "Primary Color", + "fontFamily": "Font Family" + }, + "upload": { + "hero": "Hero Image Upload" + }, + "action": { + "addHero": "Add Hero", + "addFAQ": "Add FAQ", + "addCTA": "Add CTA", + "export": "Export ZIP", + "addText": "Add Text", + "addEmail": "Add Email", + "addTel": "Add Tel", + "addDate": "Add Date", + "addTextarea": "Add Textarea", + "addCheckbox": "Add Checkbox", + "addSelect": "Add Select", + "addRadio": "Add Radio" + }, + "sections": "Sections", + "form": { + "fields": "Form Fields", + "actionUrl": "Action URL", + "honeypot": "Honeypot Field", + "minSeconds": "Min Submit Seconds" + } + } } diff --git a/messages/ko.json b/messages/ko.json index 6ffb530..f12ee70 100644 --- a/messages/ko.json +++ b/messages/ko.json @@ -1,16 +1,39 @@ { - "app.title": "랜딩 페이지 빌더", - "builder.title": "랜딩 페이지 빌더", - "builder.preview": "미리보기(정적)", - "builder.field.title": "제목", - "builder.field.locale": "로케일", - "builder.field.primaryColor": "대표 색상", - "builder.field.fontFamily": "폰트", - "builder.upload.hero": "히어로 이미지 업로드", - "builder.action.addHero": "히어로 추가", - "builder.action.addFAQ": "FAQ 추가", - "builder.action.addCTA": "CTA 추가", - "builder.action.export": "ZIP 내보내기", - "builder.sections": "섹션", - "builder.form.fields": "폼 필드" + "app": { + "title": "랜딩 페이지 빌더" + }, + "builder": { + "title": "랜딩 페이지 빌더", + "preview": "미리보기(정적)", + "field": { + "title": "제목", + "locale": "로케일", + "primaryColor": "대표 색상", + "fontFamily": "폰트" + }, + "upload": { + "hero": "히어로 이미지 업로드" + }, + "action": { + "addHero": "히어로 추가", + "addFAQ": "FAQ 추가", + "addCTA": "CTA 추가", + "export": "ZIP 내보내기", + "addText": "텍스트 필드 추가", + "addEmail": "이메일 필드 추가", + "addTel": "전화번호 필드 추가", + "addDate": "날짜 필드 추가", + "addTextarea": "텍스트영역 추가", + "addCheckbox": "체크박스 추가", + "addSelect": "셀렉트 추가", + "addRadio": "라디오 추가" + }, + "sections": "섹션", + "form": { + "fields": "폼 필드", + "actionUrl": "액션 URL", + "honeypot": "허니팟 필드", + "minSeconds": "최소 제출 대기(초)" + } + } } diff --git a/tests/e2e/viewport-toggle.kbd.e2e.ts b/tests/e2e/viewport-toggle.kbd.e2e.ts index 0a39c2f..599527b 100644 --- a/tests/e2e/viewport-toggle.kbd.e2e.ts +++ b/tests/e2e/viewport-toggle.kbd.e2e.ts @@ -4,10 +4,14 @@ const builderUrl = '/en/builder' test('Preview viewport toggle via keyboard (Tab + Enter/Space)', async ({ page }) => { await page.goto(builderUrl) + await page.waitForLoadState('domcontentloaded') + // Ensure the page has focus before sending keyboard events + await page.locator('body').click({ position: { x: 1, y: 1 } }) - // Tab to first button (Desktop) - await page.keyboard.press('Tab') - await expect(page.getByRole('button', { name: 'Desktop' })).toBeFocused() + // Focus the Desktop button explicitly to avoid flakiness from skip-link/initial focus + const desktopBtn = page.getByRole('button', { name: 'Desktop' }) + await desktopBtn.focus() + await expect(desktopBtn).toBeFocused() // Press Space to toggle Mobile (first ensure Desktop is selected, then move to Mobile with Tab) await page.keyboard.press('Tab')