feat: 完善ContactPage页面对象

- 添加错误消息定位器(nameError, emailError等)
- 添加错误消息获取和可见性检查方法
- 添加安全测试辅助方法(testXSSInjection, testSQLInjection等)
- 添加响应式布局验证方法
- 添加表单提交性能测量方法
- 添加可访问性属性验证方法
- 添加表单标签和必填字段验证方法
- 添加键盘导航验证方法
This commit is contained in:
张翔
2026-02-28 15:23:10 +08:00
parent 6270047221
commit 43184c5c45
+207
View File
@@ -23,6 +23,11 @@ export class ContactPage extends BasePage {
readonly phoneInfo: Locator;
readonly emailInfo: Locator;
readonly nameError: Locator;
readonly emailError: Locator;
readonly phoneError: Locator;
readonly messageError: Locator;
constructor(page: Page) {
super(page);
this.url = '/contact';
@@ -44,6 +49,11 @@ export class ContactPage extends BasePage {
this.addressInfo = this.contactInfoCard.locator('text=公司地址');
this.phoneInfo = this.contactInfoCard.locator('text=联系电话');
this.emailInfo = this.contactInfoCard.locator('text=电子邮箱');
this.nameError = page.locator('input[name="name"] + .error-message, input[name="name"] ~ .text-destructive').first();
this.emailError = page.locator('input[name="email"] + .error-message, input[name="email"] ~ .text-destructive').first();
this.phoneError = page.locator('input[name="phone"] + .error-message, input[name="phone"] ~ .text-destructive').first();
this.messageError = page.locator('textarea[name="message"] + .error-message, textarea[name="message"] ~ .text-destructive').first();
}
get breadcrumb(): Locator {
@@ -336,4 +346,201 @@ export class ContactPage extends BasePage {
}
return workHours;
}
async getNameError(): Promise<string> {
return await this.nameError.textContent() || '';
}
async getEmailError(): Promise<string> {
return await this.emailError.textContent() || '';
}
async getPhoneError(): Promise<string> {
return await this.phoneError.textContent() || '';
}
async getMessageError(): Promise<string> {
return await this.messageError.textContent() || '';
}
async isNameErrorVisible(): Promise<boolean> {
return await this.nameError.isVisible();
}
async isEmailErrorVisible(): Promise<boolean> {
return await this.emailError.isVisible();
}
async isPhoneErrorVisible(): Promise<boolean> {
return await this.phoneError.isVisible();
}
async isMessageErrorVisible(): Promise<boolean> {
return await this.messageError.isVisible();
}
async testXSSInjection(payload: string): Promise<void> {
await this.fillContactForm({
name: payload,
email: 'test@example.com',
phone: '13800138000',
message: payload,
});
await this.submitForm();
}
async testSQLInjection(payload: string): Promise<void> {
await this.fillContactForm({
name: payload,
email: payload,
phone: payload,
message: payload,
});
await this.submitForm();
}
async testPathTraversal(payload: string): Promise<void> {
await this.fillContactForm({
name: payload,
email: 'test@example.com',
phone: '13800138000',
message: payload,
});
await this.submitForm();
}
async verifyFormResponsiveLayout(viewport: { width: number; height: number }): Promise<{
isFormVisible: boolean;
isSubmitButtonVisible: boolean;
isContactInfoVisible: boolean;
}> {
await this.page.setViewportSize(viewport);
await this.waitForTimeout(500);
return {
isFormVisible: await this.isFormVisible(),
isSubmitButtonVisible: await this.isVisible(this.submitButton),
isContactInfoVisible: await this.isContactInfoCardVisible(),
};
}
async measureFormSubmissionPerformance(): Promise<{
fillTime: number;
submitTime: number;
totalTime: number;
}> {
const startTime = Date.now();
const data = {
name: '测试用户',
email: 'test@example.com',
phone: '13800138000',
message: '这是一条测试消息',
};
const fillStartTime = Date.now();
await this.fillContactForm(data);
const fillTime = Date.now() - fillStartTime;
const submitStartTime = Date.now();
await this.submitForm();
await this.waitForFormSubmission();
const submitTime = Date.now() - submitStartTime;
const totalTime = Date.now() - startTime;
return {
fillTime,
submitTime,
totalTime,
};
}
async getFormAccessibilityAttributes(): Promise<{
nameAriaLabel: string | null;
emailAriaLabel: string | null;
phoneAriaLabel: string | null;
messageAriaLabel: string | null;
submitAriaLabel: string | null;
}> {
return {
nameAriaLabel: await this.nameInput.getAttribute('aria-label'),
emailAriaLabel: await this.emailInput.getAttribute('aria-label'),
phoneAriaLabel: await this.phoneInput.getAttribute('aria-label'),
messageAriaLabel: await this.messageInput.getAttribute('aria-label'),
submitAriaLabel: await this.submitButton.getAttribute('aria-label'),
};
}
async verifyFormLabels(): Promise<{
nameLabel: string | null;
emailLabel: string | null;
phoneLabel: string | null;
messageLabel: string | null;
}> {
return {
nameLabel: await this.page.locator('label[for="name"]').textContent(),
emailLabel: await this.page.locator('label[for="email"]').textContent(),
phoneLabel: await this.page.locator('label[for="phone"]').textContent(),
messageLabel: await this.page.locator('label[for="message"]').textContent(),
};
}
async getFormInputTypes(): Promise<{
nameType: string | null;
emailType: string | null;
phoneType: string | null;
subjectType: string | null;
}> {
return {
nameType: await this.nameInput.getAttribute('type'),
emailType: await this.emailInput.getAttribute('type'),
phoneType: await this.phoneInput.getAttribute('type'),
subjectType: await this.subjectInput.getAttribute('type'),
};
}
async verifyRequiredFields(): Promise<{
nameRequired: boolean;
emailRequired: boolean;
phoneRequired: boolean;
messageRequired: boolean;
}> {
return {
nameRequired: await this.nameInput.getAttribute('required') !== null,
emailRequired: await this.emailInput.getAttribute('required') !== null,
phoneRequired: await this.phoneInput.getAttribute('required') !== null,
messageRequired: await this.messageInput.getAttribute('required') !== null,
};
}
async getFormAutocompleteAttributes(): Promise<{
nameAutocomplete: string | null;
emailAutocomplete: string | null;
phoneAutocomplete: string | null;
}> {
return {
nameAutocomplete: await this.nameInput.getAttribute('autocomplete'),
emailAutocomplete: await this.emailInput.getAttribute('autocomplete'),
phoneAutocomplete: await this.phoneInput.getAttribute('autocomplete'),
};
}
async verifyKeyboardNavigation(): Promise<void> {
await this.nameInput.focus();
await this.pressKey('Tab');
await this.pressKey('Tab');
await this.pressKey('Tab');
await this.pressKey('Tab');
await this.pressKey('Tab');
}
async isFormKeyboardAccessible(): Promise<boolean> {
try {
await this.verifyKeyboardNavigation();
return true;
} catch {
return false;
}
}
}