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:
google-labs-jules[bot]
2026-01-24 10:05:33 +00:00
parent 77fd62447c
commit 6801682c2e
4 changed files with 98 additions and 6 deletions

View File

@@ -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: '&lt;script&gt;alert(1)&lt;/script&gt;',
email: 'john@example.com',
title: '&lt;b&gt;Bold&lt;/b&gt;',
message: '&quot;Quotes&quot;',
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();
});
});