unit tests fixin
Some checks failed
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Failing after 58s
Some checks failed
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Failing after 58s
This commit is contained in:
@@ -112,10 +112,11 @@ describe('ProfileManager Authentication Flows', () => {
|
|||||||
fireEvent.click(screen.getByRole('button', { name: /^sign in$/i }));
|
fireEvent.click(screen.getByRole('button', { name: /^sign in$/i }));
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(apiClient.loginUser).toHaveBeenCalledWith('user@test.com', 'securepassword');
|
expect(apiClient.loginUser).toHaveBeenCalledWith('user@test.com', 'securepassword', false);
|
||||||
expect(mockOnLoginSuccess).toHaveBeenCalledWith(
|
expect(mockOnLoginSuccess).toHaveBeenCalledWith(
|
||||||
{ id: '123', email: 'test@example.com' },
|
{ id: '123', email: 'test@example.com' },
|
||||||
'mock-token'
|
'mock-token',
|
||||||
|
false
|
||||||
);
|
);
|
||||||
expect(mockOnClose).toHaveBeenCalled();
|
expect(mockOnClose).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
@@ -129,7 +130,7 @@ describe('ProfileManager Authentication Flows', () => {
|
|||||||
fireEvent.change(screen.getByLabelText(/^Password$/i), { target: { value: 'wrongpassword' } });
|
fireEvent.change(screen.getByLabelText(/^Password$/i), { target: { value: 'wrongpassword' } });
|
||||||
fireEvent.click(screen.getByRole('button', { name: /^sign in$/i }));
|
fireEvent.click(screen.getByRole('button', { name: /^sign in$/i }));
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(screen.getByText('Invalid credentials')).toBeInTheDocument();
|
expect(screen.getByText('Invalid credentials')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
expect(mockOnLoginSuccess).not.toHaveBeenCalled();
|
expect(mockOnLoginSuccess).not.toHaveBeenCalled();
|
||||||
@@ -142,7 +143,11 @@ describe('ProfileManager Authentication Flows', () => {
|
|||||||
|
|
||||||
fireEvent.click(screen.getByRole('button', { name: /^sign in$/i }));
|
fireEvent.click(screen.getByRole('button', { name: /^sign in$/i }));
|
||||||
|
|
||||||
expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
|
await waitFor(() => {
|
||||||
|
const button = screen.getByRole('button', { name: /^Sign In$/i });
|
||||||
|
expect(button).toBeDisabled();
|
||||||
|
expect(button.querySelector('svg.animate-spin')).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- Registration Functionality ---
|
// --- Registration Functionality ---
|
||||||
@@ -165,10 +170,11 @@ describe('ProfileManager Authentication Flows', () => {
|
|||||||
fireEvent.click(screen.getByRole('button', { name: /register/i })); // Submit register form
|
fireEvent.click(screen.getByRole('button', { name: /register/i })); // Submit register form
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(apiClient.registerUser).toHaveBeenCalledWith('newuser@test.com', 'newsecurepassword');
|
expect(apiClient.registerUser).toHaveBeenCalledWith('newuser@test.com', 'newsecurepassword', '', '');
|
||||||
expect(mockOnLoginSuccess).toHaveBeenCalledWith(
|
expect(mockOnLoginSuccess).toHaveBeenCalledWith(
|
||||||
{ id: '123', email: 'test@example.com' },
|
{ id: '123', email: 'test@example.com' },
|
||||||
'mock-token'
|
'mock-token',
|
||||||
|
false
|
||||||
);
|
);
|
||||||
expect(mockOnClose).toHaveBeenCalled();
|
expect(mockOnClose).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
@@ -193,7 +199,8 @@ describe('ProfileManager Authentication Flows', () => {
|
|||||||
expect(apiClient.registerUser).toHaveBeenCalledWith('newuser@test.com', 'newsecurepassword', 'New Test User', 'http://example.com/new.png');
|
expect(apiClient.registerUser).toHaveBeenCalledWith('newuser@test.com', 'newsecurepassword', 'New Test User', 'http://example.com/new.png');
|
||||||
expect(mockOnLoginSuccess).toHaveBeenCalledWith(
|
expect(mockOnLoginSuccess).toHaveBeenCalledWith(
|
||||||
{ id: '123', email: 'test@example.com' },
|
{ id: '123', email: 'test@example.com' },
|
||||||
'mock-token'
|
'mock-token',
|
||||||
|
false
|
||||||
);
|
);
|
||||||
expect(mockOnClose).toHaveBeenCalled();
|
expect(mockOnClose).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ export const ProfileManager: React.FC<ProfileManagerProps> = ({ isOpen, onClose,
|
|||||||
const [authLoading, setAuthLoading] = useState(false);
|
const [authLoading, setAuthLoading] = useState(false);
|
||||||
const [authError, setAuthError] = useState('');
|
const [authError, setAuthError] = useState('');
|
||||||
const [isForgotPassword, setIsForgotPassword] = useState(false);
|
const [isForgotPassword, setIsForgotPassword] = useState(false);
|
||||||
|
const [resetSuccessMessage, setResetSuccessMessage] = useState('');
|
||||||
const [rememberMe, setRememberMe] = useState(false);
|
const [rememberMe, setRememberMe] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
@@ -72,6 +73,7 @@ export const ProfileManager: React.FC<ProfileManagerProps> = ({ isOpen, onClose,
|
|||||||
setAuthError('');
|
setAuthError('');
|
||||||
setIsRegistering(false);
|
setIsRegistering(false);
|
||||||
setIsForgotPassword(false);
|
setIsForgotPassword(false);
|
||||||
|
setResetSuccessMessage('');
|
||||||
setRememberMe(false); // Reset on open
|
setRememberMe(false); // Reset on open
|
||||||
}
|
}
|
||||||
}, [isOpen, profile]); // Depend on isOpen and profile
|
}, [isOpen, profile]); // Depend on isOpen and profile
|
||||||
@@ -255,8 +257,9 @@ export const ProfileManager: React.FC<ProfileManagerProps> = ({ isOpen, onClose,
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setAuthLoading(true);
|
setAuthLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await requestPasswordReset(authEmail);
|
const { message } = await requestPasswordReset(authEmail);
|
||||||
notifySuccess(response.message);
|
// Instead of a toast, show an inline success message.
|
||||||
|
setResetSuccessMessage(message);
|
||||||
logger.info('Password reset email sent successfully.', { email: authEmail });
|
logger.info('Password reset email sent successfully.', { email: authEmail });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred.';
|
const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred.';
|
||||||
@@ -321,6 +324,11 @@ export const ProfileManager: React.FC<ProfileManagerProps> = ({ isOpen, onClose,
|
|||||||
<label htmlFor="resetEmail" className="block text-sm font-medium text-gray-700 dark:text-gray-300">Email Address</label>
|
<label htmlFor="resetEmail" className="block text-sm font-medium text-gray-700 dark:text-gray-300">Email Address</label>
|
||||||
<input id="resetEmail" type="email" value={authEmail} onChange={e => setAuthEmail(e.target.value)} required className="mt-1 block w-full px-3 py-2 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm" />
|
<input id="resetEmail" type="email" value={authEmail} onChange={e => setAuthEmail(e.target.value)} required className="mt-1 block w-full px-3 py-2 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm" />
|
||||||
</div>
|
</div>
|
||||||
|
{resetSuccessMessage && (
|
||||||
|
<div className="text-center text-sm text-green-600 dark:text-green-400 bg-green-50 dark:bg-green-900/20 p-3 rounded-md">
|
||||||
|
{resetSuccessMessage}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="pt-2">
|
<div className="pt-2">
|
||||||
<button type="submit" disabled={authLoading} className="w-full bg-brand-secondary hover:bg-brand-dark disabled:bg-gray-400 text-white font-bold py-2.5 px-4 rounded-lg flex justify-center">
|
<button type="submit" disabled={authLoading} className="w-full bg-brand-secondary hover:bg-brand-dark disabled:bg-gray-400 text-white font-bold py-2.5 px-4 rounded-lg flex justify-center">
|
||||||
{authLoading ? <div className="w-5 h-5"><LoadingSpinner /></div> : 'Send Reset Link'}
|
{authLoading ? <div className="w-5 h-5"><LoadingSpinner /></div> : 'Send Reset Link'}
|
||||||
@@ -337,6 +345,19 @@ export const ProfileManager: React.FC<ProfileManagerProps> = ({ isOpen, onClose,
|
|||||||
<div className="p-8">
|
<div className="p-8">
|
||||||
<h2 className="text-2xl font-bold text-gray-800 dark:text-white mb-1">{isRegistering ? 'Create an Account' : 'Sign In'}</h2>
|
<h2 className="text-2xl font-bold text-gray-800 dark:text-white mb-1">{isRegistering ? 'Create an Account' : 'Sign In'}</h2>
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400 mb-6">{isRegistering ? 'to get started.' : 'to access your account.'}</p>
|
<p className="text-sm text-gray-500 dark:text-gray-400 mb-6">{isRegistering ? 'to get started.' : 'to access your account.'}</p>
|
||||||
|
{/* When registering, show optional fields for full name and avatar URL */}
|
||||||
|
{isRegistering && (
|
||||||
|
<div className="space-y-4 mb-4">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="authFullName" className="block text-sm font-medium text-gray-700 dark:text-gray-300">Full Name</label>
|
||||||
|
<input id="authFullName" type="text" value={authFullName} onChange={e => setAuthFullName(e.target.value)} className="mt-1 block w-full px-3 py-2 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm" placeholder="Optional" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="authAvatarUrl" className="block text-sm font-medium text-gray-700 dark:text-gray-300">Avatar URL</label>
|
||||||
|
<input id="authAvatarUrl" type="url" value={authAvatarUrl} onChange={e => setAuthAvatarUrl(e.target.value)} className="mt-1 block w-full px-3 py-2 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm" placeholder="Optional, e.g., http://example.com/avatar.png" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<form onSubmit={handleAuthSubmit} className="space-y-4">
|
<form onSubmit={handleAuthSubmit} className="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="authEmail" className="block text-sm font-medium text-gray-700 dark:text-gray-300">Email Address</label>
|
<label htmlFor="authEmail" className="block text-sm font-medium text-gray-700 dark:text-gray-300">Email Address</label>
|
||||||
|
|||||||
Reference in New Issue
Block a user