08ea5fbe98
添加用户管理视图、API和状态管理文件
433 lines
14 KiB
TypeScript
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')
|
|
})
|
|
})
|