feat: 完善ContactPage页面对象
- 添加错误消息定位器(nameError, emailError等) - 添加错误消息获取和可见性检查方法 - 添加安全测试辅助方法(testXSSInjection, testSQLInjection等) - 添加响应式布局验证方法 - 添加表单提交性能测量方法 - 添加可访问性属性验证方法 - 添加表单标签和必填字段验证方法 - 添加键盘导航验证方法
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user