fix(regression): resolve dogfood findings across marketing, auth, e2e and docs

- Fix list-to-detail navigation on product/service/solution/case pages
- Fix soft 404 on service detail by removing (marketing)/loading.tsx and using force-dynamic
- Fix contact form submission feedback and news placeholder image handling
- Unify SSR/client authentication state in auth.ts
- Add "新闻动态" to main navigation
- Fix Playwright storageState path and Firefox footer link flakiness
- Add E2E coverage for nav dropdown, cases filter and auth token parsing
- Update visual regression baselines (desktop/tablet/mobile, chromium/webkit/firefox)
- Update README, lessons-learned and add REGRESSION_REPORT_2026-07-27.md
- Ignore .lighthouseci/ and heading-hierarchy-report.json
This commit is contained in:
2026-07-27 07:39:11 +08:00
parent 10404dbb36
commit 2653a3730c
97 changed files with 659 additions and 187 deletions
+38 -19
View File
@@ -647,27 +647,46 @@ test.describe('Footer - 全局底部区域', () => {
});
test('Footer 导航链接可点击', async ({ page }) => {
const footer = page.locator('footer, [data-testid="footer"]').first();
// 检查隐私政策和服务条款链接
const privacyLink = footer.locator('a:has-text("隐私政策")');
if (await privacyLink.count() > 0 && await privacyLink.isVisible()) {
await privacyLink.click();
await page.waitForTimeout(1000);
expect(page.url()).toContain('/privacy');
}
// 返回首页检查服务条款
// 隐私政策链接:独立测试,避免 Firefox 中连续全页导航的竞态问题
await page.goto('/', { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
await page.waitForTimeout(500);
await page.waitForTimeout(1500);
const termsLink = footer.locator('a:has-text("服务条款")');
if (await termsLink.count() > 0 && await termsLink.isVisible()) {
await termsLink.click();
await page.waitForTimeout(1000);
expect(page.url()).toContain('/terms');
}
const privacyClicked = await page.evaluate(() => {
const link = document.querySelector('footer a, [data-testid="footer"] a') as HTMLAnchorElement | null;
if (!link) return false;
const privacy = Array.from(document.querySelectorAll('footer a, [data-testid="footer"] a'))
.find((el) => el.textContent?.includes('隐私政策')) as HTMLAnchorElement | undefined;
if (privacy) {
privacy.scrollIntoView({ behavior: 'instant', block: 'center' });
privacy.click();
return true;
}
return false;
});
expect(privacyClicked).toBe(true);
await page.waitForURL(/\/privacy/, { timeout: 15000 });
expect(page.url()).toContain('/privacy');
});
test('Footer 服务条款链接可点击', async ({ page }) => {
await page.goto('/', { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.waitForTimeout(1500);
const termsClicked = await page.evaluate(() => {
const terms = Array.from(document.querySelectorAll('footer a, [data-testid="footer"] a'))
.find((el) => el.textContent?.includes('服务条款')) as HTMLAnchorElement | undefined;
if (terms) {
terms.scrollIntoView({ behavior: 'instant', block: 'center' });
terms.click();
return true;
}
return false;
});
expect(termsClicked).toBe(true);
await page.waitForURL(/\/terms/, { timeout: 15000 });
expect(page.url()).toContain('/terms');
});
test('Footer 包含联系方式(邮箱)', async ({ page }) => {