feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
This commit is contained in:
@@ -0,0 +1,425 @@
|
||||
import { test, expect, Page } from '@playwright/test';
|
||||
|
||||
const ANIMATION_THRESHOLDS = {
|
||||
fps: 30,
|
||||
frameTime: 33.33,
|
||||
animationDuration: 500,
|
||||
};
|
||||
|
||||
interface AnimationMetrics {
|
||||
fps: number;
|
||||
frameTime: number;
|
||||
droppedFrames: number;
|
||||
totalFrames: number;
|
||||
}
|
||||
|
||||
async function measureAnimationPerformance(page: Page, animationTrigger: () => Promise<void>, duration: number = 1000): Promise<AnimationMetrics> {
|
||||
const frames: number[] = [];
|
||||
|
||||
await page.evaluate(() => {
|
||||
window.performanceMetrics = {
|
||||
frames: [],
|
||||
startTime: performance.now(),
|
||||
};
|
||||
});
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
const frameCollector = setInterval(async () => {
|
||||
const timestamp = await page.evaluate(() => {
|
||||
const metrics = (window as any).performanceMetrics;
|
||||
if (metrics) {
|
||||
metrics.frames.push(performance.now() - metrics.startTime);
|
||||
}
|
||||
return performance.now();
|
||||
});
|
||||
frames.push(timestamp);
|
||||
}, 16);
|
||||
|
||||
await animationTrigger();
|
||||
|
||||
await page.waitForTimeout(duration);
|
||||
|
||||
clearInterval(frameCollector);
|
||||
|
||||
const metrics = await page.evaluate(() => {
|
||||
const metrics = (window as any).performanceMetrics;
|
||||
return metrics ? metrics.frames : [];
|
||||
});
|
||||
|
||||
const totalFrames = metrics.length;
|
||||
const droppedFrames = metrics.filter((frameTime: number, index: number) => {
|
||||
if (index === 0) return false;
|
||||
return frameTime - metrics[index - 1] > 33.33;
|
||||
}).length;
|
||||
|
||||
const fps = totalFrames / (duration / 1000);
|
||||
const frameTime = duration / totalFrames;
|
||||
|
||||
return {
|
||||
fps,
|
||||
frameTime,
|
||||
droppedFrames,
|
||||
totalFrames,
|
||||
};
|
||||
}
|
||||
|
||||
async function measureThemeSwitchAnimation(page: Page): Promise<AnimationMetrics> {
|
||||
return await measureAnimationPerformance(page, async () => {
|
||||
await page.click('.theme-switch-btn');
|
||||
}, 500);
|
||||
}
|
||||
|
||||
async function measurePageTransitionAnimation(page: Page, targetUrl: string): Promise<AnimationMetrics> {
|
||||
return await measureAnimationPerformance(page, async () => {
|
||||
await page.click(`[data-href="${targetUrl}"]`);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
async function measureComponentAnimation(page: Page, selector: string): Promise<AnimationMetrics> {
|
||||
return await measureAnimationPerformance(page, async () => {
|
||||
await page.click(selector);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
test.describe('主题切换动画性能测试', () => {
|
||||
test('浅色主题切换到深色主题FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/pages/user/index');
|
||||
await page.waitForSelector('.theme-switch-btn');
|
||||
|
||||
const metrics = await measureThemeSwitchAnimation(page);
|
||||
|
||||
console.log('主题切换动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('深色主题切换到浅色主题FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/pages/user/index');
|
||||
await page.waitForSelector('.theme-switch-btn');
|
||||
|
||||
await page.click('.theme-switch-btn');
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const metrics = await measureThemeSwitchAnimation(page);
|
||||
|
||||
console.log('主题切换动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('主题切换掉帧数应小于5', async ({ page }) => {
|
||||
await page.goto('/pages/user/index');
|
||||
await page.waitForSelector('.theme-switch-btn');
|
||||
|
||||
const metrics = await measureThemeSwitchAnimation(page);
|
||||
|
||||
console.log('主题切换掉帧数:', metrics.droppedFrames);
|
||||
|
||||
expect(metrics.droppedFrames).toBeLessThan(5);
|
||||
});
|
||||
|
||||
test('主题切换帧时间应小于33.33ms', async ({ page }) => {
|
||||
await page.goto('/pages/user/index');
|
||||
await page.waitForSelector('.theme-switch-btn');
|
||||
|
||||
const metrics = await measureThemeSwitchAnimation(page);
|
||||
|
||||
console.log('主题切换帧时间:', metrics.frameTime);
|
||||
|
||||
expect(metrics.frameTime).toBeLessThan(ANIMATION_THRESHOLDS.frameTime);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('页面切换动画性能测试', () => {
|
||||
test('首页切换到日历页FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForSelector('[data-href="/pages/calendar/index"]');
|
||||
|
||||
const metrics = await measurePageTransitionAnimation(page, '/pages/calendar/index');
|
||||
|
||||
console.log('页面切换动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('首页切换到黄历页FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForSelector('[data-href="/pages/almanac/index"]');
|
||||
|
||||
const metrics = await measurePageTransitionAnimation(page, '/pages/almanac/index');
|
||||
|
||||
console.log('页面切换动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('首页切换到用户页FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForSelector('[data-href="/pages/user/index"]');
|
||||
|
||||
const metrics = await measurePageTransitionAnimation(page, '/pages/user/index');
|
||||
|
||||
console.log('页面切换动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('首页切换到搜索页FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForSelector('[data-href="/pages/search/index"]');
|
||||
|
||||
const metrics = await measurePageTransitionAnimation(page, '/pages/search/index');
|
||||
|
||||
console.log('页面切换动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('日历页切换到黄历页FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/pages/calendar/index');
|
||||
await page.waitForSelector('[data-href="/pages/almanac/index"]');
|
||||
|
||||
const metrics = await measurePageTransitionAnimation(page, '/pages/almanac/index');
|
||||
|
||||
console.log('页面切换动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('黄历页切换到日历页FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/pages/almanac/index');
|
||||
await page.waitForSelector('[data-href="/pages/calendar/index"]');
|
||||
|
||||
const metrics = await measurePageTransitionAnimation(page, '/pages/calendar/index');
|
||||
|
||||
console.log('页面切换动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('页面切换掉帧数应小于5', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForSelector('[data-href="/pages/calendar/index"]');
|
||||
|
||||
const metrics = await measurePageTransitionAnimation(page, '/pages/calendar/index');
|
||||
|
||||
console.log('页面切换掉帧数:', metrics.droppedFrames);
|
||||
|
||||
expect(metrics.droppedFrames).toBeLessThan(5);
|
||||
});
|
||||
|
||||
test('页面切换帧时间应小于33.33ms', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForSelector('[data-href="/pages/calendar/index"]');
|
||||
|
||||
const metrics = await measurePageTransitionAnimation(page, '/pages/calendar/index');
|
||||
|
||||
console.log('页面切换帧时间:', metrics.frameTime);
|
||||
|
||||
expect(metrics.frameTime).toBeLessThan(ANIMATION_THRESHOLDS.frameTime);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('组件动画性能测试', () => {
|
||||
test('日历月切换动画FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/pages/calendar/index');
|
||||
await page.waitForSelector('.calendar-next-month');
|
||||
|
||||
const metrics = await measureComponentAnimation(page, '.calendar-next-month');
|
||||
|
||||
console.log('日历月切换动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('日历年切换动画FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/pages/calendar/index');
|
||||
await page.waitForSelector('.calendar-year-selector');
|
||||
|
||||
await page.click('.calendar-year-selector');
|
||||
await page.waitForSelector('.calendar-year-option[data-year="2027"]');
|
||||
|
||||
const metrics = await measureComponentAnimation(page, '.calendar-year-option[data-year="2027"]');
|
||||
|
||||
console.log('日历年切换动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('黄历月切换动画FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/pages/almanac/index');
|
||||
await page.waitForSelector('.almanac-next-month');
|
||||
|
||||
const metrics = await measureComponentAnimation(page, '.almanac-next-month');
|
||||
|
||||
console.log('黄历月切换动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('搜索建议展开动画FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/pages/search/index');
|
||||
await page.waitForSelector('.search-input');
|
||||
|
||||
await page.fill('.search-input', '春');
|
||||
await page.waitForSelector('.search-suggestions');
|
||||
|
||||
const metrics = await measureComponentAnimation(page, '.search-suggestions');
|
||||
|
||||
console.log('搜索建议展开动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('搜索历史展开动画FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/pages/search/index');
|
||||
await page.waitForSelector('.search-history-btn');
|
||||
|
||||
const metrics = await measureComponentAnimation(page, '.search-history-btn');
|
||||
|
||||
console.log('搜索历史展开动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('搜索热门展开动画FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/pages/search/index');
|
||||
await page.waitForSelector('.search-hot-btn');
|
||||
|
||||
const metrics = await measureComponentAnimation(page, '.search-hot-btn');
|
||||
|
||||
console.log('搜索热门展开动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('用户设置展开动画FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/pages/user/index');
|
||||
await page.waitForSelector('.user-settings-btn');
|
||||
|
||||
const metrics = await measureComponentAnimation(page, '.user-settings-btn');
|
||||
|
||||
console.log('用户设置展开动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('组件动画掉帧数应小于5', async ({ page }) => {
|
||||
await page.goto('/pages/calendar/index');
|
||||
await page.waitForSelector('.calendar-next-month');
|
||||
|
||||
const metrics = await measureComponentAnimation(page, '.calendar-next-month');
|
||||
|
||||
console.log('组件动画掉帧数:', metrics.droppedFrames);
|
||||
|
||||
expect(metrics.droppedFrames).toBeLessThan(5);
|
||||
});
|
||||
|
||||
test('组件动画帧时间应小于33.33ms', async ({ page }) => {
|
||||
await page.goto('/pages/calendar/index');
|
||||
await page.waitForSelector('.calendar-next-month');
|
||||
|
||||
const metrics = await measureComponentAnimation(page, '.calendar-next-month');
|
||||
|
||||
console.log('组件动画帧时间:', metrics.frameTime);
|
||||
|
||||
expect(metrics.frameTime).toBeLessThan(ANIMATION_THRESHOLDS.frameTime);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('滚动动画性能测试', () => {
|
||||
test('日历列表滚动FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/pages/calendar/index');
|
||||
await page.waitForSelector('.calendar-container');
|
||||
|
||||
const metrics = await measureAnimationPerformance(page, async () => {
|
||||
await page.evaluate(() => {
|
||||
const container = document.querySelector('.calendar-container');
|
||||
if (container) {
|
||||
container.scrollTop = 500;
|
||||
}
|
||||
});
|
||||
}, 500);
|
||||
|
||||
console.log('日历列表滚动动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('黄历列表滚动FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/pages/almanac/index');
|
||||
await page.waitForSelector('.almanac-container');
|
||||
|
||||
const metrics = await measureAnimationPerformance(page, async () => {
|
||||
await page.evaluate(() => {
|
||||
const container = document.querySelector('.almanac-container');
|
||||
if (container) {
|
||||
container.scrollTop = 500;
|
||||
}
|
||||
});
|
||||
}, 500);
|
||||
|
||||
console.log('黄历列表滚动动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('搜索结果滚动FPS应大于30', async ({ page }) => {
|
||||
await page.goto('/pages/search/index');
|
||||
await page.waitForSelector('.search-input');
|
||||
|
||||
await page.fill('.search-input', '春节');
|
||||
await page.click('.search-btn');
|
||||
await page.waitForSelector('.search-results');
|
||||
|
||||
const metrics = await measureAnimationPerformance(page, async () => {
|
||||
await page.evaluate(() => {
|
||||
const container = document.querySelector('.search-results');
|
||||
if (container) {
|
||||
container.scrollTop = 500;
|
||||
}
|
||||
});
|
||||
}, 500);
|
||||
|
||||
console.log('搜索结果滚动动画指标:', metrics);
|
||||
|
||||
expect(metrics.fps).toBeGreaterThan(ANIMATION_THRESHOLDS.fps);
|
||||
});
|
||||
|
||||
test('滚动掉帧数应小于5', async ({ page }) => {
|
||||
await page.goto('/pages/calendar/index');
|
||||
await page.waitForSelector('.calendar-container');
|
||||
|
||||
const metrics = await measureAnimationPerformance(page, async () => {
|
||||
await page.evaluate(() => {
|
||||
const container = document.querySelector('.calendar-container');
|
||||
if (container) {
|
||||
container.scrollTop = 500;
|
||||
}
|
||||
});
|
||||
}, 500);
|
||||
|
||||
console.log('滚动掉帧数:', metrics.droppedFrames);
|
||||
|
||||
expect(metrics.droppedFrames).toBeLessThan(5);
|
||||
});
|
||||
|
||||
test('滚动帧时间应小于33.33ms', async ({ page }) => {
|
||||
await page.goto('/pages/calendar/index');
|
||||
await page.waitForSelector('.calendar-container');
|
||||
|
||||
const metrics = await measureAnimationPerformance(page, async () => {
|
||||
await page.evaluate(() => {
|
||||
const container = document.querySelector('.calendar-container');
|
||||
if (container) {
|
||||
container.scrollTop = 500;
|
||||
}
|
||||
});
|
||||
}, 500);
|
||||
|
||||
console.log('滚动帧时间:', metrics.frameTime);
|
||||
|
||||
expect(metrics.frameTime).toBeLessThan(ANIMATION_THRESHOLDS.frameTime);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user