diff --git a/frontend/src/components/common/ConfirmationDialog.jsx b/frontend/src/components/common/ConfirmationDialog.jsx index f07a033..d842a89 100644 --- a/frontend/src/components/common/ConfirmationDialog.jsx +++ b/frontend/src/components/common/ConfirmationDialog.jsx @@ -1,3 +1,4 @@ +/* eslint-disable react/prop-types */ /* eslint-disable no-unused-vars */ // frontend/src/components/common/ConfirmationDialog.jsx import React from 'react'; @@ -17,7 +18,10 @@ const ConfirmationDialog = ({ message = "Are you sure you want to proceed? This action cannot be undone.", // Default message confirmText = "Confirm", // Default confirm button text cancelText = "Cancel", // Default cancel button text - isProcessing = false // Optional: disable buttons while processing confirm action + isProcessing = false, // Optional: disable buttons while processing confirm action + dialogTestId = "confirmation-dialog", + confirmButtonTestId = "confirmation-dialog-confirm-button", + cancelButtonTestId = "confirmation-dialog-cancel-button" }) => { return ( @@ -26,6 +30,7 @@ const ConfirmationDialog = ({ onClose={() => !isProcessing && onClose()} // Prevent closing while processing aria-labelledby="confirmation-dialog-title" aria-describedby="confirmation-dialog-description" + data-testid={dialogTestId} // <<< ADDED TEST ID > {title} @@ -36,7 +41,7 @@ const ConfirmationDialog = ({ - {/* Make confirm button stand out, often uses primary or error color */} @@ -46,6 +51,7 @@ const ConfirmationDialog = ({ variant="contained" // Make it more prominent autoFocus // Focus on confirm by default disabled={isProcessing} + data-testid={confirmButtonTestId} > {isProcessing ? "Processing..." : confirmText} diff --git a/frontend/src/components/common/EditableField.jsx b/frontend/src/components/common/EditableField.jsx index 37bf383..966e6c4 100644 --- a/frontend/src/components/common/EditableField.jsx +++ b/frontend/src/components/common/EditableField.jsx @@ -8,6 +8,7 @@ import CheckIcon from '@mui/icons-material/Check'; import CloseIcon from '@mui/icons-material/Close'; const EditableField = ({ + testIdPrefix, // Optional: Prefix for test IDs (e.g., "student-name") label, // Label for the TextField in edit mode AND display mode now value, // The current value to display onSave, // Async function to call when saving (receives new value) @@ -46,9 +47,12 @@ const EditableField = ({ } }; + // Helper function to generate test ID only if prefix is provided + const addTestId = (suffix) => (testIdPrefix ? { [`data-testid`]: `${testIdPrefix}-${suffix}` } : {}); + return ( // Container - align items to the start (top) for label - + {!isEditing ? ( // --- MODIFIED Display Mode --- <> @@ -68,15 +72,15 @@ const EditableField = ({ color: !value ? 'text.secondary' : 'inherit', // Apply word break for safety, although less likely needed for single-line fields overflowWrap: 'break-word', - lineHeight: 1.4 // Adjust line height if needed - }} + lineHeight: 1.4}} // Adjust line height if needed + {...addTestId('display')} // <<< ADDED TEST ID FOR DISPLAY VALUE > {/* Use value, fallback to emptyText. Placeholder less relevant here */} {value || emptyText} {/* Edit Button */} - + @@ -95,11 +99,15 @@ const EditableField = ({ rows={multiline ? rows : 1} {...textFieldProps} disabled={isSaving} + // Add test ID to the TextField wrapper - Cypress can find input inside + {...addTestId('input-wrapper')} // <<< ADDED TEST ID FOR TEXTFIELD WRAPPER + // Alternatively, add directly to inputProps if needed, but wrapper is often easier + // inputProps={{ ...textFieldProps?.inputProps, ...addTestId('input') }} /> - + - + diff --git a/frontend/src/components/common/EditableTextArea.jsx b/frontend/src/components/common/EditableTextArea.jsx index 5370116..e4f0252 100644 --- a/frontend/src/components/common/EditableTextArea.jsx +++ b/frontend/src/components/common/EditableTextArea.jsx @@ -8,6 +8,7 @@ import CheckIcon from '@mui/icons-material/Check'; import CloseIcon from '@mui/icons-material/Close'; const EditableTextArea = ({ + testIdPrefix, label, // Label for the TextField in edit mode AND display mode now value, // The current value to display onSave, // Async function to call when saving (receives new value) @@ -45,9 +46,12 @@ const EditableTextArea = ({ } }; + // Helper function to generate test ID only if prefix is provided + const addTestId = (suffix) => (testIdPrefix ? { [`data-testid`]: `${testIdPrefix}-${suffix}` } : {}); + return ( // Container remains largely the same - + {!isEditing ? ( // Display Mode @@ -67,11 +71,12 @@ const EditableTextArea = ({ color: !value ? 'text.secondary' : 'inherit', minHeight: '20px' }} + {...addTestId('display')} > {value?.trim() || placeholder || emptyText} - + @@ -90,12 +95,15 @@ const EditableTextArea = ({ autoFocus {...textFieldProps} disabled={isSaving} + {...addTestId('input-wrapper')} // <<< ADDED TEST ID FOR TEXTFIELD WRAPPER + // You might need to target the actual textarea element inside this wrapper in tests + // using .find('textarea') /> - + - + diff --git a/frontend/src/components/opportunities/AddOpportunityForm.jsx b/frontend/src/components/opportunities/AddOpportunityForm.jsx index bfdd70a..c95873a 100644 --- a/frontend/src/components/opportunities/AddOpportunityForm.jsx +++ b/frontend/src/components/opportunities/AddOpportunityForm.jsx @@ -91,10 +91,11 @@ const AddOpportunityForm = ({ open, onClose, onSave, initialData = null, isSavin }; return ( - !isSaving && onClose()} maxWidth="sm" fullWidth> {/* Prevent closing while saving */} + !isSaving && onClose()} maxWidth="sm" fullWidth data-testid="opportunity-form-dialog"> {/* Prevent closing while saving */} {initialData ? 'Edit Opportunity Post' : 'Create New Opportunity Post'} - + Type { - - @@ -305,4 +319,4 @@ const ProfessorCourses = () => { ); }; -export default ProfessorCourses; +export default ProfessorCourses; \ No newline at end of file diff --git a/frontend/src/pages/ProfessorDashboard.jsx b/frontend/src/pages/ProfessorDashboard.jsx index 8bbfb33..7102188 100644 --- a/frontend/src/pages/ProfessorDashboard.jsx +++ b/frontend/src/pages/ProfessorDashboard.jsx @@ -92,6 +92,18 @@ const ProfessorDashboard = () => { const navigate = useNavigate(); const storage = getStorage(app); + + {/* Define the prefixes */} + const profileTestIdPrefixes = { + name: 'prof-profile-name', + headline: 'prof-profile-headline', + pronouns: 'prof-profile-pronouns', + department: 'prof-profile-department', + about: 'prof-profile-about', + // resume: 'prof-profile-resume' // If you add to FileUploadField + }; + + // +++ UPDATED useEffect for Realtime Professor Data +++ useEffect(() => { setUiLoading(true); @@ -487,18 +499,19 @@ const ProfessorDashboard = () => { {isSaving && ( )} - - - - + + + + @@ -511,8 +524,10 @@ const ProfessorDashboard = () => { onEditPhoto={handleTriggerEditPhoto} onViewPhoto={handleTriggerViewPhoto} /> + {/* --- Render ProfileInfoSection --- */} { handleResumeSave={handleResumeSave} handleResumeDelete={handleResumeDelete} handleDepartmentSave={handleDepartmentSave} + // You might need to pass prefixes down if ProfileInfoSection renders EditableFields + // testIdPrefixes={{ + // name: 'prof-profile-name', + // headline: 'prof-profile-headline', + // // etc. + // }} /> @@ -539,7 +560,7 @@ const ProfessorDashboard = () => { gap: 2, mb: 2, }} - > + > My Posted Opportunities @@ -547,6 +568,7 @@ const ProfessorDashboard = () => {