mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-14 02:42:04 +08:00
Add E2E tests for internationalization across multiple pages
- Implemented navigation.spec.ts to test language switching and translation of navigation elements. - Created sessions-page.spec.ts to verify translations on the sessions page, including headers, status badges, and date formatting. - Developed settings-page.spec.ts to ensure settings page content is translated and persists across sessions. - Added skills-page.spec.ts to validate translations for skill categories, action buttons, and empty states.
This commit is contained in:
254
ccw/frontend/tests/e2e/issues-page.spec.ts
Normal file
254
ccw/frontend/tests/e2e/issues-page.spec.ts
Normal file
@@ -0,0 +1,254 @@
|
||||
// ========================================
|
||||
// E2E Tests: Issues Page i18n
|
||||
// ========================================
|
||||
// Tests for issues page internationalization
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import {
|
||||
switchLanguageAndVerify,
|
||||
verifyI18nState,
|
||||
} from './helpers/i18n-helpers';
|
||||
|
||||
test.describe('[Issues Page] - i18n E2E Tests', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/', { waitUntil: 'networkidle' });
|
||||
|
||||
// Navigate to issues page
|
||||
const issuesLink = page.getByRole('link', { name: /issues/i });
|
||||
const isVisible = await issuesLink.isVisible().catch(() => false);
|
||||
|
||||
if (isVisible) {
|
||||
await issuesLink.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* ISS-01: Verify issue list headers are translated
|
||||
* Priority: P1
|
||||
*/
|
||||
test('ISS-01: should translate issue list table headers', async ({ page }) => {
|
||||
// Look for table headers in English
|
||||
const tableHeaders = page.locator('table th, thead th');
|
||||
const count = await tableHeaders.count();
|
||||
|
||||
if (count > 0) {
|
||||
// Get initial header text
|
||||
const firstHeaderText = await tableHeaders.first().textContent();
|
||||
expect(firstHeaderText).toBeTruthy();
|
||||
|
||||
// Switch to Chinese
|
||||
const languageSwitcher = page.getByRole('combobox', { name: /select language/i });
|
||||
await switchLanguageAndVerify(page, 'zh', languageSwitcher);
|
||||
|
||||
// Verify i18n state
|
||||
await verifyI18nState(page, 'zh');
|
||||
|
||||
// Get updated header text
|
||||
const updatedHeaderText = await tableHeaders.first().textContent();
|
||||
expect(updatedHeaderText).toBeTruthy();
|
||||
|
||||
// Headers should contain Chinese characters or be different
|
||||
const hasChineseOrDifferent = updatedHeaderText !== firstHeaderText ||
|
||||
/[\u4e00-\u9fa5]/.test(updatedHeaderText || '');
|
||||
expect(hasChineseOrDifferent).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* ISS-02: Verify status badges are translated
|
||||
* Priority: P2
|
||||
*/
|
||||
test('ISS-02: should translate status badges', async ({ page }) => {
|
||||
// Look for status badges
|
||||
const statusBadges = page.locator('[class*="status"], [class*="badge"], span.badge').first();
|
||||
const isVisible = await statusBadges.isVisible().catch(() => false);
|
||||
|
||||
if (isVisible) {
|
||||
// Get initial status text
|
||||
const initialStatus = await statusBadges.textContent();
|
||||
expect(initialStatus).toBeTruthy();
|
||||
|
||||
// Switch to Chinese
|
||||
const languageSwitcher = page.getByRole('combobox', { name: /select language/i });
|
||||
await switchLanguageAndVerify(page, 'zh', languageSwitcher);
|
||||
|
||||
// Get updated status text
|
||||
const updatedStatus = await statusBadges.textContent();
|
||||
expect(updatedStatus).toBeTruthy();
|
||||
|
||||
// Status should contain Chinese characters or be different
|
||||
const hasChineseOrDifferent = updatedStatus !== initialStatus ||
|
||||
/[\u4e00-\u9fa5]/.test(updatedStatus || '');
|
||||
expect(hasChineseOrDifferent).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* ISS-03: Verify action buttons are translated
|
||||
* Priority: P1
|
||||
*/
|
||||
test('ISS-03: should translate action buttons', async ({ page }) => {
|
||||
// Look for action buttons (view, edit, delete, etc.)
|
||||
const actionButtons = page.locator('button').filter({ hasText: /^(view|edit|delete|create)/i });
|
||||
const count = await actionButtons.count();
|
||||
|
||||
if (count > 0) {
|
||||
// Get first action button text
|
||||
const initialText = await actionButtons.first().textContent();
|
||||
expect(initialText).toBeTruthy();
|
||||
|
||||
// Switch to Chinese
|
||||
const languageSwitcher = page.getByRole('combobox', { name: /select language/i });
|
||||
await switchLanguageAndVerify(page, 'zh', languageSwitcher);
|
||||
|
||||
// Get updated button text
|
||||
const updatedText = await actionButtons.first().textContent();
|
||||
expect(updatedText).toBeTruthy();
|
||||
|
||||
// Button text should contain Chinese characters or be different
|
||||
const hasChineseOrDifferent = updatedText !== initialText ||
|
||||
/[\u4e00-\u9fa5]/.test(updatedText || '');
|
||||
expect(hasChineseOrDifferent).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* ISS-04: Verify date formatting per locale
|
||||
* Priority: P2
|
||||
*/
|
||||
test('ISS-04: should format dates according to locale', async ({ page }) => {
|
||||
// Look for date elements
|
||||
const dateElements = page.locator('time, [datetime], [class*="date"], [class*="time"]');
|
||||
const count = await dateElements.count();
|
||||
|
||||
if (count > 0) {
|
||||
// Get initial date format
|
||||
const initialDate = await dateElements.first().textContent();
|
||||
expect(initialDate).toBeTruthy();
|
||||
|
||||
// Switch to Chinese
|
||||
const languageSwitcher = page.getByRole('combobox', { name: /select language/i });
|
||||
await switchLanguageAndVerify(page, 'zh', languageSwitcher);
|
||||
|
||||
// Get updated date
|
||||
const updatedDate = await dateElements.first().textContent();
|
||||
expect(updatedDate).toBeTruthy();
|
||||
|
||||
// Date might be formatted differently or contain Chinese date characters
|
||||
// This is a basic check that dates exist in both locales
|
||||
const hasDateContent = updatedDate && updatedDate.length > 0;
|
||||
expect(hasDateContent).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Additional: Verify empty state message is translated
|
||||
*/
|
||||
test('should translate empty state message', async ({ page }) => {
|
||||
// Look for empty state indicators
|
||||
const emptyState = page.getByText(/no issues|empty|no data/i);
|
||||
const isVisible = await emptyState.isVisible().catch(() => false);
|
||||
|
||||
if (isVisible) {
|
||||
// Get initial empty state text
|
||||
const initialText = await emptyState.textContent();
|
||||
expect(initialText).toBeTruthy();
|
||||
|
||||
// Switch to Chinese
|
||||
const languageSwitcher = page.getByRole('combobox', { name: /select language/i });
|
||||
await switchLanguageAndVerify(page, 'zh', languageSwitcher);
|
||||
|
||||
// Get updated empty state text
|
||||
const updatedText = await emptyState.textContent();
|
||||
expect(updatedText).toBeTruthy();
|
||||
|
||||
// Empty state should contain Chinese characters or be different
|
||||
const hasChineseOrDifferent = updatedText !== initialText ||
|
||||
/[\u4e00-\u9fa5]/.test(updatedText || '');
|
||||
expect(hasChineseOrDifferent).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Additional: Verify pagination controls are translated
|
||||
*/
|
||||
test('should translate pagination controls', async ({ page }) => {
|
||||
// Look for pagination controls
|
||||
const pagination = page.locator('[class*="pagination"], nav[aria-label*="pagination"]');
|
||||
const isVisible = await pagination.isVisible().catch(() => false);
|
||||
|
||||
if (isVisible) {
|
||||
// Get initial pagination text
|
||||
const initialText = await pagination.textContent();
|
||||
expect(initialText).toBeTruthy();
|
||||
|
||||
// Switch to Chinese
|
||||
const languageSwitcher = page.getByRole('combobox', { name: /select language/i });
|
||||
await switchLanguageAndVerify(page, 'zh', languageSwitcher);
|
||||
|
||||
// Get updated pagination text
|
||||
const updatedText = await pagination.textContent();
|
||||
expect(updatedText).toBeTruthy();
|
||||
|
||||
// Pagination should contain Chinese characters or be different
|
||||
const hasChineseOrDifferent = updatedText !== initialText ||
|
||||
/[\u4e00-\u9fa5]/.test(updatedText || '');
|
||||
expect(hasChineseOrDifferent).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Additional: Verify filter controls are translated
|
||||
*/
|
||||
test('should translate filter controls', async ({ page }) => {
|
||||
// Look for filter controls
|
||||
const filterSelect = page.locator('select').filter({ hasText: /filter|status|all/i }).first();
|
||||
const isVisible = await filterSelect.isVisible().catch(() => false);
|
||||
|
||||
if (isVisible) {
|
||||
// Get initial filter options
|
||||
const initialOptions = await filterSelect.locator('option').allTextContents();
|
||||
expect(initialOptions.length).toBeGreaterThan(0);
|
||||
|
||||
// Switch to Chinese
|
||||
const languageSwitcher = page.getByRole('combobox', { name: /select language/i });
|
||||
await switchLanguageAndVerify(page, 'zh', languageSwitcher);
|
||||
|
||||
// Get updated filter options
|
||||
const updatedOptions = await filterSelect.locator('option').allTextContents();
|
||||
expect(updatedOptions.length).toBeGreaterThan(0);
|
||||
|
||||
// At least some options should be different or contain Chinese
|
||||
const hasTranslation = updatedOptions.some((opt, i) =>
|
||||
opt !== initialOptions[i] || /[\u4e00-\u9fa5]/.test(opt)
|
||||
);
|
||||
expect(hasTranslation).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Additional: Verify language persists when viewing issue details
|
||||
*/
|
||||
test('should maintain language when viewing issue details', async ({ page }) => {
|
||||
const languageSwitcher = page.getByRole('combobox', { name: /select language/i });
|
||||
|
||||
// Switch to Chinese
|
||||
await switchLanguageAndVerify(page, 'zh', languageSwitcher);
|
||||
|
||||
// Look for issue detail links
|
||||
const detailLink = page.locator('a').filter({ hasText: /#/ }).first();
|
||||
const isVisible = await detailLink.isVisible().catch(() => false);
|
||||
|
||||
if (isVisible) {
|
||||
await detailLink.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Verify language is maintained
|
||||
await verifyI18nState(page, 'zh');
|
||||
|
||||
const lang = await page.evaluate(() => document.documentElement.lang);
|
||||
expect(lang).toBe('zh');
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user