From 6c9b06b98311380bef7271eb3eb542cebe105572 Mon Sep 17 00:00:00 2001 From: Philippe Torrel Date: Fri, 6 Nov 2026 10:57:46 +0100 Subject: [PATCH] --- ...debugging-multi-step-form-template-new.zip | Bin 0 -> 126543 bytes .../.gitignore | 24 +++ .../.oxlintrc.json | 8 + .../README.md | 19 ++ .../index.html | 13 ++ .../package.json | 37 ++++ .../public/favicon.svg | 1 + .../public/icons.svg | 24 +++ .../src/App.jsx | 12 ++ .../src/MultiStepForm.jsx | 125 +++++++++++++ .../src/components/FormCheckboxes.jsx | 44 +++++ .../src/components/FormInput.jsx | 47 +++++ .../src/components/FormSelect.jsx | 44 +++++ .../src/components/NavigationButtons.jsx | 43 +++++ .../src/components/ProgressIndicator.jsx | 33 ++++ .../src/index.css | 2 + .../src/main.jsx | 10 + .../src/steps/AccountInfo.jsx | 60 ++++++ .../src/steps/ActivityInfo.jsx | 45 +++++ .../src/steps/GoalSetting.jsx | 65 +++++++ .../src/utils/validation.js | 96 ++++++++++ .../tests/validation/step1.test.jsx | 125 +++++++++++++ .../tests/validation/step2.test.jsx | 114 ++++++++++++ .../tests/validation/step3.test.jsx | 173 ++++++++++++++++++ .../tests/validation/utility.test.js | 58 ++++++ .../vite.config.js | 13 ++ .../vitest.config.js | 9 + .../debugging-multi-step-form-template.zip | Bin 0 -> 37445 bytes .../.gitignore | 24 +++ .../README.md | 132 +++++++++++++ .../eslint.config.js | 38 ++++ .../index.html | 13 ++ .../package.json | 42 +++++ .../postcss.config.js | 6 + .../public/vite.svg | 1 + .../src/App.jsx | 12 ++ .../src/MultiStepForm.jsx | 125 +++++++++++++ .../src/components/FormCheckboxes.jsx | 44 +++++ .../src/components/FormInput.jsx | 47 +++++ .../src/components/FormSelect.jsx | 44 +++++ .../src/components/NavigationButtons.jsx | 43 +++++ .../src/components/ProgressIndicator.jsx | 33 ++++ .../src/index.css | 3 + .../src/main.jsx | 10 + .../src/steps/AccountInfo.jsx | 60 ++++++ .../src/steps/ActivityInfo.jsx | 45 +++++ .../src/steps/GoalSetting.jsx | 64 +++++++ .../src/utils/validation.js | 96 ++++++++++ .../tailwind.config.js | 8 + .../tests/validation/step1.test.jsx | 125 +++++++++++++ .../tests/validation/step2.test.jsx | 114 ++++++++++++ .../tests/validation/step3.test.jsx | 139 ++++++++++++++ .../tests/validation/utility.test.js | 58 ++++++ .../vite.config.js | 7 + .../vitest.config.js | 9 + 55 files changed, 2586 insertions(+) create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new.zip create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/.gitignore create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/.oxlintrc.json create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/README.md create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/index.html create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/package.json create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/public/favicon.svg create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/public/icons.svg create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/src/App.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/src/MultiStepForm.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/src/components/FormCheckboxes.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/src/components/FormInput.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/src/components/FormSelect.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/src/components/NavigationButtons.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/src/components/ProgressIndicator.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/src/index.css create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/src/main.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/src/steps/AccountInfo.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/src/steps/ActivityInfo.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/src/steps/GoalSetting.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/src/utils/validation.js create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/step1.test.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/step2.test.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/step3.test.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/utility.test.js create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/vite.config.js create mode 100644 07_js-debug/projects/debugging-multi-step-form-template-new/vitest.config.js create mode 100644 07_js-debug/projects/debugging-multi-step-form-template.zip create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/.gitignore create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/README.md create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/eslint.config.js create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/index.html create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/package.json create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/postcss.config.js create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/public/vite.svg create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/src/App.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/src/MultiStepForm.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/src/components/FormCheckboxes.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/src/components/FormInput.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/src/components/FormSelect.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/src/components/NavigationButtons.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/src/components/ProgressIndicator.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/src/index.css create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/src/main.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/src/steps/AccountInfo.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/src/steps/ActivityInfo.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/src/steps/GoalSetting.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/src/utils/validation.js create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/tailwind.config.js create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/tests/validation/step1.test.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/tests/validation/step2.test.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/tests/validation/step3.test.jsx create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/tests/validation/utility.test.js create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/vite.config.js create mode 100644 07_js-debug/projects/debugging-multi-step-form-template/vitest.config.js diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new.zip b/07_js-debug/projects/debugging-multi-step-form-template-new.zip new file mode 100644 index 0000000000000000000000000000000000000000..672f3e77b30b70972cf1c75f56f35de6d82ebc1f GIT binary patch literal 126543 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

