feat: 完善ContactPage页面对象
- 添加错误消息定位器(nameError, emailError等) - 添加错误消息获取和可见性检查方法 - 添加安全测试辅助方法(testXSSInjection, testSQLInjection等) - 添加响应式布局验证方法 - 添加表单提交性能测量方法 - 添加可访问性属性验证方法 - 添加表单标签和必填字段验证方法 - 添加键盘导航验证方法
This commit is contained in:
@@ -23,6 +23,11 @@ export class ContactPage extends BasePage {
|
|||||||
readonly phoneInfo: Locator;
|
readonly phoneInfo: Locator;
|
||||||
readonly emailInfo: Locator;
|
readonly emailInfo: Locator;
|
||||||
|
|
||||||
|
readonly nameError: Locator;
|
||||||
|
readonly emailError: Locator;
|
||||||
|
readonly phoneError: Locator;
|
||||||
|
readonly messageError: Locator;
|
||||||
|
|
||||||
constructor(page: Page) {
|
constructor(page: Page) {
|
||||||
super(page);
|
super(page);
|
||||||
this.url = '/contact';
|
this.url = '/contact';
|
||||||
@@ -44,6 +49,11 @@ export class ContactPage extends BasePage {
|
|||||||
this.addressInfo = this.contactInfoCard.locator('text=公司地址');
|
this.addressInfo = this.contactInfoCard.locator('text=公司地址');
|
||||||
this.phoneInfo = this.contactInfoCard.locator('text=联系电话');
|
this.phoneInfo = this.contactInfoCard.locator('text=联系电话');
|
||||||
this.emailInfo = 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 {
|
get breadcrumb(): Locator {
|
||||||
@@ -336,4 +346,201 @@ export class ContactPage extends BasePage {
|
|||||||
}
|
}
|
||||||
return workHours;
|
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