diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..4b56fd0 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,8 @@ +export const config = { + emailJs: { + serviceId: import.meta.env.VITE_EMAILJS_SERVICE_ID, + templateIdAdmin: import.meta.env.VITE_EMAILJS_TEMPLATE_ID_ADMIN, + templateIdUser: import.meta.env.VITE_EMAILJS_TEMPLATE_ID_USER, + publicKey: import.meta.env.VITE_EMAILJS_PUBLIC_KEY, + }, +}; diff --git a/src/pages/Contact.tsx b/src/pages/Contact.tsx index 668a14a..e026327 100644 --- a/src/pages/Contact.tsx +++ b/src/pages/Contact.tsx @@ -2,15 +2,10 @@ import { useState, type FormEvent } from 'react'; import { motion } from 'motion/react'; import emailjs from '@emailjs/browser'; import { useTranslation } from '../i18n'; +import { config } from '../config'; import { Button, Input, Textarea } from '../components/ui'; import styles from './Contact.module.css'; -// EmailJS configuration -const EMAILJS_SERVICE_ID = import.meta.env.VITE_EMAILJS_SERVICE_ID; -const EMAILJS_TEMPLATE_ID_ADMIN = import.meta.env.VITE_EMAILJS_TEMPLATE_ID_ADMIN; -const EMAILJS_TEMPLATE_ID_USER = import.meta.env.VITE_EMAILJS_TEMPLATE_ID_USER; -const EMAILJS_PUBLIC_KEY = import.meta.env.VITE_EMAILJS_PUBLIC_KEY; - interface FormData { name: string; email: string; @@ -72,26 +67,26 @@ export function Contact() { try { const templateParams = { - from_name: formData.name, - from_email: formData.email, - subject: formData.subject, + name: formData.name, + email: formData.email, + title: formData.subject, message: formData.message, }; await Promise.all([ // Send to Admin emailjs.send( - EMAILJS_SERVICE_ID, - EMAILJS_TEMPLATE_ID_ADMIN, + config.emailJs.serviceId, + config.emailJs.templateIdAdmin, templateParams, - EMAILJS_PUBLIC_KEY + { publicKey: config.emailJs.publicKey } ), // Send Auto-reply to User emailjs.send( - EMAILJS_SERVICE_ID, - EMAILJS_TEMPLATE_ID_USER, + config.emailJs.serviceId, + config.emailJs.templateIdUser, templateParams, - EMAILJS_PUBLIC_KEY + { publicKey: config.emailJs.publicKey } ), ]); diff --git a/src/pages/__tests__/Contact.test.tsx b/src/pages/__tests__/Contact.test.tsx new file mode 100644 index 0000000..4dd0958 --- /dev/null +++ b/src/pages/__tests__/Contact.test.tsx @@ -0,0 +1,113 @@ + +// @vitest-environment jsdom +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { vi, describe, it, expect, beforeEach } from 'vitest'; +import { Contact } from '../Contact'; +import emailjs from '@emailjs/browser'; + +// Mock dependencies +vi.mock('@emailjs/browser', () => ({ + default: { + send: vi.fn().mockResolvedValue({ status: 200, text: 'OK' }), + }, +})); + +vi.mock('../../i18n', () => ({ + useTranslation: () => ({ + t: { + contact: { + title: 'Contact Us', + subtitle: 'Get in touch', + intro: 'Send us a message', + form: { + name: 'Name', + namePlaceholder: 'Your Name', + email: 'Email', + emailPlaceholder: 'Your Email', + subject: 'Subject', + subjectPlaceholder: 'Message Subject', + message: 'Message', + messagePlaceholder: 'Your Message', + submit: 'Send Message', + sending: 'Sending...', + success: 'Message sent successfully!', + error: 'Failed to send message.', + }, + info: { + title: 'Contact Info', + email: 'Email Us', + github: 'GitHub', + }, + }, + }, + }), +})); + +// Mock config +vi.mock('../../config', () => ({ + config: { + emailJs: { + serviceId: 'mock_service_id', + templateIdAdmin: 'mock_template_admin', + templateIdUser: 'mock_template_user', + publicKey: 'mock_public_key', + }, + }, +})); + +describe('Contact Page', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('submits the form with correct parameters', async () => { + render(); + + // Fill out the form + fireEvent.change(screen.getByLabelText('Name'), { target: { value: 'John Doe' } }); + fireEvent.change(screen.getByLabelText('Email'), { target: { value: 'john@example.com' } }); + fireEvent.change(screen.getByLabelText('Subject'), { target: { value: 'Test Subject' } }); + fireEvent.change(screen.getByLabelText('Message'), { target: { value: 'Hello world' } }); + + // Submit + fireEvent.click(screen.getByRole('button', { name: 'Send Message' })); + + // Wait for submission + await waitFor(() => { + expect(emailjs.send).toHaveBeenCalledTimes(2); + }); + + const expectedParams = { + name: 'John Doe', + email: 'john@example.com', + title: 'Test Subject', + message: 'Hello world', + }; + + const expectedOptions = { + publicKey: 'mock_public_key' + }; + + // Check first call (Admin) + expect(emailjs.send).toHaveBeenNthCalledWith( + 1, + 'mock_service_id', + 'mock_template_admin', + expectedParams, + expectedOptions + ); + + // Check second call (User) + expect(emailjs.send).toHaveBeenNthCalledWith( + 2, + 'mock_service_id', + 'mock_template_user', + expectedParams, + expectedOptions + ); + + // Verify success message + const successMessage = await screen.findByText('Message sent successfully!'); + expect(successMessage).toBeTruthy(); + }); +});