feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
This commit is contained in:
@@ -0,0 +1,432 @@
|
||||
/**
|
||||
* 跨平台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')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user