feat: 修复测试套件问题并添加Woodpecker CI配置
- 修复API测试认证问题:创建全局认证设置,更新Playwright配置 - 优化回归测试稳定性:增加超时时间到15秒,修复定位器 - 创建Woodpecker CI工作流:CI、部署和质量门禁配置 - 添加Jest配置和测试脚本 - 移除登录页面的默认账号密码显示(安全问题修复)
This commit is contained in:
@@ -1,16 +1,20 @@
|
||||
import { Page } from '@playwright/test';
|
||||
import { CoreWebVitals } from '../../types';
|
||||
import { CoreWebVitals as CoreWebVitalsMetrics } from '../../types';
|
||||
|
||||
export class CoreWebVitals {
|
||||
constructor(private page: Page) {}
|
||||
|
||||
async measureLCP(): Promise<number> {
|
||||
return await this.page.evaluate(() => {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise<number>((resolve) => {
|
||||
new PerformanceObserver((list) => {
|
||||
const entries = list.getEntries();
|
||||
const lastEntry = entries[entries.length - 1];
|
||||
resolve(lastEntry.startTime);
|
||||
if (lastEntry) {
|
||||
resolve(lastEntry.startTime);
|
||||
} else {
|
||||
resolve(0);
|
||||
}
|
||||
}).observe({ type: 'largest-contentful-paint', buffered: true });
|
||||
});
|
||||
});
|
||||
@@ -18,11 +22,15 @@ export class CoreWebVitals {
|
||||
|
||||
async measureFID(): Promise<number> {
|
||||
return await this.page.evaluate(() => {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise<number>((resolve) => {
|
||||
new PerformanceObserver((list) => {
|
||||
const entries = list.getEntries();
|
||||
const firstEntry = entries[0];
|
||||
resolve(firstEntry.processingStart - firstEntry.startTime);
|
||||
const firstEntry = entries[0] as any;
|
||||
if (firstEntry) {
|
||||
resolve(firstEntry.processingStart - firstEntry.startTime);
|
||||
} else {
|
||||
resolve(0);
|
||||
}
|
||||
}).observe({ type: 'first-input', buffered: true });
|
||||
});
|
||||
});
|
||||
@@ -30,12 +38,12 @@ export class CoreWebVitals {
|
||||
|
||||
async measureCLS(): Promise<number> {
|
||||
return await this.page.evaluate(() => {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise<number>((resolve) => {
|
||||
let clsValue = 0;
|
||||
new PerformanceObserver((list) => {
|
||||
for (const entry of list.getEntries()) {
|
||||
if (!entry.hadRecentInput) {
|
||||
const value = entry.value;
|
||||
if (!(entry as any).hadRecentInput) {
|
||||
const value = (entry as any).value;
|
||||
clsValue = Math.max(clsValue, value);
|
||||
}
|
||||
}
|
||||
@@ -46,7 +54,7 @@ export class CoreWebVitals {
|
||||
});
|
||||
}
|
||||
|
||||
async measureAll(): Promise<CoreWebVitals> {
|
||||
async measureAll(): Promise<CoreWebVitalsMetrics> {
|
||||
const [lcp, fid, cls] = await Promise.all([
|
||||
this.measureLCP(),
|
||||
this.measureFID(),
|
||||
@@ -69,12 +77,14 @@ export class CoreWebVitals {
|
||||
|
||||
async measureFCP(): Promise<number> {
|
||||
return await this.page.evaluate(() => {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise<number>((resolve) => {
|
||||
new PerformanceObserver((list) => {
|
||||
const entries = list.getEntries();
|
||||
const fcpEntry = entries.find((entry: any) => entry.name === 'first-contentful-paint');
|
||||
if (fcpEntry) {
|
||||
resolve(fcpEntry.startTime);
|
||||
} else {
|
||||
resolve(0);
|
||||
}
|
||||
}).observe({ type: 'paint', buffered: true });
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ export class LighthouseRunner {
|
||||
|
||||
async runLighthouse(url: string): Promise<LighthouseResult> {
|
||||
const results = await this.page.evaluate(async () => {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise<LighthouseResult>((resolve) => {
|
||||
if (!(window as any).lighthouse) {
|
||||
resolve({
|
||||
performance: 0,
|
||||
@@ -46,7 +46,16 @@ export class LighthouseRunner {
|
||||
};
|
||||
}> {
|
||||
const results = await this.page.evaluate(async () => {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise<{
|
||||
score: number;
|
||||
metrics: {
|
||||
firstContentfulPaint: number;
|
||||
largestContentfulPaint: number;
|
||||
cumulativeLayoutShift: number;
|
||||
firstInputDelay: number;
|
||||
speedIndex: number;
|
||||
};
|
||||
}>((resolve) => {
|
||||
if (!(window as any).lighthouse) {
|
||||
resolve({
|
||||
score: 0,
|
||||
@@ -61,18 +70,17 @@ export class LighthouseRunner {
|
||||
return;
|
||||
}
|
||||
|
||||
(window as any).lighthouse(location.href, {
|
||||
(window as any).lighthouse(window.location.href, {
|
||||
onlyCategories: ['performance']
|
||||
}).then((result: any) => {
|
||||
const audits = result.audits;
|
||||
resolve({
|
||||
score: Math.round(result.categories.performance.score * 100),
|
||||
metrics: {
|
||||
firstContentfulPaint: audits['first-contentful-paint'].numericValue,
|
||||
largestContentfulPaint: audits['largest-contentful-paint'].numericValue,
|
||||
cumulativeLayoutShift: audits['cumulative-layout-shift'].numericValue,
|
||||
firstInputDelay: audits['max-potential-fid'].numericValue,
|
||||
speedIndex: audits['speed-index'].numericValue
|
||||
firstContentfulPaint: result.audits['first-contentful-paint'].numericValue,
|
||||
largestContentfulPaint: result.audits['largest-contentful-paint'].numericValue,
|
||||
cumulativeLayoutShift: result.audits['cumulative-layout-shift'].numericValue,
|
||||
firstInputDelay: result.audits['max-potential-fid'].numericValue,
|
||||
speedIndex: result.audits['speed-index'].numericValue
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user