Skip to content

Commit 3fa763a

Browse files
Enhance form validation and submission feedback in the API and UI components
1 parent 55c8672 commit 3fa763a

File tree

3 files changed

+210
-40
lines changed

3 files changed

+210
-40
lines changed

src/app/api/submit/route.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
// import { NextResponse } from 'next/server';
2+
3+
// export async function POST(req: Request) {
4+
// try {
5+
// const { name, email } = await req.json();
6+
7+
// if (!name || !email) {
8+
// return NextResponse.json({ message: 'Name and Email are required' }, { status: 400 });
9+
// }
10+
11+
// return NextResponse.json({ message: `Thank you, ${name}!` });
12+
// } catch {
13+
// return NextResponse.json({ message: 'Server error' }, { status: 500 });
14+
// }
15+
// }
16+
117
import { NextResponse } from 'next/server';
218

319
export async function POST(req: Request) {
@@ -8,8 +24,8 @@ export async function POST(req: Request) {
824
return NextResponse.json({ message: 'Name and Email are required' }, { status: 400 });
925
}
1026

11-
return NextResponse.json({ message: `Thank you, ${name}!` });
27+
return NextResponse.json({ message: `Hello ${name}, your form has been submitted successfully!` });
1228
} catch {
13-
return NextResponse.json({ message: 'Server error' }, { status: 500 });
29+
return NextResponse.json({ message: 'Internal server error' }, { status: 500 });
1430
}
1531
}

src/app/form/page.tsx

Lines changed: 109 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,118 @@
1+
// 'use client';
2+
3+
// import { useState } from 'react';
4+
5+
// export default function Form() {
6+
// const [name, setName] = useState('');
7+
// const [email, setEmail] = useState('');
8+
// const [message, setMessage] = useState('');
9+
// const [loading, setLoading] = useState(false);
10+
// const [error, setError] = useState('');
11+
12+
// const handleSubmit = async (e: React.FormEvent) => {
13+
// e.preventDefault();
14+
// setLoading(true);
15+
// setMessage('');
16+
// setError('');
17+
18+
// try {
19+
// const res = await fetch('/api/submit', {
20+
// method: 'POST',
21+
// headers: { 'Content-Type': 'application/json' },
22+
// body: JSON.stringify({ name, email }),
23+
// });
24+
25+
// if (!res.ok) throw new Error('Failed to submit');
26+
// const data = await res.json();
27+
// setMessage(data.message);
28+
// } catch {
29+
// setError('Submission failed. Please try again.');
30+
// } finally {
31+
// setLoading(false);
32+
// }
33+
// };
34+
35+
// const handleReset = () => {
36+
// setName('');
37+
// setEmail('');
38+
// setMessage('');
39+
// setError('');
40+
// };
41+
42+
// return (
43+
// <div>
44+
// <h1>Form Page</h1>
45+
// <form onSubmit={handleSubmit}>
46+
// <input
47+
// type="text"
48+
// placeholder="Enter your name"
49+
// value={name}
50+
// onChange={(e) => setName(e.target.value)}
51+
// />
52+
// <input
53+
// type="email"
54+
// placeholder="Enter your email"
55+
// value={email}
56+
// onChange={(e) => setEmail(e.target.value)}
57+
// />
58+
// <button type="submit" disabled={loading}>
59+
// {loading ? 'Submitting...' : 'Submit'}
60+
// </button>
61+
// <button type="button" onClick={handleReset}>Reset</button>
62+
// </form>
63+
// {message && <p style={{ color: 'green' }}>{message}</p>}
64+
// {error && <p style={{ color: 'red' }}>{error}</p>}
65+
// </div>
66+
// );
67+
// }
68+
69+
170
'use client';
271

372
import { useState } from 'react';
473