H}8%h`jEt*F3}@Ub27l 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 + + + + + + debugging-multi-step-form-template-new + + +

+ + + diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/package.json b/07_js-debug/projects/debugging-multi-step-form-template-new/package.json new file mode 100644 index 0000000..47a08a7 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/package.json @@ -0,0 +1,37 @@ +{ + "name": "debugging-multi-step-form-template-new", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "oxlint", + "preview": "vite preview", + "test": "vitest", + "test:ui": "vitest --ui" + }, + "dependencies": { + "react": "^19.3.1", + "react-dom": "^19.3.1" + }, + "devDependencies": { + "@babel/core": "^8.1.0", + "@rolldown/plugin-babel": "^0.3.0", + "@tailwindcss/forms": "^0.5.11", + "@tailwindcss/vite": "^4.3.4", + "@testing-library/jest-dom": "^7.0.1", + "@testing-library/react": "^16.3.3", + "@testing-library/user-event": "^14.6.8", + "@types/react": "^19.3.0", + "@types/react-dom": "^19.3.0", + "@vitejs/plugin-react": "^6.2.1", + "@vitest/ui": "^5.1.0", + "babel-plugin-react-compiler": "^1.0.0", + "jsdom": "^31.0.0", + "oxlint": "^1.91.0", + "tailwindcss": "^4.3.4", + "vite": "^8.3.6", + "vitest": "^5.1.0" + } +} diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/public/favicon.svg b/07_js-debug/projects/debugging-multi-step-form-template-new/public/favicon.svg new file mode 100644 index 0000000..6893eb1 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/public/icons.svg b/07_js-debug/projects/debugging-multi-step-form-template-new/public/icons.svg new file mode 100644 index 0000000..e952219 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/public/icons.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/src/App.jsx b/07_js-debug/projects/debugging-multi-step-form-template-new/src/App.jsx new file mode 100644 index 0000000..af3ed2e --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/src/App.jsx @@ -0,0 +1,12 @@ +import React from 'react'; +import MultiStepForm from './MultiStepForm'; + +function App() { + return ( +
+ +
+ ); +} + +export default App; diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/src/MultiStepForm.jsx b/07_js-debug/projects/debugging-multi-step-form-template-new/src/MultiStepForm.jsx new file mode 100644 index 0000000..e56c9fc --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/src/MultiStepForm.jsx @@ -0,0 +1,125 @@ +import { useState } from 'react'; + +import ProgressIndicator from './components/ProgressIndicator'; +import NavigationButtons from './components/NavigationButtons'; +import AccountInfo from './steps/AccountInfo'; +import ActivityInfo from './steps/ActivityInfo'; +import GoalSetting from './steps/GoalSetting'; + +import { validate } from './utils/validation'; + +function MultiStepForm() { + const [stepIndex, setStepIndex] = useState(1); + const [errors, setErrors] = useState({}); + const [formData, setFormData] = useState({ + fullName: '', + email: '', + password: '', + activityLevel: 'never', + energyLevel: 'low', + goals: [], + timeCommitment: '15', + }); + + const formSteps = [ + { id: 1, name: 'Account Info', component: AccountInfo }, + { id: 2, name: 'Activity Info', component: ActivityInfo }, + { id: 3, name: 'Goal Setting', component: GoalSetting }, + ]; + + // ===== Event Handlers ===== + const handleChange = (e) => { + const { name, value } = e.target; + setFormData({ ...formData, [name]: value }); + }; + + const handleCheckboxChange = (field, id, isChecked) => { + setFormData((prev) => ({ + ...prev, + [field]: isChecked + ? [...prev[field], id] + : prev[field].filter((item) => item !== id), + })); + }; + + // ===== Form Navigation ===== + const handleNext = () => { + if (handleValidation()) { + setStepIndex(stepIndex + 1); + } + }; + + const handlePrev = () => { + setErrors({}); + setStepIndex(stepIndex - 1); + }; + + // ===== Form Validation & Submission ===== + const handleValidation = () => { + const validationErrors = validate(formData, stepIndex); + setErrors(validationErrors); + return Object.keys(validationErrors).length === 0; + }; + + const handleSubmit = (e) => { + e.preventDefault(); + + if (handleValidation()) { + alert('Form submitted successfully!'); + console.log('Submitted Data:', formData); + } + }; + + return ( +
+
+
+
+

+ Let's get you started! +

+ + + +
+ {formSteps.map((s) => { + const StepComponent = s.component; + return ( +
+ {stepIndex === s.id && ( + + )} +
+ ); + })} + + {/* Navigation Buttons */} + + +
+
+
+
+ ); +} + +export default MultiStepForm; diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/src/components/FormCheckboxes.jsx b/07_js-debug/projects/debugging-multi-step-form-template-new/src/components/FormCheckboxes.jsx new file mode 100644 index 0000000..8df52e2 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/src/components/FormCheckboxes.jsx @@ -0,0 +1,44 @@ +import React from 'react'; + +const FormCheckboxes = ({ legend, required, options, onChange, error }) => { + return ( +
+ + +
+ {legend} +
+ {options.map((option) => ( +
+
+ onChange(option.id, e.target.checked)} + checked={option.checked} + /> +
+
+ +
+
+ ))} +
+
+ +

{error}

+
+ ); +}; + +export default FormCheckboxes; diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/src/components/FormInput.jsx b/07_js-debug/projects/debugging-multi-step-form-template-new/src/components/FormInput.jsx new file mode 100644 index 0000000..0b6827a --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/src/components/FormInput.jsx @@ -0,0 +1,47 @@ +import React from 'react'; + +const FormInput = ({ + htmlFor, + label, + id, + name, + value, + onChange, + error, + placeholder, + required = false, + type = 'text', +}) => { + return ( +
+ + +
+ +
+ +

{error}

+
+ ); +}; + +export default FormInput; diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/src/components/FormSelect.jsx b/07_js-debug/projects/debugging-multi-step-form-template-new/src/components/FormSelect.jsx new file mode 100644 index 0000000..185a5c2 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/src/components/FormSelect.jsx @@ -0,0 +1,44 @@ +import React from 'react'; + +const FormSelect = ({ + id, + name, + options, + defaultValue, + onChange, + label, + required = false, + className = '', + labelClassName = '', + error, +}) => { + return ( +
+ {label && ( + + )} + + +

{error}

+
+ ); +}; + +export default FormSelect; diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/src/components/NavigationButtons.jsx b/07_js-debug/projects/debugging-multi-step-form-template-new/src/components/NavigationButtons.jsx new file mode 100644 index 0000000..37b90fc --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/src/components/NavigationButtons.jsx @@ -0,0 +1,43 @@ +import React from 'react'; + +function NavigationButtons({ + currentStep, + totalSteps, + handlePrev, + handleNext, + handleSubmit, +}) { + return ( +
+ {currentStep > 1 && ( + + )} + {currentStep < totalSteps && ( + + )} + {currentStep === totalSteps && ( + + )} +
+ ); +} + +export default NavigationButtons; diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/src/components/ProgressIndicator.jsx b/07_js-debug/projects/debugging-multi-step-form-template-new/src/components/ProgressIndicator.jsx new file mode 100644 index 0000000..8359817 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/src/components/ProgressIndicator.jsx @@ -0,0 +1,33 @@ +import React from 'react'; + +function ProgressIndicator({ steps, currentStep }) { + return ( +
+ {steps.map((step, index) => ( +
+
+
= step.id + ? 'bg-teal-600 text-white' + : 'bg-gray-300 text-gray-700' + }`} + aria-current={currentStep === step.id ? 'step' : undefined} + > + {step.id} +
+ {index !== steps.length - 1 && ( +
step.id ? 'bg-teal-600' : 'bg-gray-300' + }`} + >
+ )} +
+
+ ))} +
+ ); +} + +export default ProgressIndicator; diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/src/index.css b/07_js-debug/projects/debugging-multi-step-form-template-new/src/index.css new file mode 100644 index 0000000..bb6c52e --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/src/index.css @@ -0,0 +1,2 @@ +@import "tailwindcss"; +@plugin "@tailwindcss/forms"; diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/src/main.jsx b/07_js-debug/projects/debugging-multi-step-form-template-new/src/main.jsx new file mode 100644 index 0000000..b9a1a6d --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/src/main.jsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + + + , +) diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/src/steps/AccountInfo.jsx b/07_js-debug/projects/debugging-multi-step-form-template-new/src/steps/AccountInfo.jsx new file mode 100644 index 0000000..5abdb13 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/src/steps/AccountInfo.jsx @@ -0,0 +1,60 @@ +import FormInput from '../components/FormInput'; + +function AccountInfo({ formData, handleChange, errors }) { + return ( +
+

+ Welcome to BrightPath Wellness! +

+

+ Let’s create your account and begin your wellness journey. +

+ +
+ +
+ +
+ +
+ +
+ +
+
+ ); +} + +export default AccountInfo; diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/src/steps/ActivityInfo.jsx b/07_js-debug/projects/debugging-multi-step-form-template-new/src/steps/ActivityInfo.jsx new file mode 100644 index 0000000..92c2736 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/src/steps/ActivityInfo.jsx @@ -0,0 +1,45 @@ +import FormSelect from '../components/FormSelect'; + +function ActivityInfo({ handleChange, errors }) { + return ( +
+

Activity & Energy

+

+ Tell us a little about your activity level and energy. +

+ +
+ +
+ +
+ +
+
+ ); +} + +export default ActivityInfo; diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/src/steps/GoalSetting.jsx b/07_js-debug/projects/debugging-multi-step-form-template-new/src/steps/GoalSetting.jsx new file mode 100644 index 0000000..10889cf --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/src/steps/GoalSetting.jsx @@ -0,0 +1,65 @@ +import FormSelect from '../components/FormSelect'; +import FormCheckboxes from '../components/FormCheckboxes'; + +function GoalSetting({ formData, handleChange, handleCheckboxChange, errors }) { + return ( +
+

Activity & Energy

+

+ Tell us a little about your activity level and energy. +

+ +
+ handleCheckboxChange('goals', id)} + required={true} + error={errors.goals} + /> +
+ +
+ +
+
+ ); +} + +export default GoalSetting; diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/src/utils/validation.js b/07_js-debug/projects/debugging-multi-step-form-template-new/src/utils/validation.js new file mode 100644 index 0000000..99c87f7 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/src/utils/validation.js @@ -0,0 +1,96 @@ +const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; +const PASSWORD_MIN_LENGTH = 6; + +// Helper Functions +export const isEmpty = (value) => { + return !value || !value.trim(); +}; + +export const isValidEmail = (email) => { + return EMAIL_REGEX.test(email); +}; + +export const hasMinLength = (value, min) => { + return value.length >= min; +}; + +export const hasTwoWords = (fullName) => { + return fullName.trim().split(' ').length >= 2; +}; + +// Main Validation Function +export const validate = (formData, currentStep) => { + const errors = {}; + + const { + fullName, + email, + password, + activityLevel, + energyLevel, + goals, + timeCommitment, + } = formData; + + switch (currentStep) { + case 1: + // Full Name Validations + if (isEmpty(fullName)) { + errors.fullName = 'Full Name is required'; + } else if (!hasTwoWords(fullName)) { + errors.fullName = 'Full Name must contain at least two words'; + } + + // Email Validations + if (isEmpty(email)) { + errors.email = 'Email is required'; + } else if (!isValidEmail(email)) { + errors.email = 'Email address is invalid'; + } + + // Password Validations + if (isEmpty(password)) { + errors.password = 'Password is required'; + } else { + if (!hasMinLength(password, PASSWORD_MIN_LENGTH)) { + errors.password = `Password must be at least ${PASSWORD_MIN_LENGTH} characters`; + } + } + break; + + case 2: + // Activity Level Validation + if (isEmpty(activityLevel)) { + errors.activityLevel = 'Activity Level is required'; + } + + // Energy Level Validation + if (isEmpty(energyLevel)) { + errors.energyLevel = 'Energy Level is required'; + } + break; + + case 3: + // Goals Validation + if (!Array.isArray(goals) || goals.length === 0) { + errors.goals = 'At least one goal is required'; + } else { + goals.forEach((goal, index) => { + if (isEmpty(goal)) { + errors[`goals.${index}`] = 'Goal cannot be empty'; + } + }); + } + + // Time Commitment Validation + if (isEmpty(timeCommitment)) { + errors.timeCommitment = 'Time Commitment is required'; + } + break; + + default: + break; + } + + return errors; +}; diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/step1.test.jsx b/07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/step1.test.jsx new file mode 100644 index 0000000..0aed95e --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/step1.test.jsx @@ -0,0 +1,125 @@ +import { it, expect, describe, afterEach } from 'vitest'; +import { render, screen, cleanup } from '@testing-library/react'; +import '@testing-library/jest-dom/vitest'; +import userEvent from '@testing-library/user-event'; + +import AccountInfo from '../../src/steps/AccountInfo'; +import { validate } from '../../src/utils/validation'; + +describe('AccountInfo Component', () => { + afterEach(cleanup); + + const step = 1; + + it('renders all form fields', () => { + render( + {}} + errors={{}} + /> + ); + + expect(screen.getByLabelText(/Full Name/i)).toBeInTheDocument(); + expect(screen.getByLabelText(/Email/i)).toBeInTheDocument(); + expect(screen.getByLabelText(/Password/i)).toBeInTheDocument(); + }); + + it('displays validation errors for invalid data', () => { + const formData = { fullName: '', email: '', password: '' }; + const errors = validate(formData, step); + + render( + {}} + errors={errors} + /> + ); + + expect(screen.getByText(/Full Name is required/i)).toBeInTheDocument(); + expect(screen.getByText(/Email is required/i)).toBeInTheDocument(); + expect(screen.getByText(/Password is required/i)).toBeInTheDocument(); + }); + + it('displays no validation errors for valid data', () => { + const formData = { + fullName: 'John Doe', + email: 'john.doe@example.com', + password: 'securepassword', + }; + const errors = validate(formData, step); + + render( + {}} + errors={errors} + /> + ); + + expect(screen.queryByText(/is required/i)).not.toBeInTheDocument(); + expect(screen.queryByText(/invalid/i)).not.toBeInTheDocument(); + expect( + screen.queryByText(/must be at least 6 characters/i) + ).not.toBeInTheDocument(); + }); + + it('calls handleChange and updates error messages dynamically', async () => { + let formData = { fullName: '', email: '', password: '' }; + let errors = validate(formData, step); + + const handleChangeTest = (field, value) => { + formData = { ...formData, [field]: value }; + errors = validate(formData, step); + }; + + const { rerender } = render( + + handleChangeTest(target.name, target.value) + } + errors={errors} + /> + ); + + const fullNameInput = screen.getByLabelText(/Full Name/i); + await userEvent.type(fullNameInput, 'John'); + + rerender( + + handleChangeTest(target.name, target.value) + } + errors={errors} + /> + ); + + expect( + screen.getByText(/Full Name must contain at least two words/i) + ).toBeInTheDocument(); + }); + + it('retains user input in form fields', () => { + const formData = { + fullName: 'Jane Doe', + email: 'jane.doe@example.com', + password: 'securepassword', + }; + const errors = validate(formData, step); + + render( + {}} + errors={errors} + /> + ); + + expect(screen.getByLabelText(/Full Name/i)).toHaveValue('Jane Doe'); + expect(screen.getByLabelText(/Email/i)).toHaveValue('jane.doe@example.com'); + expect(screen.getByLabelText(/Password/i)).toHaveValue('securepassword'); + }); +}); diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/step2.test.jsx b/07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/step2.test.jsx new file mode 100644 index 0000000..7505148 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/step2.test.jsx @@ -0,0 +1,114 @@ +import { it, expect, describe, afterEach } from 'vitest'; +import { render, screen, cleanup } from '@testing-library/react'; +import '@testing-library/jest-dom/vitest'; +import userEvent from '@testing-library/user-event'; + +import ActivityInfo from '../../src/steps/ActivityInfo'; +import { validate } from '../../src/utils/validation'; + +describe('ActivityInfo Component', () => { + afterEach(cleanup); + + const step = 2; + + it('renders all form fields', () => { + render( {}} errors={{}} />); + + expect( + screen.getByLabelText(/How often do you exercise\?/i) + ).toBeInTheDocument(); + expect( + screen.getByLabelText( + /How would you describe your average energy level\?/i + ) + ).toBeInTheDocument(); + }); + + it('displays validation errors for invalid data', () => { + const formData = { + fullName: 'John Doe', + email: 'john@example.com', + password: 'password123', + activityLevel: '', + energyLevel: '', + goals: [], + timeCommitment: '15', + }; + const errors = validate(formData, step); + + render( {}} errors={errors} />); + + expect(screen.getByText(/Activity Level is required/i)).toBeInTheDocument(); + expect(screen.getByText(/Energy Level is required/i)).toBeInTheDocument(); + }); + + it('displays no validation errors for valid data', () => { + const formData = { + fullName: 'John Doe', + email: 'john@example.com', + password: 'password123', + activityLevel: 'moderate', + energyLevel: 'high', + goals: [], + timeCommitment: '15', + }; + const errors = validate(formData, step); + + render( {}} errors={errors} />); + + expect(screen.queryByText(/is required/i)).not.toBeInTheDocument(); + }); + + it('calls handleChange and updates error messages dynamically', async () => { + let formData = { + fullName: 'John Doe', + email: 'john@example.com', + password: 'password123', + activityLevel: '', + energyLevel: '', + goals: [], + timeCommitment: '15', + }; + let errors = validate(formData, step); + + const handleChangeTest = (field, value) => { + formData = { ...formData, [field]: value }; + errors = validate(formData, step); + }; + + const { rerender } = render( + + handleChangeTest(target.name, target.value) + } + errors={errors} + /> + ); + + const activitySelect = screen.getByLabelText( + /How often do you exercise\?/i + ); + const energySelect = screen.getByLabelText( + /How would you describe your average energy level\?/i + ); + + await userEvent.selectOptions(activitySelect, '3+ times a week'); + await userEvent.selectOptions(energySelect, 'medium'); + + rerender( + + handleChangeTest(target.name, target.value) + } + errors={errors} + /> + ); + + expect( + screen.queryByText(/Activity Level is required/i) + ).not.toBeInTheDocument(); + expect( + screen.queryByText(/Energy Level is required/i) + ).not.toBeInTheDocument(); + }); +}); diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/step3.test.jsx b/07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/step3.test.jsx new file mode 100644 index 0000000..57fb4ff --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/step3.test.jsx @@ -0,0 +1,173 @@ +import { it, expect, describe, afterEach } from 'vitest'; +import { render, screen, cleanup } from '@testing-library/react'; +import '@testing-library/jest-dom/vitest'; +import userEvent from '@testing-library/user-event'; + +import GoalSetting from '../../src/steps/GoalSetting'; +import { validate } from '../../src/utils/validation'; + +describe('GoalSetting Component', () => { + afterEach(cleanup); + + const step = 3; + + it('renders all form fields', () => { + render( + {}} + handleCheckboxChange={() => {}} + errors={{}} + /> + ); + + // Use getByRole to target the fieldset for "What are your goals?" + expect( + screen.getByRole('group', { name: /What are your goals\?/i }) + ).toBeInTheDocument(); + + expect( + screen.getByLabelText(/How much time can you commit each day\?/i) + ).toBeInTheDocument(); + }); + + it('displays validation errors for empty fields', () => { + const formData = { + goals: [], + timeCommitment: '', + }; + const errors = validate(formData, step); + + render( + {}} + handleCheckboxChange={() => {}} + errors={errors} + /> + ); + + expect( + screen.getByText(/At least one goal is required/i) + ).toBeInTheDocument(); + expect( + screen.getByText(/Time Commitment is required/i) + ).toBeInTheDocument(); + }); + + it('displays no validation errors for valid data', () => { + const formData = { + goals: ['weightLoss', 'muscleGain'], + timeCommitment: '30', + }; + const errors = validate(formData, step); + + render( + {}} + handleCheckboxChange={() => {}} + errors={errors} + /> + ); + + expect(screen.queryByText(/is required/i)).not.toBeInTheDocument(); + }); + + it('handles checkbox interactions and updates goals dynamically', async () => { + let formData = { goals: [], timeCommitment: '' }; + let errors = validate(formData, step); + + const handleCheckboxChangeTest = (field, id, isChecked) => { + const updatedGoals = isChecked + ? [...formData[field], id] + : formData[field].filter((goal) => goal !== id); + + formData = { ...formData, [field]: updatedGoals }; + errors = validate(formData, step); + }; + + const { rerender } = render( + {}} + handleCheckboxChange={handleCheckboxChangeTest} + errors={errors} + /> + ); + + const weightLossCheckbox = screen.getByLabelText(/Weight Loss/i); + const muscleGainCheckbox = screen.getByLabelText(/Muscle Gain/i); + + await userEvent.click(weightLossCheckbox); + rerender( + {}} + handleCheckboxChange={handleCheckboxChangeTest} + errors={errors} + /> + ); + + expect(weightLossCheckbox).toBeChecked(); + expect( + screen.queryByText(/At least one goal is required/i) + ).not.toBeInTheDocument(); + + await userEvent.click(muscleGainCheckbox); + rerender( + {}} + handleCheckboxChange={handleCheckboxChangeTest} + errors={errors} + /> + ); + + expect(muscleGainCheckbox).toBeChecked(); + expect(formData.goals).toContain('weightLoss'); + expect(formData.goals).toContain('muscleGain'); + }); + + it('handles select interactions and updates time commitment dynamically', async () => { + let formData = { goals: ['weightLoss'], timeCommitment: '' }; + let errors = validate(formData, step); + + const handleChangeTest = (field, value) => { + formData = { ...formData, [field]: value }; + errors = validate(formData, step); + }; + + const { rerender } = render( + + handleChangeTest(target.name, target.value) + } + handleCheckboxChange={() => {}} + errors={errors} + /> + ); + + const timeCommitmentSelect = screen.getByLabelText( + /How much time can you commit each day\?/i + ); + await userEvent.selectOptions(timeCommitmentSelect, '30'); + + rerender( + + handleChangeTest(target.name, target.value) + } + handleCheckboxChange={() => {}} + errors={errors} + /> + ); + + expect(timeCommitmentSelect).toHaveValue('30'); + expect( + screen.queryByText(/Time Commitment is required/i) + ).not.toBeInTheDocument(); + }); +}); diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/utility.test.js b/07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/utility.test.js new file mode 100644 index 0000000..6c3b9cd --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/tests/validation/utility.test.js @@ -0,0 +1,58 @@ +import { describe, it, expect } from 'vitest'; +import { + isEmpty, + isValidEmail, + hasMinLength, + hasTwoWords, +} from '../../src/utils/validation'; + +describe('Utility Functions', () => { + describe('isEmpty', () => { + it('should return true for empty strings', () => { + expect(isEmpty('')).toBe(true); + expect(isEmpty(' ')).toBe(true); + }); + + it('should return false for non-empty strings', () => { + expect(isEmpty('John')).toBe(false); + expect(isEmpty(' John Doe ')).toBe(false); + }); + }); + + describe('isValidEmail', () => { + it('should validate correct email formats', () => { + expect(isValidEmail('john@example.com')).toBe(true); + expect(isValidEmail('jane.doe@sub.domain.co')).toBe(true); + }); + + it('should invalidate incorrect email formats', () => { + expect(isValidEmail('johnexample.com')).toBe(false); + expect(isValidEmail('jane@.com')).toBe(false); + expect(isValidEmail('jane@com')).toBe(false); + }); + }); + + describe('hasMinLength', () => { + it('should return true if value meets minimum length', () => { + expect(hasMinLength('password', 6)).toBe(true); + expect(hasMinLength('123456', 6)).toBe(true); + }); + + it('should return false if value does not meet minimum length', () => { + expect(hasMinLength('pass', 6)).toBe(false); + expect(hasMinLength('123', 6)).toBe(false); + }); + }); + + describe('hasTwoWords', () => { + it('should return true if fullName has at least two words', () => { + expect(hasTwoWords('John Doe')).toBe(true); + expect(hasTwoWords('Jane Mary Doe')).toBe(true); + }); + + it('should return false if fullName has less than two words', () => { + expect(hasTwoWords('John')).toBe(false); + expect(hasTwoWords(' Jane ')).toBe(false); + }); + }); +}); diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/vite.config.js b/07_js-debug/projects/debugging-multi-step-form-template-new/vite.config.js new file mode 100644 index 0000000..5b7c4e9 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/vite.config.js @@ -0,0 +1,13 @@ +import react, { reactCompilerPreset } from '@vitejs/plugin-react' +import babel from '@rolldown/plugin-babel' +import tailwindcss from '@tailwindcss/vite' +import { defineConfig } from 'vite' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + react(), + babel({ presets: [reactCompilerPreset()] }), + tailwindcss(), + ], +}) diff --git a/07_js-debug/projects/debugging-multi-step-form-template-new/vitest.config.js b/07_js-debug/projects/debugging-multi-step-form-template-new/vitest.config.js new file mode 100644 index 0000000..5853726 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template-new/vitest.config.js @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + test: { + environment: 'jsdom', + }, + plugins: [react()], +}); diff --git a/07_js-debug/projects/debugging-multi-step-form-template.zip b/07_js-debug/projects/debugging-multi-step-form-template.zip new file mode 100644 index 0000000000000000000000000000000000000000..c8e601a764d50b16bb0009ed3be7177c6af14dd6 GIT binary patch literal 37445 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 literal 0 HcmV?d00001 diff --git a/07_js-debug/projects/debugging-multi-step-form-template/.gitignore b/07_js-debug/projects/debugging-multi-step-form-template/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/07_js-debug/projects/debugging-multi-step-form-template/README.md b/07_js-debug/projects/debugging-multi-step-form-template/README.md new file mode 100644 index 0000000..2861a84 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/README.md @@ -0,0 +1,132 @@ +# Assignment: Completing the Multi-Step Wizard Form + +In this assignment, you will complete a multi-step wizard form by adding two final steps, Step 4 (Personal Preferences) and Step 5 (Ready to Start), bringing the total number of steps to five. Your tasks include: + +- Fixing any failing components so that all existing tests pass. +- Adding two new steps with validation logic. +- Writing tests to ensure the new steps are functional and robust. + +Below are detailed requirements for the two new steps and their associated tests. + +## Adding Step 4 and Step 5 to the Multi-Step Wizard Form + +This section outlines the requirements for implementing Step 4: Personal Preferences and Step 5: Ready to Start. Your implementation should maintain consistency with the existing form design and functionality while ensuring robust validation and comprehensive test coverage. + +### Step 4: Personal Preferences + +This step gathers information about the user’s preferred activities and dietary preferences. + +#### Inputs + +- **Checkboxes**: Allow users to select one or more activities. Options include: + - Yoga + - Cardio + - Strength Training + - Meditation +- **Dropdown (Select)**: Allow users to specify their dietary preferences. Options include: + - None + - Vegetarian + - Vegan + - Gluten-Free + +Display the following text in this step: “Let us know your preferences to make the experience personal.” + +#### What to Test + +1. Rendering of Form Fields: + +- **Activity Checkboxes**: + - Verify that checkboxes for activities are rendered and grouped under the label “What type of activities do you prefer?” + - Ensure that all activity options (Yoga, Cardio, Strength Training, Meditation) are present and selectable. +- **Dietary Preferences Dropdown**: + - Confirm that the dropdown for dietary preferences is rendered with the label “Do you have any dietary preferences?” + - Ensure that all dietary options (None, Vegetarian, Vegan, Gluten-Free) are available for selection. + +2. Validation of User Input: + +- **Activity Preferences Validation**: + - Attempt to proceed without selecting any activities and verify that an error message appears stating “At least one activity preference is required.” + - Select one or more activities and ensure that the error message disappears upon valid input. +- **Dietary Preferences Validation**: + - Attempt to proceed without selecting a dietary preference and verify that an error message appears stating “Dietary preference is required.” + - Select a dietary preference and ensure that the error message disappears upon valid input. + +3. Dynamic Updates to Form Data: + +- **Activity Checkboxes Interaction**: + - Select and deselect activity checkboxes and confirm that the activityPreferences array in the form data updates accordingly. +- **Dietary Preferences Dropdown Interaction**: + - Change the selection in the dietary preferences dropdown and verify that the diet field in the form data updates to reflect the current selection. + +#### Test Summary for Step 4: Personal Preferences + +- **Test Case 1**: Verifies that all form fields (activity checkboxes and dietary preferences dropdown) are rendered correctly with the appropriate labels and options. +- **Test Case 2**: Ensures validation errors appear when no activities or dietary preferences are selected and disappear when valid inputs are provided. +- **Test Case 3**: Confirms that interacting with the form elements (selecting activities and dietary preferences) dynamically updates the form data. + +### Step 5: Ready to Start + +This step collects motivational information, enables users to join optional challenges, and allows them to choose their preferred reminder method. + +#### Inputs + +- **Short Text Input**: A field for users to describe what motivates them the most. Placeholder: “What motivates you the most?” +- **Checkboxes**: Options to join one or more optional challenges, including: + - Fitness Challenge + - Healthy Eating Challenge + - Mindfulness Challenge +- **Dropdown (Select)**: A field to specify how users want to receive reminders. Options include: + - Email + - Push Notifications + - None + +Display the following text in this step: “We are ready to guide you! Set your preferences and begin your journey.” + +#### What to Test + +1. Rendering of Form Fields: + +- **Motivational Input Field**: + - Verify that the motivational input field is rendered with the label “What motivates you the most?” and the placeholder text is correctly displayed. +- **Optional Challenges Checkboxes**: + - Confirm that checkboxes for optional challenges are rendered and grouped under the label “Would you like to join any optional challenges?” + - Ensure that all challenge options (Fitness Challenge, Healthy Eating Challenge, Mindfulness Challenge) are present and selectable. +- **Reminders Dropdown**: + - Check that the dropdown for reminder preferences is rendered with the label “Preferred way to receive reminders?” + - Ensure that all reminder options (Email, Push Notifications, None) are available for selection. + +2. Validation and Dynamic Updates of User Input: + +- **Form Validation**: + - Enter valid inputs for all fields: + - Type a non-empty string into the motivation field. + - Optionally select one or more challenges (since they are optional, the form should accept both selecting and not selecting any challenges). + - Select a valid option from the reminders dropdown. + - Ensure that the form passes validation without any errors when all inputs are valid. +- **Dynamic Updates to Form Data**: + - Confirm that typing into the motivation field updates the motivation field in the form data. + - Verify that selecting or deselecting challenges updates the optionalChallenges array in the form data. + - Ensure that changing the selection in the reminders dropdown updates the reminders field in the form data. + +#### Test Summary for Step 5: Ready to Start + +- **Test Case 1**: Verifies that all form fields (motivation input, optional challenges checkboxes, and reminders dropdown) are rendered correctly with the appropriate labels and options. +- **Test Case 2**: Ensures the form passes validation with valid inputs and confirms that user interactions (typing in the motivation field, selecting/deselecting challenges, choosing a reminder option) dynamically update the form data accurately. + +## License and terms of use + +© Web Professional Institute Inc. All rights reserved. + +This material is provided solely for students enrolled in courses offered by Web Professional Institute Inc. By accessing or using this code, you acknowledge that it is strictly for educational use within the context of Web Professional Institute Inc. programs. + +**Usage Restrictions:** + +- Redistribution, sharing, or copying of this material outside the course environment is strictly prohibited. +- The content is designed to support your learning objectives and is not authorized for commercial projects, public repositories, or applications beyond the course scope. +- Unauthorized commercial use or open-source distribution is strictly prohibited and may result in expulsion from the program and legal action. + +**Agreement & Rights:** + +As a student, you have agreed to these terms as part of your enrollment agreement, which includes additional details on permitted uses, restrictions, and policies. The author and Web Professional Institute Inc. retain all rights to this material, including the code base and instructional content. + +For any questions regarding these terms, please contact Web Professional Institute Inc. for clarification. diff --git a/07_js-debug/projects/debugging-multi-step-form-template/eslint.config.js b/07_js-debug/projects/debugging-multi-step-form-template/eslint.config.js new file mode 100644 index 0000000..238d2e4 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/eslint.config.js @@ -0,0 +1,38 @@ +import js from '@eslint/js' +import globals from 'globals' +import react from 'eslint-plugin-react' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' + +export default [ + { ignores: ['dist'] }, + { + files: ['**/*.{js,jsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + settings: { react: { version: '18.3' } }, + plugins: { + react, + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...js.configs.recommended.rules, + ...react.configs.recommended.rules, + ...react.configs['jsx-runtime'].rules, + ...reactHooks.configs.recommended.rules, + 'react/jsx-no-target-blank': 'off', + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, + }, +] diff --git a/07_js-debug/projects/debugging-multi-step-form-template/index.html b/07_js-debug/projects/debugging-multi-step-form-template/index.html new file mode 100644 index 0000000..0c589ec --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + + +
+ + + diff --git a/07_js-debug/projects/debugging-multi-step-form-template/package.json b/07_js-debug/projects/debugging-multi-step-form-template/package.json new file mode 100644 index 0000000..5bd42b3 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/package.json @@ -0,0 +1,42 @@ +{ + "name": "debugging-assignment-wizard", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview", + "test": "vitest", + "test:ui": "vitest --ui" + }, + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@eslint/js": "^9.13.0", + "@tailwindcss/forms": "^0.5.9", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^16.0.1", + "@testing-library/user-event": "^14.5.2", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@vitejs/plugin-react": "^4.3.3", + "@vitest/ui": "^2.1.5", + "autoprefixer": "^10.4.20", + "eslint": "^9.13.0", + "eslint-plugin-react": "^7.37.2", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.14", + "globals": "^15.11.0", + "i": "^0.3.7", + "jsdom": "^25.0.1", + "npm": "^10.9.0", + "postcss": "^8.4.49", + "tailwindcss": "^3.4.14", + "vite": "^5.4.10", + "vitest": "^2.1.5" + } +} diff --git a/07_js-debug/projects/debugging-multi-step-form-template/postcss.config.js b/07_js-debug/projects/debugging-multi-step-form-template/postcss.config.js new file mode 100644 index 0000000..2e7af2b --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/07_js-debug/projects/debugging-multi-step-form-template/public/vite.svg b/07_js-debug/projects/debugging-multi-step-form-template/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/07_js-debug/projects/debugging-multi-step-form-template/src/App.jsx b/07_js-debug/projects/debugging-multi-step-form-template/src/App.jsx new file mode 100644 index 0000000..af3ed2e --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/src/App.jsx @@ -0,0 +1,12 @@ +import React from 'react'; +import MultiStepForm from './MultiStepForm'; + +function App() { + return ( +
+ +
+ ); +} + +export default App; diff --git a/07_js-debug/projects/debugging-multi-step-form-template/src/MultiStepForm.jsx b/07_js-debug/projects/debugging-multi-step-form-template/src/MultiStepForm.jsx new file mode 100644 index 0000000..e56c9fc --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/src/MultiStepForm.jsx @@ -0,0 +1,125 @@ +import { useState } from 'react'; + +import ProgressIndicator from './components/ProgressIndicator'; +import NavigationButtons from './components/NavigationButtons'; +import AccountInfo from './steps/AccountInfo'; +import ActivityInfo from './steps/ActivityInfo'; +import GoalSetting from './steps/GoalSetting'; + +import { validate } from './utils/validation'; + +function MultiStepForm() { + const [stepIndex, setStepIndex] = useState(1); + const [errors, setErrors] = useState({}); + const [formData, setFormData] = useState({ + fullName: '', + email: '', + password: '', + activityLevel: 'never', + energyLevel: 'low', + goals: [], + timeCommitment: '15', + }); + + const formSteps = [ + { id: 1, name: 'Account Info', component: AccountInfo }, + { id: 2, name: 'Activity Info', component: ActivityInfo }, + { id: 3, name: 'Goal Setting', component: GoalSetting }, + ]; + + // ===== Event Handlers ===== + const handleChange = (e) => { + const { name, value } = e.target; + setFormData({ ...formData, [name]: value }); + }; + + const handleCheckboxChange = (field, id, isChecked) => { + setFormData((prev) => ({ + ...prev, + [field]: isChecked + ? [...prev[field], id] + : prev[field].filter((item) => item !== id), + })); + }; + + // ===== Form Navigation ===== + const handleNext = () => { + if (handleValidation()) { + setStepIndex(stepIndex + 1); + } + }; + + const handlePrev = () => { + setErrors({}); + setStepIndex(stepIndex - 1); + }; + + // ===== Form Validation & Submission ===== + const handleValidation = () => { + const validationErrors = validate(formData, stepIndex); + setErrors(validationErrors); + return Object.keys(validationErrors).length === 0; + }; + + const handleSubmit = (e) => { + e.preventDefault(); + + if (handleValidation()) { + alert('Form submitted successfully!'); + console.log('Submitted Data:', formData); + } + }; + + return ( +
+
+
+
+

+ Let's get you started! +

+ + + +
+ {formSteps.map((s) => { + const StepComponent = s.component; + return ( +
+ {stepIndex === s.id && ( + + )} +
+ ); + })} + + {/* Navigation Buttons */} + + +
+
+
+
+ ); +} + +export default MultiStepForm; diff --git a/07_js-debug/projects/debugging-multi-step-form-template/src/components/FormCheckboxes.jsx b/07_js-debug/projects/debugging-multi-step-form-template/src/components/FormCheckboxes.jsx new file mode 100644 index 0000000..8df52e2 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/src/components/FormCheckboxes.jsx @@ -0,0 +1,44 @@ +import React from 'react'; + +const FormCheckboxes = ({ legend, required, options, onChange, error }) => { + return ( +
+ + +
+ {legend} +
+ {options.map((option) => ( +
+
+ onChange(option.id, e.target.checked)} + checked={option.checked} + /> +
+
+ +
+
+ ))} +
+
+ +

{error}

+
+ ); +}; + +export default FormCheckboxes; diff --git a/07_js-debug/projects/debugging-multi-step-form-template/src/components/FormInput.jsx b/07_js-debug/projects/debugging-multi-step-form-template/src/components/FormInput.jsx new file mode 100644 index 0000000..0b6827a --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/src/components/FormInput.jsx @@ -0,0 +1,47 @@ +import React from 'react'; + +const FormInput = ({ + htmlFor, + label, + id, + name, + value, + onChange, + error, + placeholder, + required = false, + type = 'text', +}) => { + return ( +
+ + +
+ +
+ +

{error}

+
+ ); +}; + +export default FormInput; diff --git a/07_js-debug/projects/debugging-multi-step-form-template/src/components/FormSelect.jsx b/07_js-debug/projects/debugging-multi-step-form-template/src/components/FormSelect.jsx new file mode 100644 index 0000000..185a5c2 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/src/components/FormSelect.jsx @@ -0,0 +1,44 @@ +import React from 'react'; + +const FormSelect = ({ + id, + name, + options, + defaultValue, + onChange, + label, + required = false, + className = '', + labelClassName = '', + error, +}) => { + return ( +
+ {label && ( + + )} + + +

{error}

+
+ ); +}; + +export default FormSelect; diff --git a/07_js-debug/projects/debugging-multi-step-form-template/src/components/NavigationButtons.jsx b/07_js-debug/projects/debugging-multi-step-form-template/src/components/NavigationButtons.jsx new file mode 100644 index 0000000..37b90fc --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/src/components/NavigationButtons.jsx @@ -0,0 +1,43 @@ +import React from 'react'; + +function NavigationButtons({ + currentStep, + totalSteps, + handlePrev, + handleNext, + handleSubmit, +}) { + return ( +
+ {currentStep > 1 && ( + + )} + {currentStep < totalSteps && ( + + )} + {currentStep === totalSteps && ( + + )} +
+ ); +} + +export default NavigationButtons; diff --git a/07_js-debug/projects/debugging-multi-step-form-template/src/components/ProgressIndicator.jsx b/07_js-debug/projects/debugging-multi-step-form-template/src/components/ProgressIndicator.jsx new file mode 100644 index 0000000..8359817 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/src/components/ProgressIndicator.jsx @@ -0,0 +1,33 @@ +import React from 'react'; + +function ProgressIndicator({ steps, currentStep }) { + return ( +
+ {steps.map((step, index) => ( +
+
+
= step.id + ? 'bg-teal-600 text-white' + : 'bg-gray-300 text-gray-700' + }`} + aria-current={currentStep === step.id ? 'step' : undefined} + > + {step.id} +
+ {index !== steps.length - 1 && ( +
step.id ? 'bg-teal-600' : 'bg-gray-300' + }`} + >
+ )} +
+
+ ))} +
+ ); +} + +export default ProgressIndicator; diff --git a/07_js-debug/projects/debugging-multi-step-form-template/src/index.css b/07_js-debug/projects/debugging-multi-step-form-template/src/index.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/src/index.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/07_js-debug/projects/debugging-multi-step-form-template/src/main.jsx b/07_js-debug/projects/debugging-multi-step-form-template/src/main.jsx new file mode 100644 index 0000000..b9a1a6d --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/src/main.jsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + + + , +) diff --git a/07_js-debug/projects/debugging-multi-step-form-template/src/steps/AccountInfo.jsx b/07_js-debug/projects/debugging-multi-step-form-template/src/steps/AccountInfo.jsx new file mode 100644 index 0000000..5abdb13 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/src/steps/AccountInfo.jsx @@ -0,0 +1,60 @@ +import FormInput from '../components/FormInput'; + +function AccountInfo({ formData, handleChange, errors }) { + return ( +
+

+ Welcome to BrightPath Wellness! +

+

+ Let’s create your account and begin your wellness journey. +

+ +
+ +
+ +
+ +
+ +
+ +
+
+ ); +} + +export default AccountInfo; diff --git a/07_js-debug/projects/debugging-multi-step-form-template/src/steps/ActivityInfo.jsx b/07_js-debug/projects/debugging-multi-step-form-template/src/steps/ActivityInfo.jsx new file mode 100644 index 0000000..92c2736 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/src/steps/ActivityInfo.jsx @@ -0,0 +1,45 @@ +import FormSelect from '../components/FormSelect'; + +function ActivityInfo({ handleChange, errors }) { + return ( +
+

Activity & Energy

+

+ Tell us a little about your activity level and energy. +

+ +
+ +
+ +
+ +
+
+ ); +} + +export default ActivityInfo; diff --git a/07_js-debug/projects/debugging-multi-step-form-template/src/steps/GoalSetting.jsx b/07_js-debug/projects/debugging-multi-step-form-template/src/steps/GoalSetting.jsx new file mode 100644 index 0000000..0e1b1ef --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/src/steps/GoalSetting.jsx @@ -0,0 +1,64 @@ +import FormSelect from '../components/FormSelect'; +import FormCheckboxes from '../components/FormCheckboxes'; + +function GoalSetting({ formData, handleChange, handleCheckboxChange, errors }) { + return ( +
+

Activity & Energy

+

Tell us a little about your activity level and energy.

+ +
+ handleCheckboxChange('goals', id)} + required={true} + error={errors.goals} + /> +
+ +
+ +
+
+ ); +} + +export default GoalSetting; diff --git a/07_js-debug/projects/debugging-multi-step-form-template/src/utils/validation.js b/07_js-debug/projects/debugging-multi-step-form-template/src/utils/validation.js new file mode 100644 index 0000000..99c87f7 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/src/utils/validation.js @@ -0,0 +1,96 @@ +const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; +const PASSWORD_MIN_LENGTH = 6; + +// Helper Functions +export const isEmpty = (value) => { + return !value || !value.trim(); +}; + +export const isValidEmail = (email) => { + return EMAIL_REGEX.test(email); +}; + +export const hasMinLength = (value, min) => { + return value.length >= min; +}; + +export const hasTwoWords = (fullName) => { + return fullName.trim().split(' ').length >= 2; +}; + +// Main Validation Function +export const validate = (formData, currentStep) => { + const errors = {}; + + const { + fullName, + email, + password, + activityLevel, + energyLevel, + goals, + timeCommitment, + } = formData; + + switch (currentStep) { + case 1: + // Full Name Validations + if (isEmpty(fullName)) { + errors.fullName = 'Full Name is required'; + } else if (!hasTwoWords(fullName)) { + errors.fullName = 'Full Name must contain at least two words'; + } + + // Email Validations + if (isEmpty(email)) { + errors.email = 'Email is required'; + } else if (!isValidEmail(email)) { + errors.email = 'Email address is invalid'; + } + + // Password Validations + if (isEmpty(password)) { + errors.password = 'Password is required'; + } else { + if (!hasMinLength(password, PASSWORD_MIN_LENGTH)) { + errors.password = `Password must be at least ${PASSWORD_MIN_LENGTH} characters`; + } + } + break; + + case 2: + // Activity Level Validation + if (isEmpty(activityLevel)) { + errors.activityLevel = 'Activity Level is required'; + } + + // Energy Level Validation + if (isEmpty(energyLevel)) { + errors.energyLevel = 'Energy Level is required'; + } + break; + + case 3: + // Goals Validation + if (!Array.isArray(goals) || goals.length === 0) { + errors.goals = 'At least one goal is required'; + } else { + goals.forEach((goal, index) => { + if (isEmpty(goal)) { + errors[`goals.${index}`] = 'Goal cannot be empty'; + } + }); + } + + // Time Commitment Validation + if (isEmpty(timeCommitment)) { + errors.timeCommitment = 'Time Commitment is required'; + } + break; + + default: + break; + } + + return errors; +}; diff --git a/07_js-debug/projects/debugging-multi-step-form-template/tailwind.config.js b/07_js-debug/projects/debugging-multi-step-form-template/tailwind.config.js new file mode 100644 index 0000000..2be9ef7 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/tailwind.config.js @@ -0,0 +1,8 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], + theme: { + extend: {}, + }, + plugins: [require('@tailwindcss/forms')], +}; diff --git a/07_js-debug/projects/debugging-multi-step-form-template/tests/validation/step1.test.jsx b/07_js-debug/projects/debugging-multi-step-form-template/tests/validation/step1.test.jsx new file mode 100644 index 0000000..0aed95e --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/tests/validation/step1.test.jsx @@ -0,0 +1,125 @@ +import { it, expect, describe, afterEach } from 'vitest'; +import { render, screen, cleanup } from '@testing-library/react'; +import '@testing-library/jest-dom/vitest'; +import userEvent from '@testing-library/user-event'; + +import AccountInfo from '../../src/steps/AccountInfo'; +import { validate } from '../../src/utils/validation'; + +describe('AccountInfo Component', () => { + afterEach(cleanup); + + const step = 1; + + it('renders all form fields', () => { + render( + {}} + errors={{}} + /> + ); + + expect(screen.getByLabelText(/Full Name/i)).toBeInTheDocument(); + expect(screen.getByLabelText(/Email/i)).toBeInTheDocument(); + expect(screen.getByLabelText(/Password/i)).toBeInTheDocument(); + }); + + it('displays validation errors for invalid data', () => { + const formData = { fullName: '', email: '', password: '' }; + const errors = validate(formData, step); + + render( + {}} + errors={errors} + /> + ); + + expect(screen.getByText(/Full Name is required/i)).toBeInTheDocument(); + expect(screen.getByText(/Email is required/i)).toBeInTheDocument(); + expect(screen.getByText(/Password is required/i)).toBeInTheDocument(); + }); + + it('displays no validation errors for valid data', () => { + const formData = { + fullName: 'John Doe', + email: 'john.doe@example.com', + password: 'securepassword', + }; + const errors = validate(formData, step); + + render( + {}} + errors={errors} + /> + ); + + expect(screen.queryByText(/is required/i)).not.toBeInTheDocument(); + expect(screen.queryByText(/invalid/i)).not.toBeInTheDocument(); + expect( + screen.queryByText(/must be at least 6 characters/i) + ).not.toBeInTheDocument(); + }); + + it('calls handleChange and updates error messages dynamically', async () => { + let formData = { fullName: '', email: '', password: '' }; + let errors = validate(formData, step); + + const handleChangeTest = (field, value) => { + formData = { ...formData, [field]: value }; + errors = validate(formData, step); + }; + + const { rerender } = render( + + handleChangeTest(target.name, target.value) + } + errors={errors} + /> + ); + + const fullNameInput = screen.getByLabelText(/Full Name/i); + await userEvent.type(fullNameInput, 'John'); + + rerender( + + handleChangeTest(target.name, target.value) + } + errors={errors} + /> + ); + + expect( + screen.getByText(/Full Name must contain at least two words/i) + ).toBeInTheDocument(); + }); + + it('retains user input in form fields', () => { + const formData = { + fullName: 'Jane Doe', + email: 'jane.doe@example.com', + password: 'securepassword', + }; + const errors = validate(formData, step); + + render( + {}} + errors={errors} + /> + ); + + expect(screen.getByLabelText(/Full Name/i)).toHaveValue('Jane Doe'); + expect(screen.getByLabelText(/Email/i)).toHaveValue('jane.doe@example.com'); + expect(screen.getByLabelText(/Password/i)).toHaveValue('securepassword'); + }); +}); diff --git a/07_js-debug/projects/debugging-multi-step-form-template/tests/validation/step2.test.jsx b/07_js-debug/projects/debugging-multi-step-form-template/tests/validation/step2.test.jsx new file mode 100644 index 0000000..7505148 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/tests/validation/step2.test.jsx @@ -0,0 +1,114 @@ +import { it, expect, describe, afterEach } from 'vitest'; +import { render, screen, cleanup } from '@testing-library/react'; +import '@testing-library/jest-dom/vitest'; +import userEvent from '@testing-library/user-event'; + +import ActivityInfo from '../../src/steps/ActivityInfo'; +import { validate } from '../../src/utils/validation'; + +describe('ActivityInfo Component', () => { + afterEach(cleanup); + + const step = 2; + + it('renders all form fields', () => { + render( {}} errors={{}} />); + + expect( + screen.getByLabelText(/How often do you exercise\?/i) + ).toBeInTheDocument(); + expect( + screen.getByLabelText( + /How would you describe your average energy level\?/i + ) + ).toBeInTheDocument(); + }); + + it('displays validation errors for invalid data', () => { + const formData = { + fullName: 'John Doe', + email: 'john@example.com', + password: 'password123', + activityLevel: '', + energyLevel: '', + goals: [], + timeCommitment: '15', + }; + const errors = validate(formData, step); + + render( {}} errors={errors} />); + + expect(screen.getByText(/Activity Level is required/i)).toBeInTheDocument(); + expect(screen.getByText(/Energy Level is required/i)).toBeInTheDocument(); + }); + + it('displays no validation errors for valid data', () => { + const formData = { + fullName: 'John Doe', + email: 'john@example.com', + password: 'password123', + activityLevel: 'moderate', + energyLevel: 'high', + goals: [], + timeCommitment: '15', + }; + const errors = validate(formData, step); + + render( {}} errors={errors} />); + + expect(screen.queryByText(/is required/i)).not.toBeInTheDocument(); + }); + + it('calls handleChange and updates error messages dynamically', async () => { + let formData = { + fullName: 'John Doe', + email: 'john@example.com', + password: 'password123', + activityLevel: '', + energyLevel: '', + goals: [], + timeCommitment: '15', + }; + let errors = validate(formData, step); + + const handleChangeTest = (field, value) => { + formData = { ...formData, [field]: value }; + errors = validate(formData, step); + }; + + const { rerender } = render( + + handleChangeTest(target.name, target.value) + } + errors={errors} + /> + ); + + const activitySelect = screen.getByLabelText( + /How often do you exercise\?/i + ); + const energySelect = screen.getByLabelText( + /How would you describe your average energy level\?/i + ); + + await userEvent.selectOptions(activitySelect, '3+ times a week'); + await userEvent.selectOptions(energySelect, 'medium'); + + rerender( + + handleChangeTest(target.name, target.value) + } + errors={errors} + /> + ); + + expect( + screen.queryByText(/Activity Level is required/i) + ).not.toBeInTheDocument(); + expect( + screen.queryByText(/Energy Level is required/i) + ).not.toBeInTheDocument(); + }); +}); diff --git a/07_js-debug/projects/debugging-multi-step-form-template/tests/validation/step3.test.jsx b/07_js-debug/projects/debugging-multi-step-form-template/tests/validation/step3.test.jsx new file mode 100644 index 0000000..9f18107 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/tests/validation/step3.test.jsx @@ -0,0 +1,139 @@ +import { it, expect, describe, afterEach } from 'vitest'; +import { render, screen, cleanup } from '@testing-library/react'; +import '@testing-library/jest-dom/vitest'; +import userEvent from '@testing-library/user-event'; + +import GoalSetting from '../../src/steps/GoalSetting'; +import { validate } from '../../src/utils/validation'; + +describe('GoalSetting Component', () => { + afterEach(cleanup); + + const step = 3; + + it('renders all form fields', () => { + render( + {}} + handleCheckboxChange={() => {}} + errors={{}} + />, + ); + + // Use getByRole to target the fieldset for "What are your goals?" + expect(screen.getByRole('group', { name: /What are your goals\?/i })).toBeInTheDocument(); + + expect(screen.getByLabelText(/How much time can you commit each day\?/i)).toBeInTheDocument(); + }); + + it('displays validation errors for empty fields', () => { + const formData = { + goals: [], + timeCommitment: '', + }; + const errors = validate(formData, step); + + render( {}} handleCheckboxChange={() => {}} errors={errors} />); + + expect(screen.getByText(/At least one goal is required/i)).toBeInTheDocument(); + expect(screen.getByText(/Time Commitment is required/i)).toBeInTheDocument(); + }); + + it('displays no validation errors for valid data', () => { + const formData = { + goals: ['weightLoss', 'muscleGain'], + timeCommitment: '30', + }; + const errors = validate(formData, step); + + render( {}} handleCheckboxChange={() => {}} errors={errors} />); + + expect(screen.queryByText(/is required/i)).not.toBeInTheDocument(); + }); + + it('handles checkbox interactions and updates goals dynamically', async () => { + let formData = { goals: [], timeCommitment: '' }; + let errors = validate(formData, step); + + const handleCheckboxChangeTest = (field, id, isChecked) => { + const updatedGoals = isChecked ? [...formData[field], id] : formData[field].filter((goal) => goal !== id); + + formData = { ...formData, [field]: updatedGoals }; + errors = validate(formData, step); + }; + + const { rerender } = render( + {}} + handleCheckboxChange={handleCheckboxChangeTest} + errors={errors} + />, + ); + + const weightLossCheckbox = screen.getByLabelText(/Weight Loss/i); + const muscleGainCheckbox = screen.getByLabelText(/Muscle Gain/i); + + await userEvent.click(weightLossCheckbox); + rerender( + {}} + handleCheckboxChange={handleCheckboxChangeTest} + errors={errors} + />, + ); + + expect(weightLossCheckbox).toBeChecked(); + expect(screen.queryByText(/At least one goal is required/i)).not.toBeInTheDocument(); + + await userEvent.click(muscleGainCheckbox); + rerender( + {}} + handleCheckboxChange={handleCheckboxChangeTest} + errors={errors} + />, + ); + + expect(muscleGainCheckbox).toBeChecked(); + expect(formData.goals).toContain('weightLoss'); + expect(formData.goals).toContain('muscleGain'); + }); + + it('handles select interactions and updates time commitment dynamically', async () => { + let formData = { goals: ['weightLoss'], timeCommitment: '' }; + let errors = validate(formData, step); + + const handleChangeTest = (field, value) => { + formData = { ...formData, [field]: value }; + errors = validate(formData, step); + }; + + const { rerender } = render( + handleChangeTest(target.name, target.value)} + handleCheckboxChange={() => {}} + errors={errors} + />, + ); + + const timeCommitmentSelect = screen.getByLabelText(/How much time can you commit each day\?/i); + await userEvent.selectOptions(timeCommitmentSelect, '30'); + + rerender( + handleChangeTest(target.name, target.value)} + handleCheckboxChange={() => {}} + errors={errors} + />, + ); + + expect(timeCommitmentSelect).toHaveValue('30'); + expect(screen.queryByText(/Time Commitment is required/i)).not.toBeInTheDocument(); + }); +}); diff --git a/07_js-debug/projects/debugging-multi-step-form-template/tests/validation/utility.test.js b/07_js-debug/projects/debugging-multi-step-form-template/tests/validation/utility.test.js new file mode 100644 index 0000000..6c3b9cd --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/tests/validation/utility.test.js @@ -0,0 +1,58 @@ +import { describe, it, expect } from 'vitest'; +import { + isEmpty, + isValidEmail, + hasMinLength, + hasTwoWords, +} from '../../src/utils/validation'; + +describe('Utility Functions', () => { + describe('isEmpty', () => { + it('should return true for empty strings', () => { + expect(isEmpty('')).toBe(true); + expect(isEmpty(' ')).toBe(true); + }); + + it('should return false for non-empty strings', () => { + expect(isEmpty('John')).toBe(false); + expect(isEmpty(' John Doe ')).toBe(false); + }); + }); + + describe('isValidEmail', () => { + it('should validate correct email formats', () => { + expect(isValidEmail('john@example.com')).toBe(true); + expect(isValidEmail('jane.doe@sub.domain.co')).toBe(true); + }); + + it('should invalidate incorrect email formats', () => { + expect(isValidEmail('johnexample.com')).toBe(false); + expect(isValidEmail('jane@.com')).toBe(false); + expect(isValidEmail('jane@com')).toBe(false); + }); + }); + + describe('hasMinLength', () => { + it('should return true if value meets minimum length', () => { + expect(hasMinLength('password', 6)).toBe(true); + expect(hasMinLength('123456', 6)).toBe(true); + }); + + it('should return false if value does not meet minimum length', () => { + expect(hasMinLength('pass', 6)).toBe(false); + expect(hasMinLength('123', 6)).toBe(false); + }); + }); + + describe('hasTwoWords', () => { + it('should return true if fullName has at least two words', () => { + expect(hasTwoWords('John Doe')).toBe(true); + expect(hasTwoWords('Jane Mary Doe')).toBe(true); + }); + + it('should return false if fullName has less than two words', () => { + expect(hasTwoWords('John')).toBe(false); + expect(hasTwoWords(' Jane ')).toBe(false); + }); + }); +}); diff --git a/07_js-debug/projects/debugging-multi-step-form-template/vite.config.js b/07_js-debug/projects/debugging-multi-step-form-template/vite.config.js new file mode 100644 index 0000000..8b0f57b --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], +}) diff --git a/07_js-debug/projects/debugging-multi-step-form-template/vitest.config.js b/07_js-debug/projects/debugging-multi-step-form-template/vitest.config.js new file mode 100644 index 0000000..5853726 --- /dev/null +++ b/07_js-debug/projects/debugging-multi-step-form-template/vitest.config.js @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + test: { + environment: 'jsdom', + }, + plugins: [react()], +});