feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
This commit is contained in:
@@ -0,0 +1,352 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Web平台兼容性测试', () => {
|
||||
let baseUrl: string;
|
||||
|
||||
test.beforeAll(async () => {
|
||||
baseUrl = 'http://localhost:8081';
|
||||
});
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto(baseUrl);
|
||||
await page.waitForLoadState('networkidle');
|
||||
});
|
||||
|
||||
test.describe('TC-001: 页面加载测试', () => {
|
||||
test('应该能够加载页面', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const pageTitle = await page.title();
|
||||
expect(pageTitle).toBeTruthy();
|
||||
|
||||
const bodyContent = await page.evaluate(() => document.body.innerText);
|
||||
expect(bodyContent.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('页面应该正常显示', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const isPageVisible = await page.evaluate(() => {
|
||||
return document.visibilityState === 'visible';
|
||||
});
|
||||
|
||||
expect(isPageVisible).toBe(true);
|
||||
});
|
||||
|
||||
test('页面加载时不应该有错误提示', async ({ page }) => {
|
||||
const errors: string[] = [];
|
||||
|
||||
page.on('console', (msg) => {
|
||||
if (msg.type() === 'error') {
|
||||
errors.push(msg.text());
|
||||
}
|
||||
});
|
||||
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.waitForTimeout(1500);
|
||||
|
||||
const criticalErrors = errors.filter(e =>
|
||||
e.includes('TypeError') ||
|
||||
e.includes('ReferenceError') ||
|
||||
e.includes('SyntaxError')
|
||||
);
|
||||
|
||||
expect(criticalErrors.length).toBeLessThan(3);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('TC-002: CSS变量测试', () => {
|
||||
test('CSS变量应该正确设置', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
const cssVars = await page.evaluate(() => {
|
||||
const root = document.documentElement;
|
||||
const style = getComputedStyle(root);
|
||||
const properties = Array.from(style).filter(prop =>
|
||||
prop.includes('--') || prop.includes('theme')
|
||||
);
|
||||
return properties.length;
|
||||
});
|
||||
|
||||
expect(cssVars).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('CSS变量应该能够被继承和覆盖', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
const rootHasVars = await page.evaluate(() => {
|
||||
const root = document.documentElement;
|
||||
const style = getComputedStyle(root);
|
||||
const properties = Array.from(style).filter(prop =>
|
||||
prop.includes('--') || prop.includes('theme')
|
||||
);
|
||||
return properties.length > 0;
|
||||
});
|
||||
|
||||
const bodyHasVars = await page.evaluate(() => {
|
||||
const body = document.body;
|
||||
const style = getComputedStyle(body);
|
||||
const properties = Array.from(style).filter(prop =>
|
||||
prop.includes('--') || prop.includes('theme')
|
||||
);
|
||||
return properties.length > 0;
|
||||
});
|
||||
|
||||
expect(rootHasVars).toBe(true);
|
||||
expect(bodyHasVars).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('TC-003: 字体系统测试', () => {
|
||||
test('字体应该正确加载', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const fontsLoaded = await page.evaluate(() => {
|
||||
return document.fonts.ready.then(() => {
|
||||
return document.fonts.size > 0;
|
||||
});
|
||||
});
|
||||
|
||||
expect(fontsLoaded).toBe(true);
|
||||
});
|
||||
|
||||
test('字体大小应该正确应用', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const fontSize = await page.evaluate(() => {
|
||||
const body = document.body;
|
||||
const style = getComputedStyle(body);
|
||||
return style.fontSize;
|
||||
});
|
||||
|
||||
expect(fontSize).toBeTruthy();
|
||||
expect(fontSize).not.toBe('0px');
|
||||
});
|
||||
|
||||
test('字体粗细应该正确应用', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const fontWeight = await page.evaluate(() => {
|
||||
const body = document.body;
|
||||
const style = getComputedStyle(body);
|
||||
return style.fontWeight;
|
||||
});
|
||||
|
||||
expect(fontWeight).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('TC-004: SVG纹样测试', () => {
|
||||
test('SVG纹样应该正确显示', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const svgElements = await page.evaluate(() => {
|
||||
const svgs = document.querySelectorAll('svg');
|
||||
return svgs.length;
|
||||
});
|
||||
|
||||
expect(svgElements).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
test('SVG纹样应该能够缩放', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const svgElements = await page.evaluate(() => {
|
||||
const svgs = document.querySelectorAll('svg');
|
||||
return Array.from(svgs).map(svg => {
|
||||
const style = getComputedStyle(svg);
|
||||
return {
|
||||
width: style.width,
|
||||
height: style.height
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
expect(svgElements.length).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
test('SVG纹样应该能够应用颜色', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const svgElements = await page.evaluate(() => {
|
||||
const svgs = document.querySelectorAll('svg');
|
||||
return Array.from(svgs).map(svg => {
|
||||
const style = getComputedStyle(svg);
|
||||
return style.fill;
|
||||
});
|
||||
});
|
||||
|
||||
expect(svgElements.length).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('TC-005: 动画效果测试', () => {
|
||||
test('动画应该正常播放', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const animatedElements = await page.evaluate(() => {
|
||||
const elements = document.querySelectorAll('*');
|
||||
return Array.from(elements).filter(el => {
|
||||
const style = getComputedStyle(el);
|
||||
return style.animationName !== 'none' ||
|
||||
style.transitionProperty !== 'none';
|
||||
}).length;
|
||||
});
|
||||
|
||||
expect(animatedElements).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
test('动画应该流畅无卡顿', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const startTime = Date.now();
|
||||
await page.evaluate(() => {
|
||||
return new Promise(resolve => setTimeout(resolve, 1000));
|
||||
});
|
||||
const endTime = Date.now();
|
||||
|
||||
expect(endTime - startTime).toBeLessThan(2000);
|
||||
});
|
||||
|
||||
test('动画性能应该良好', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const performanceMetrics = await page.evaluate(() => {
|
||||
if (window.performance && window.performance.memory) {
|
||||
return {
|
||||
usedJSHeapSize: window.performance.memory.usedJSHeapSize,
|
||||
totalJSHeapSize: window.performance.memory.totalJSHeapSize
|
||||
};
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
expect(performanceMetrics).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('TC-006: 组件样式测试', () => {
|
||||
test('日历组件样式应该正确应用', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const calendarElements = await page.evaluate(() => {
|
||||
const elements = document.querySelectorAll('[class*="calendar"], [class*="Calendar"]');
|
||||
return elements.length;
|
||||
});
|
||||
|
||||
expect(calendarElements).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
test('导航组件样式应该正确应用', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const navElements = await page.evaluate(() => {
|
||||
const elements = document.querySelectorAll('[class*="nav"], [class*="Nav"]');
|
||||
return elements.length;
|
||||
});
|
||||
|
||||
expect(navElements).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
test('卡片组件样式应该正确应用', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const cardElements = await page.evaluate(() => {
|
||||
const elements = document.querySelectorAll('[class*="card"], [class*="Card"]');
|
||||
return elements.length;
|
||||
});
|
||||
|
||||
expect(cardElements).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('TC-007: 页面样式测试', () => {
|
||||
test('日历页面样式应该正确应用', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const pageContent = await page.evaluate(() => {
|
||||
const body = document.body;
|
||||
const style = getComputedStyle(body);
|
||||
return {
|
||||
backgroundColor: style.backgroundColor,
|
||||
color: style.color
|
||||
};
|
||||
});
|
||||
|
||||
expect(pageContent.backgroundColor).toBeTruthy();
|
||||
expect(pageContent.color).toBeTruthy();
|
||||
});
|
||||
|
||||
test('页面布局应该正常', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const pageLayout = await page.evaluate(() => {
|
||||
const body = document.body;
|
||||
const style = getComputedStyle(body);
|
||||
return {
|
||||
width: style.width,
|
||||
height: style.height,
|
||||
display: style.display
|
||||
};
|
||||
});
|
||||
|
||||
expect(pageLayout.width).toBeTruthy();
|
||||
expect(pageLayout.height).toBeTruthy();
|
||||
});
|
||||
|
||||
test('页面响应式应该正常', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
await page.setViewportSize({ width: 375, height: 667 });
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const mobileLayout = await page.evaluate(() => {
|
||||
const body = document.body;
|
||||
const style = getComputedStyle(body);
|
||||
return {
|
||||
width: style.width,
|
||||
display: style.display
|
||||
};
|
||||
});
|
||||
|
||||
expect(mobileLayout.width).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('TC-008: 功能测试', () => {
|
||||
test('日历功能应该正常', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const calendarExists = await page.evaluate(() => {
|
||||
const elements = document.querySelectorAll('[class*="calendar"], [class*="Calendar"]');
|
||||
return elements.length > 0;
|
||||
});
|
||||
|
||||
expect(calendarExists).toBe(true);
|
||||
});
|
||||
|
||||
test('导航功能应该正常', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const navExists = await page.evaluate(() => {
|
||||
const elements = document.querySelectorAll('[class*="nav"], [class*="Nav"]');
|
||||
return elements.length > 0;
|
||||
});
|
||||
|
||||
expect(navExists).toBe(true);
|
||||
});
|
||||
|
||||
test('用户界面应该正常', async ({ page }) => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const userInterfaceExists = await page.evaluate(() => {
|
||||
const body = document.body;
|
||||
return body.innerText.length > 0;
|
||||
});
|
||||
|
||||
expect(userInterfaceExists).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user