574
export default function Form() {
6-
const [name, setName] = useState('');
7-
const [email, setEmail] = useState('');
75+
const [formData, setFormData] = useState({ name: '', email: '' });
876
const [message, setMessage] = useState('');
977
const [loading, setLoading] = useState(false);
1078
const [error, setError] = useState('');
1179

80+
const validateInputs = () => {
81+
if (!formData.name.trim() || !formData.email.trim()) {
82+
setError('Both Name and Email are required');
83+
return false;
84+
}
85+
if (formData.name.length > 50) {
86+
setError('Name must be 50 characters or less');
87+
return false;
88+
}
89+
if (!/\S+@\S+\.\S+/.test(formData.email)) {
90+
setError('Invalid email format');
91+
return false;
92+
}
93+
return true;
94+
};
95+
96+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
97+
setFormData({ ...formData, [e.target.name]: e.target.value });
98+
};
99+
12100
const handleSubmit = async (e: React.FormEvent) => {
13101
e.preventDefault();
14102
setLoading(true);
15103
setMessage('');
16104
setError('');
17-
105+
106+
if (!validateInputs()) {
107+
setLoading(false);
108+
return;
109+
}
110+
18111
try {
19112
const res = await fetch('/api/submit', {
20113
method: 'POST',
21114
headers: { 'Content-Type': 'application/json' },
22-
body: JSON.stringify({ name, email }),
115+
body: JSON.stringify(formData),
23116
});
24117

25118
if (!res.ok) throw new Error('Failed to submit');
@@ -33,35 +126,34 @@ export default function Form() {
33126
};
34127

35128
const handleReset = () => {
36-
setName('');
37-
setEmail('');
129+
setFormData({ name: '', email: '' });
38130
setMessage('');
39131
setError('');
40132
};
41133

42134
return (
43-
<div>
135+
<div style={{ maxWidth: '400px', margin: 'auto', padding: '20px', border: '1px solid #ccc', borderRadius: '8px' }}>
44136
<h1>Form Page</h1>
45-
<form onSubmit={handleSubmit}>
137+
<form onSubmit={handleSubmit} noValidate>
46138
<input
47139
type="text"
140+
name="name"
48141
placeholder="Enter your name"
49-
value={name}
50-
onChange={(e) => setName(e.target.value)}
142+
value={formData.name}
143+
onChange={handleChange}
51144
/>
52145
<input
53146
type="email"
147+
name="email"
54148
placeholder="Enter your email"
55-
value={email}
56-
onChange={(e) => setEmail(e.target.value)}
149+
value={formData.email}
150+
onChange={handleChange}
57151
/>
58-
<button type="submit" disabled={loading}>
59-
{loading ? 'Submitting...' : 'Submit'}
60-
</button>
152+
<button type="submit">{loading ? 'Submitting...' : 'Submit'}</button>
61153
<button type="button" onClick={handleReset}>Reset</button>
62154
</form>
63-
{message && <p style={{ color: 'green' }}>{message}</p>}
64-
{error && <p style={{ color: 'red' }}>{error}</p>}
155+
<p id="error" style={{ color: 'red', visibility: error ? 'visible' : 'hidden' }}>{error}</p>
156+
<p id="message" style={{ color: 'green', visibility: message ? 'visible' : 'hidden' }}>{message}</p>
65157
</div>
66158
);
67159
}

tests/form.spec.ts

Lines changed: 83 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,93 @@
1+
// import { test, expect } from '@playwright/test';
2+
3+
// test('Form submission works correctly', async ({ page }) => {
4+
// await page.goto('/form');
5+
6+
// // Ensure form elements are present
7+
// await expect(page.locator('input[placeholder="Enter your name"]')).toBeVisible();
8+
// await expect(page.locator('input[placeholder="Enter your email"]')).toBeVisible();
9+
// await expect(page.locator('button[type="submit"]')).toHaveText('Submit');
10+
11+
// // Fill out the form
12+
// await page.fill('input[placeholder="Enter your name"]', 'John Doe');
13+
// await page.fill('input[placeholder="Enter your email"]', '[email protected]');
14+
15+
// // Submit the form
16+
// await page.click('button[type="submit"]');
17+
18+
// // Wait for success message
19+
// await expect(page.locator('p')).toHaveText('Thank you, John Doe!');
20+
// });
21+
22+
// test('Shows validation error if fields are missing', async ({ page }) => {
23+
// await page.goto('/form');
24+
25+
// // Try to submit without filling anything
26+
// await page.click('button[type="submit"]');
27+
28+
// // Expect an error message
29+
// await expect(page.locator('p')).toHaveText('Submission failed. Please try again.');
30+
// });
31+
132
import { test, expect } from '@playwright/test';
233

3-
test('Form submission works correctly', async ({ page }) => {
4-
await page.goto('/form');
34+
test.describe('Form Submission Tests', () => {
35+
test('✅ Form submission works correctly', async ({ page }) => {
36+
await page.goto('/form');
537

6-
// Ensure form elements are present
7-
await expect(page.locator('input[placeholder="Enter your name"]')).toBeVisible();
8-
await expect(page.locator('input[placeholder="Enter your email"]')).toBeVisible();
9-
await expect(page.locator('button[type="submit"]')).toHaveText('Submit');
38+
// Check form elements exist
39+
await expect(page.locator('input[name="name"]')).toBeVisible();
40+
await expect(page.locator('input[name="email"]')).toBeVisible();
41+
await expect(page.locator('button[type="submit"]')).toHaveText('Submit');
1042

11-
// Fill out the form
12-
await page.fill('input[placeholder="Enter your name"]', 'John Doe');
13-
await page.fill('input[placeholder="Enter your email"]', '[email protected]');
43+
// Fill out the form
44+
await page.fill('input[name="name"]', 'John Doe');
45+
await page.fill('input[name="email"]', '[email protected]');
1446

15-
// Submit the form
16-
await page.click('button[type="submit"]');
47+
// Submit the form
48+
await page.click('button[type="submit"]');
1749

18-
// Wait for success message
19-
await expect(page.locator('p')).toHaveText('Thank you, John Doe!');
20-
});
50+
// Expect success message
51+
await expect(page.locator('#message')).toHaveText(`Hello John Doe, your form has been submitted successfully!`);
52+
});
2153

22-
test('Shows validation error if fields are missing', async ({ page }) => {
23-
await page.goto('/form');
54+
test('Shows validation error if fields are missing', async ({ page }) => {
55+
await page.goto('/form');
2456

25-
// Try to submit without filling anything
26-
await page.click('button[type="submit"]');
57+
// Click submit without filling anything
58+
await page.click('button[type="submit"]');
2759

28-
// Expect an error message
29-
await expect(page.locator('p')).toHaveText('Submission failed. Please try again.');
30-
});
60+
// Expect validation error
61+
await expect(page.locator('#error')).toHaveText('Both Name and Email are required');
62+
});
63+
64+
test('❌ Shows validation error for invalid email', async ({ page }) => {
65+
await page.goto('/form');
66+
67+
// Fill in the name field
68+
await page.fill('input[name="name"]', 'John Doe');
69+
// Enter an invalid email
70+
await page.fill('input[name="email"]', 'invalid-email');
71+
72+
// Submit the form
73+
await page.click('button[type="submit"]');
74+
75+
// Expect email validation error
76+
await expect(page.locator('#error')).toHaveText('Invalid email format');
77+
});
3178

79+
test('🔄 Reset button clears the form', async ({ page }) => {
80+
await page.goto('/form');
81+
82+
// Fill out the form
83+
await page.fill('input[name="name"]', 'John Doe');
84+
await page.fill('input[name="email"]', '[email protected]');
85+
86+
// Click reset
87+
await page.click('button[type="button"]');
88+
89+
// Expect fields to be cleared
90+
await expect(page.locator('input[name="name"]')).toHaveValue('');
91+
await expect(page.locator('input[name="email"]')).toHaveValue('');
92+
});
93+
});

0 commit comments

Comments
 (0)