Files
张翔 08ea5fbe98 feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
2026-03-28 14:37:29 +08:00

433 lines
14 KiB
TypeScript

/**
* 跨平台E2E测试套件
*
* 测试uniapp和admin两个平台的数据一致性和功能完整性
*
* @tags @cross-platform @e2e @integration
*/
import { test, expect, Page } from '@playwright/test'
import { TestLogger } from './core/test-logger.js'
interface AlmanacData {
date: string
lunarDate: string
ganZhi: string
zodiac: string
solarTerm: string | null
festivals: string[]
yi: string[]
ji: string[]
}
/**
* 黄历页面对象 - UniApp
*/
class UniAppAlmanacPage {
private page: Page
private logger: TestLogger
constructor(page: Page, logger: TestLogger) {
this.page = page
this.logger = logger
}
async navigate() {
this.logger.info('导航到UniApp黄历页面')
await this.page.goto('http://localhost:3000/pages/almanac/index')
await this.page.waitForLoadState('networkidle')
}
async selectDate(date: string) {
this.logger.info(`选择日期: ${date}`)
await this.page.click(`[data-date="${date}"]`)
}
async getAlmanacData(): Promise<AlmanacData> {
this.logger.info('获取黄历数据')
const date = await this.page.locator('[data-testid="almanac-date"]').textContent() || ''
const lunarDate = await this.page.locator('[data-testid="lunar-date"]').textContent() || ''
const ganZhi = await this.page.locator('[data-testid="ganzhi"]').textContent() || ''
const zodiac = await this.page.locator('[data-testid="zodiac"]').textContent() || ''
const solarTerm = await this.page.locator('[data-testid="solar-term"]').textContent()
return {
date,
lunarDate,
ganZhi,
zodiac,
solarTerm: solarTerm || null,
festivals: await this.page.locator('[data-testid="festival"]').allTextContents(),
yi: await this.page.locator('[data-testid="yi-item"]').allTextContents(),
ji: await this.page.locator('[data-testid="ji-item"]').allTextContents()
}
}
}
/**
* 黄历页面对象 - Admin
*/
class AdminAlmanacPage {
private page: Page
private logger: TestLogger
constructor(page: Page, logger: TestLogger) {
this.page = page
this.logger = logger
}
async navigate() {
this.logger.info('导航到Admin黄历页面')
await this.page.goto('http://localhost:5174/almanac')
await this.page.waitForLoadState('networkidle')
}
async selectDate(date: string) {
this.logger.info(`选择日期: ${date}`)
await this.page.fill('[data-testid="date-input"]', date)
await this.page.click('[data-testid="query-button"]')
}
async getAlmanacData(): Promise<AlmanacData> {
this.logger.info('获取黄历数据')
const date = await this.page.locator('[data-testid="almanac-date"]').textContent() || ''
const lunarDate = await this.page.locator('[data-testid="lunar-date"]').textContent() || ''
const ganZhi = await this.page.locator('[data-testid="ganzhi"]').textContent() || ''
const zodiac = await this.page.locator('[data-testid="zodiac"]').textContent() || ''
const solarTerm = await this.page.locator('[data-testid="solar-term"]').textContent()
return {
date,
lunarDate,
ganZhi,
zodiac,
solarTerm: solarTerm || null,
festivals: await this.page.locator('[data-testid="festival"]').allTextContents(),
yi: await this.page.locator('[data-testid="yi-item"]').allTextContents(),
ji: await this.page.locator('[data-testid="ji-item"]').allTextContents()
}
}
}
test.describe('E2E: 跨平台数据一致性测试', () => {
let logger: TestLogger
test.beforeEach(() => {
logger = new TestLogger()
})
test('两个平台应该显示相同的农历日期 @cross-platform @critical', async ({ browser }) => {
// Given: 测试日期
const testDate = '2024-02-10' // 春节
// 打开两个页面
const uniappContext = await browser.newContext()
const adminContext = await browser.newContext()
const uniappPage = await uniappContext.newPage()
const adminPage = await adminContext.newPage()
const uniappAlmanac = new UniAppAlmanacPage(uniappPage, logger)
const adminAlmanac = new AdminAlmanacPage(adminPage, logger)
// When: 两个平台选择相同日期
await uniappAlmanac.navigate()
await adminAlmanac.navigate()
await uniappAlmanac.selectDate(testDate)
await adminAlmanac.selectDate(testDate)
// Then: 农历日期应该一致
const uniappData = await uniappAlmanac.getAlmanacData()
const adminData = await adminAlmanac.getAlmanacData()
expect(uniappData.lunarDate).toBe(adminData.lunarDate)
expect(uniappData.ganZhi).toBe(adminData.ganZhi)
expect(uniappData.zodiac).toBe(adminData.zodiac)
await uniappContext.close()
await adminContext.close()
})
test('两个平台应该显示相同的宜忌信息 @cross-platform', async ({ browser }) => {
// Given: 测试日期
const testDate = '2024-06-01'
const uniappContext = await browser.newContext()
const adminContext = await browser.newContext()
const uniappPage = await uniappContext.newPage()
const adminPage = await adminContext.newPage()
const uniappAlmanac = new UniAppAlmanacPage(uniappPage, logger)
const adminAlmanac = new AdminAlmanacPage(adminPage, logger)
// When: 两个平台选择相同日期
await uniappAlmanac.navigate()
await adminAlmanac.navigate()
await uniappAlmanac.selectDate(testDate)
await adminAlmanac.selectDate(testDate)
// Then: 宜忌信息应该一致
const uniappData = await uniappAlmanac.getAlmanacData()
const adminData = await adminAlmanac.getAlmanacData()
expect(uniappData.yi).toEqual(adminData.yi)
expect(uniappData.ji).toEqual(adminData.ji)
await uniappContext.close()
await adminContext.close()
})
test('两个平台应该显示相同的节日信息 @cross-platform', async ({ browser }) => {
// Given: 节日日期
const festivalDates = [
{ date: '2024-02-10', festival: '春节' },
{ date: '2024-06-10', festival: '端午节' },
{ date: '2024-09-17', festival: '中秋节' }
]
for (const { date, festival } of festivalDates) {
const uniappContext = await browser.newContext()
const adminContext = await browser.newContext()
const uniappPage = await uniappContext.newPage()
const adminPage = await adminContext.newPage()
const uniappAlmanac = new UniAppAlmanacPage(uniappPage, logger)
const adminAlmanac = new AdminAlmanacPage(adminPage, logger)
// When: 两个平台选择节日日期
await uniappAlmanac.navigate()
await adminAlmanac.navigate()
await uniappAlmanac.selectDate(date)
await adminAlmanac.selectDate(date)
// Then: 节日信息应该一致且包含对应节日
const uniappData = await uniappAlmanac.getAlmanacData()
const adminData = await adminAlmanac.getAlmanacData()
expect(uniappData.festivals).toContain(festival)
expect(adminData.festivals).toContain(festival)
expect(uniappData.festivals).toEqual(adminData.festivals)
await uniappContext.close()
await adminContext.close()
}
})
test('两个平台应该显示相同的节气信息 @cross-platform', async ({ browser }) => {
// Given: 节气日期
const solarTermDates = [
{ date: '2024-02-04', term: '立春' },
{ date: '2024-03-20', term: '春分' },
{ date: '2024-06-21', term: '夏至' }
]
for (const { date, term } of solarTermDates) {
const uniappContext = await browser.newContext()
const adminContext = await browser.newContext()
const uniappPage = await uniappContext.newPage()
const adminPage = await adminContext.newPage()
const uniappAlmanac = new UniAppAlmanacPage(uniappPage, logger)
const adminAlmanac = new AdminAlmanacPage(adminPage, logger)
// When: 两个平台选择节气日期
await uniappAlmanac.navigate()
await adminAlmanac.navigate()
await uniappAlmanac.selectDate(date)
await adminAlmanac.selectDate(date)
// Then: 节气信息应该一致
const uniappData = await uniappAlmanac.getAlmanacData()
const adminData = await adminAlmanac.getAlmanacData()
expect(uniappData.solarTerm).toBe(term)
expect(adminData.solarTerm).toBe(term)
expect(uniappData.solarTerm).toBe(adminData.solarTerm)
await uniappContext.close()
await adminContext.close()
}
})
})
test.describe('E2E: 跨平台响应式测试', () => {
let logger: TestLogger
test.beforeEach(() => {
logger = new TestLogger()
})
test('UniApp应该在移动端正常显示 @cross-platform @responsive', async ({ browser }) => {
// Given: 移动端视口
const context = await browser.newContext({
viewport: { width: 375, height: 667 },
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X)'
})
const page = await context.newPage()
const uniappAlmanac = new UniAppAlmanacPage(page, logger)
// When: 访问UniApp
await uniappAlmanac.navigate()
// Then: 页面应该正常显示
await expect(page.locator('[data-testid="almanac-container"]')).toBeVisible()
await expect(page.locator('[data-testid="calendar-grid"]')).toBeVisible()
await context.close()
})
test('Admin应该在桌面端正常显示 @cross-platform @responsive', async ({ browser }) => {
// Given: 桌面端视口
const context = await browser.newContext({
viewport: { width: 1920, height: 1080 }
})
const page = await context.newPage()
const adminAlmanac = new AdminAlmanacPage(page, logger)
// When: 访问Admin
await adminAlmanac.navigate()
// Then: 页面应该正常显示
await expect(page.locator('[data-testid="almanac-container"]')).toBeVisible()
await expect(page.locator('[data-testid="date-input"]')).toBeVisible()
await context.close()
})
})
test.describe('E2E: 跨平台性能测试', () => {
let logger: TestLogger
test.beforeEach(() => {
logger = new TestLogger()
})
test('两个平台的页面加载时间应该符合要求 @cross-platform @performance', async ({ browser }) => {
// Given: 性能阈值
const maxLoadTime = 3000 // 3秒
// 测试UniApp
const uniappContext = await browser.newContext()
const uniappPage = await uniappContext.newPage()
const uniappStart = Date.now()
await uniappPage.goto('http://localhost:3000/pages/almanac/index')
await uniappPage.waitForLoadState('networkidle')
const uniappLoadTime = Date.now() - uniappStart
logger.info(`UniApp加载时间: ${uniappLoadTime}ms`)
expect(uniappLoadTime).toBeLessThan(maxLoadTime)
await uniappContext.close()
// 测试Admin
const adminContext = await browser.newContext()
const adminPage = await adminContext.newPage()
const adminStart = Date.now()
await adminPage.goto('http://localhost:5174/almanac')
await adminPage.waitForLoadState('networkidle')
const adminLoadTime = Date.now() - adminStart
logger.info(`Admin加载时间: ${adminLoadTime}ms`)
expect(adminLoadTime).toBeLessThan(maxLoadTime)
await adminContext.close()
})
test('两个平台的日期切换应该流畅 @cross-platform @performance', async ({ browser }) => {
// Given: 性能阈值
const maxSwitchTime = 500 // 500ms
const uniappContext = await browser.newContext()
const adminContext = await browser.newContext()
const uniappPage = await uniappContext.newPage()
const adminPage = await adminContext.newPage()
const uniappAlmanac = new UniAppAlmanacPage(uniappPage, logger)
const adminAlmanac = new AdminAlmanacPage(adminPage, logger)
// 测试UniApp日期切换
await uniappAlmanac.navigate()
const uniappStart = Date.now()
await uniappAlmanac.selectDate('2024-06-15')
const uniappSwitchTime = Date.now() - uniappStart
logger.info(`UniApp日期切换时间: ${uniappSwitchTime}ms`)
expect(uniappSwitchTime).toBeLessThan(maxSwitchTime)
// 测试Admin日期切换
await adminAlmanac.navigate()
const adminStart = Date.now()
await adminAlmanac.selectDate('2024-06-15')
const adminSwitchTime = Date.now() - adminStart
logger.info(`Admin日期切换时间: ${adminSwitchTime}ms`)
expect(adminSwitchTime).toBeLessThan(maxSwitchTime)
await uniappContext.close()
await adminContext.close()
})
})
test.describe('E2E: 跨平台API一致性测试', () => {
let logger: TestLogger
test.beforeEach(() => {
logger = new TestLogger()
})
test('两个平台应该使用相同的API端点 @cross-platform @api', async ({ request }) => {
// Given: API端点
const endpoints = [
'/api/almanac/today',
'/api/almanac/date',
'/api/lunar/convert',
'/api/solar-term/list'
]
for (const endpoint of endpoints) {
// When: 请求API
const response = await request.get(`http://localhost:8080${endpoint}`)
// Then: 应该返回成功状态
expect(response.status()).toBe(200)
const data = await response.json()
expect(data).toHaveProperty('code')
expect(data).toHaveProperty('data')
}
})
test('API响应格式应该一致 @cross-platform @api', async ({ request }) => {
// Given: 日期参数
const date = '2024-06-01'
// When: 请求黄历数据
const response = await request.get(`http://localhost:8080/api/almanac/date?date=${date}`)
// Then: 响应格式应该符合规范
const data = await response.json()
expect(data.code).toBe(200)
expect(data.data).toHaveProperty('date')
expect(data.data).toHaveProperty('lunarDate')
expect(data.data).toHaveProperty('ganZhi')
expect(data.data).toHaveProperty('zodiac')
expect(data.data).toHaveProperty('yi')
expect(data.data).toHaveProperty('ji')
})
})