Shield: Add input sanitization and length validation to Contact form
Added `sanitizeInput` utility to escape HTML characters. Updated `Contact.tsx` to sanitize inputs before sending via `emailjs`. Added max length validation for Name (100), Subject (200), and Message (5000). Updated tests to cover sanitization and validation logic, including adding `cleanup()` to prevent test leakage.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
|
||||
// @vitest-environment jsdom
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||
import { render, screen, fireEvent, waitFor, cleanup } from '@testing-library/react';
|
||||
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { Contact } from '../Contact';
|
||||
import emailjs from '@emailjs/browser';
|
||||
|
||||
@@ -60,6 +60,11 @@ describe('Contact Page', () => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
document.body.innerHTML = '';
|
||||
});
|
||||
|
||||
it('submits the form with correct parameters', async () => {
|
||||
render(<Contact />);
|
||||
|
||||
@@ -111,4 +116,58 @@ describe('Contact Page', () => {
|
||||
const successMessage = await screen.findByText('Message sent successfully!');
|
||||
expect(successMessage).toBeTruthy();
|
||||
});
|
||||
|
||||
it('sanitizes input before sending', async () => {
|
||||
render(<Contact />);
|
||||
|
||||
// Fill out with malicious input
|
||||
fireEvent.change(screen.getByLabelText('Name'), { target: { value: '<script>alert(1)</script>' } });
|
||||
fireEvent.change(screen.getByLabelText('Email'), { target: { value: 'john@example.com' } });
|
||||
fireEvent.change(screen.getByLabelText('Subject'), { target: { value: '<b>Bold</b>' } });
|
||||
fireEvent.change(screen.getByLabelText('Message'), { target: { value: '"Quotes"' } });
|
||||
|
||||
// Submit
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Send Message' }));
|
||||
|
||||
// Wait for submission
|
||||
await waitFor(() => {
|
||||
expect(emailjs.send).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
const expectedParams = {
|
||||
name: '<script>alert(1)</script>',
|
||||
email: 'john@example.com',
|
||||
title: '<b>Bold</b>',
|
||||
message: '"Quotes"',
|
||||
reply_to: 'john@example.com',
|
||||
};
|
||||
|
||||
// Check first call
|
||||
expect(emailjs.send).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.any(String),
|
||||
expectedParams,
|
||||
expect.any(Object)
|
||||
);
|
||||
});
|
||||
|
||||
it('shows error when input exceeds max length', async () => {
|
||||
render(<Contact />);
|
||||
|
||||
// Create a long string (101 characters)
|
||||
const longName = 'a'.repeat(101);
|
||||
|
||||
// Fill out the form
|
||||
fireEvent.change(screen.getByLabelText('Name'), { target: { value: longName } });
|
||||
|
||||
// Submit
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Send Message' }));
|
||||
|
||||
// Validation error should appear
|
||||
const errorMessage = await screen.findByText('Max 100 characters');
|
||||
expect(errorMessage).toBeTruthy();
|
||||
|
||||
// EmailJS should NOT be called
|
||||
expect(emailjs.send).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user