test: add E2E tests for contact form security
This commit is contained in:
@@ -0,0 +1,254 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { ContactFormPage } from '../pages/ContactFormPage';
|
||||
|
||||
test.describe('Contact Form Security E2E Tests', () => {
|
||||
let contactPage: ContactFormPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
contactPage = new ContactFormPage(page);
|
||||
await contactPage.goto();
|
||||
});
|
||||
|
||||
test.describe('Captcha Functionality', () => {
|
||||
test('should display captcha question', async () => {
|
||||
const question = await contactPage.getCaptchaQuestion();
|
||||
expect(question).toMatch(/\d+\s*[+\-×÷]\s*\d+\s*=/);
|
||||
});
|
||||
|
||||
test('should refresh captcha when refresh button is clicked', async () => {
|
||||
const firstQuestion = await contactPage.getCaptchaQuestion();
|
||||
await contactPage.refreshCaptcha();
|
||||
const secondQuestion = await contactPage.getCaptchaQuestion();
|
||||
expect(secondQuestion).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should submit form with correct captcha', async ({ page }) => {
|
||||
const formData = {
|
||||
name: '张三',
|
||||
phone: '13800138000',
|
||||
email: 'test@example.com',
|
||||
message: '这是一条测试留言内容',
|
||||
};
|
||||
|
||||
await contactPage.submitForm(formData);
|
||||
|
||||
await expect(page).toHaveURL(/\/contact/);
|
||||
const successMessage = await contactPage.getSuccessMessage();
|
||||
expect(successMessage).toContain('成功');
|
||||
});
|
||||
|
||||
test('should show error for incorrect captcha', async ({ page }) => {
|
||||
const formData = {
|
||||
name: '张三',
|
||||
phone: '13800138000',
|
||||
email: 'test@example.com',
|
||||
message: '这是一条测试留言内容',
|
||||
};
|
||||
|
||||
await contactPage.fillForm(formData);
|
||||
await contactPage.captchaInput.fill('999');
|
||||
await contactPage.submit();
|
||||
|
||||
const captchaError = await contactPage.getCaptchaErrorMessage();
|
||||
expect(captchaError).toContain('验证码错误');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Form Validation', () => {
|
||||
test('should validate name field', async ({ page }) => {
|
||||
await contactPage.nameInput.fill('');
|
||||
await contactPage.nameInput.blur();
|
||||
|
||||
const errorMessage = await contactPage.getErrorMessage();
|
||||
expect(errorMessage).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should validate phone field', async ({ page }) => {
|
||||
await contactPage.phoneInput.fill('123');
|
||||
await contactPage.phoneInput.blur();
|
||||
|
||||
const errorMessage = await contactPage.getErrorMessage();
|
||||
expect(errorMessage).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should validate email field', async ({ page }) => {
|
||||
await contactPage.emailInput.fill('invalid-email');
|
||||
await contactPage.emailInput.blur();
|
||||
|
||||
const errorMessage = await contactPage.getErrorMessage();
|
||||
expect(errorMessage).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should validate message field', async ({ page }) => {
|
||||
await contactPage.messageInput.fill('太短');
|
||||
await contactPage.messageInput.blur();
|
||||
|
||||
const errorMessage = await contactPage.getErrorMessage();
|
||||
expect(errorMessage).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Security Features', () => {
|
||||
test('should prevent XSS attacks in form fields', async ({ page }) => {
|
||||
const xssPayload = '<script>alert("XSS")</script>';
|
||||
|
||||
await contactPage.nameInput.fill(xssPayload);
|
||||
await contactPage.messageInput.fill(xssPayload);
|
||||
await contactPage.solveCaptcha();
|
||||
await contactPage.submit();
|
||||
|
||||
await expect(page.locator('script')).not.toBeAttached();
|
||||
});
|
||||
|
||||
test('should handle SQL injection attempts', async ({ page }) => {
|
||||
const sqlPayload = "'; DROP TABLE users; --";
|
||||
|
||||
await contactPage.nameInput.fill(sqlPayload);
|
||||
await contactPage.messageInput.fill(sqlPayload);
|
||||
await contactPage.solveCaptcha();
|
||||
await contactPage.submit();
|
||||
|
||||
const successMessage = await contactPage.getSuccessMessage();
|
||||
expect(successMessage).toBeNull();
|
||||
});
|
||||
|
||||
test('should sanitize malicious content', async ({ page }) => {
|
||||
const maliciousContent = '<img src=x onerror=alert(1)>';
|
||||
|
||||
await contactPage.messageInput.fill(maliciousContent);
|
||||
await contactPage.solveCaptcha();
|
||||
await contactPage.submit();
|
||||
|
||||
await expect(page.locator('img[onerror]')).not.toBeAttached();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Rate Limiting', () => {
|
||||
test('should enforce rate limiting on rapid submissions', async ({ page }) => {
|
||||
const formData = {
|
||||
name: '张三',
|
||||
phone: '13800138000',
|
||||
email: 'test@example.com',
|
||||
message: '这是一条测试留言内容',
|
||||
};
|
||||
|
||||
let submissionCount = 0;
|
||||
let rateLimited = false;
|
||||
|
||||
for (let i = 0; i < 15; i++) {
|
||||
await contactPage.goto();
|
||||
await contactPage.fillForm(formData);
|
||||
await contactPage.solveCaptcha();
|
||||
await contactPage.submit();
|
||||
|
||||
const errorMessage = await contactPage.getErrorMessage();
|
||||
if (errorMessage && errorMessage.includes('过于频繁')) {
|
||||
rateLimited = true;
|
||||
break;
|
||||
}
|
||||
|
||||
submissionCount++;
|
||||
await page.waitForTimeout(100);
|
||||
}
|
||||
|
||||
expect(rateLimited).toBe(true);
|
||||
});
|
||||
|
||||
test('should allow submissions after rate limit window', async ({ page }) => {
|
||||
const formData = {
|
||||
name: '张三',
|
||||
phone: '13800138000',
|
||||
email: 'test@example.com',
|
||||
message: '这是一条测试留言内容',
|
||||
};
|
||||
|
||||
await contactPage.submitForm(formData);
|
||||
await page.waitForTimeout(61000);
|
||||
|
||||
await contactPage.goto();
|
||||
await contactPage.submitForm(formData);
|
||||
|
||||
const successMessage = await contactPage.getSuccessMessage();
|
||||
expect(successMessage).toContain('成功');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Accessibility', () => {
|
||||
test('should have proper form labels', async () => {
|
||||
await expect(contactPage.nameInput).toBeVisible();
|
||||
await expect(contactPage.phoneInput).toBeVisible();
|
||||
await expect(contactPage.emailInput).toBeVisible();
|
||||
await expect(contactPage.messageInput).toBeVisible();
|
||||
await expect(contactPage.captchaInput).toBeVisible();
|
||||
});
|
||||
|
||||
test('should be keyboard navigable', async ({ page }) => {
|
||||
await contactPage.nameInput.focus();
|
||||
await page.keyboard.press('Tab');
|
||||
await expect(contactPage.phoneInput).toBeFocused();
|
||||
|
||||
await page.keyboard.press('Tab');
|
||||
await expect(contactPage.emailInput).toBeFocused();
|
||||
|
||||
await page.keyboard.press('Tab');
|
||||
await expect(contactPage.messageInput).toBeFocused();
|
||||
|
||||
await page.keyboard.press('Tab');
|
||||
await expect(contactPage.captchaInput).toBeFocused();
|
||||
|
||||
await page.keyboard.press('Tab');
|
||||
await expect(contactPage.submitButton).toBeFocused();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Responsive Design', () => {
|
||||
test('should work on mobile devices', async ({ page }) => {
|
||||
await page.setViewportSize({ width: 375, height: 667 });
|
||||
await contactPage.goto();
|
||||
|
||||
await expect(contactPage.nameInput).toBeVisible();
|
||||
await expect(contactPage.submitButton).toBeVisible();
|
||||
});
|
||||
|
||||
test('should work on tablet devices', async ({ page }) => {
|
||||
await page.setViewportSize({ width: 768, height: 1024 });
|
||||
await contactPage.goto();
|
||||
|
||||
await expect(contactPage.nameInput).toBeVisible();
|
||||
await expect(contactPage.submitButton).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('User Flow', () => {
|
||||
test('should complete full contact form submission flow', async ({ page }) => {
|
||||
await test.step('Navigate to contact page', async () => {
|
||||
await contactPage.goto();
|
||||
await expect(page).toHaveURL(/\/contact/);
|
||||
});
|
||||
|
||||
await test.step('Fill in all required fields', async () => {
|
||||
const formData = {
|
||||
name: '李四',
|
||||
phone: '13900139000',
|
||||
email: 'lisi@example.com',
|
||||
message: '我想咨询贵公司的服务详情,请尽快联系我。',
|
||||
};
|
||||
await contactPage.fillForm(formData);
|
||||
});
|
||||
|
||||
await test.step('Solve captcha', async () => {
|
||||
await contactPage.solveCaptcha();
|
||||
});
|
||||
|
||||
await test.step('Submit form', async () => {
|
||||
await contactPage.submit();
|
||||
});
|
||||
|
||||
await test.step('Verify success message', async () => {
|
||||
await contactPage.waitForSuccessMessage();
|
||||
const successMessage = await contactPage.getSuccessMessage();
|
||||
expect(successMessage).toContain('成功');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user