Skip to content

Commit ab4da58

Browse files
authored
Merge pull request #32 from fraidakis/fraidakis
docs: add comprehensive documentation
2 parents 8df39a9 + 2aa0fd2 commit ab4da58

54 files changed

Lines changed: 1299 additions & 29 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cypress/e2e/auth_login_logout.cy.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,40 @@
11
/**
2-
* E2E Tests for Login & Logout Flows
2+
* @fileoverview E2E Tests for Login & Logout Flows
3+
* Tests authentication workflow, session persistence, and protected routes.
34
* Split from auth_happy_unhappy.cy.js for file size optimization
5+
* @module cypress/e2e/auth_login_logout
46
*/
7+
58
import { visitLogin, expectUrlToEqual, expectUrlToContain, fillLoginForm, submitForm, logMessage } from '../support/helpers';
69

10+
/**
11+
* Test suite for authentication flows.
12+
* Covers login, logout, session persistence, and route protection.
13+
*/
714
describe('Login & Logout Flows', () => {
15+
// Clear state before each test for isolation
816
beforeEach(() => { cy.clearLocalStorage(); cy.clearCookies(); });
917

18+
/**
19+
* Login Page Tests
20+
* Verify login form renders and authentication succeeds with valid credentials.
21+
*/
1022
describe('Login Page', () => {
23+
// Test: Page loads correctly
1124
it('should load the login page', () => {
1225
visitLogin();
1326
cy.contains(/login/i).should('be.visible');
1427
});
1528

29+
// Test: Login with custom test user fixture
1630
it('should successfully log in with valid credentials', () => {
1731
cy.loginAsTestUser('validUser');
1832
expectUrlToEqual('/');
1933
cy.shouldBeAuthenticated();
2034
logMessage('✅ Successfully logged in with test user');
2135
});
2236

37+
// Test: Login with hardcoded demo credentials
2338
it('should log in with demo user credentials', () => {
2439
cy.login('user1@example.com', 'password123');
2540
cy.url().should('not.include', '/login');
@@ -28,7 +43,12 @@ describe('Login & Logout Flows', () => {
2843
});
2944
});
3045

46+
/**
47+
* Logout Tests
48+
* Verify logout clears session and redirects appropriately.
49+
*/
3150
describe('Logout', () => {
51+
// Test: Programmatic logout
3252
it('should successfully log out', () => {
3353
cy.loginAsTestUser('validUser');
3454
cy.url().should('not.include', '/login');
@@ -37,6 +57,7 @@ describe('Login & Logout Flows', () => {
3757
logMessage('✅ Successfully logged out');
3858
});
3959

60+
// Test: Logout via UI dropdown button
4061
it('should log out via UI logout button', () => {
4162
cy.loginAsTestUser('validUser');
4263
cy.get('[data-cy="user-dropdown-trigger"]').should('be.visible').click();
@@ -47,7 +68,12 @@ describe('Login & Logout Flows', () => {
4768
});
4869
});
4970

71+
/**
72+
* Session Persistence Tests
73+
* Verify session survives page reloads and data is stored correctly.
74+
*/
5075
describe('Session Persistence', () => {
76+
// Test: Session survives reload
5177
it('should maintain session after page reload', () => {
5278
cy.loginAsTestUser('validUser');
5379
expectUrlToEqual('/');
@@ -57,6 +83,7 @@ describe('Login & Logout Flows', () => {
5783
logMessage('✅ Session persists after page reload');
5884
});
5985

86+
// Test: User data in localStorage is correct
6087
it('should restore user data from localStorage', () => {
6188
cy.loginAsTestUser('validUser');
6289
cy.window().its('localStorage.user').should('exist');
@@ -69,7 +96,12 @@ describe('Login & Logout Flows', () => {
6996
});
7097
});
7198

99+
/**
100+
* Protected Route Tests
101+
* Verify authenticated users can access protected routes.
102+
*/
72103
describe('Protected Routes', () => {
104+
// Test: Authenticated access to profile page
73105
it('should allow access to protected route when authenticated', () => {
74106
cy.loginAsTestUser('validUser');
75107
cy.visit('/profile');

cypress/e2e/auth_validation.cy.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
/**
2-
* E2E Tests for Authentication Validation Errors
2+
* @fileoverview E2E Tests for Authentication Validation Errors
3+
* Tests form validation, error messages, and protected route access.
34
* Split from auth_happy_unhappy.cy.js for file size optimization
5+
* @module cypress/e2e/auth_validation
46
*/
7+
58
import { visitLogin, visitSignup, expectUrlToContain, fillLoginForm, fillSignupForm, submitForm, getRandomEmail, logMessage } from '../support/helpers';
69

10+
/**
11+
* Test suite for authentication validation.
12+
* Covers signup validation, login errors, and route protection.
13+
*/
714
describe('Authentication Validation Errors', () => {
15+
// Clear state before each test for isolation
816
beforeEach(() => { cy.clearLocalStorage(); cy.clearCookies(); });
917

18+
/**
19+
* Signup Validation Tests
20+
* Tests email format, password strength, and required fields.
21+
*/
1022
describe('Signup Validation Errors', () => {
23+
// Test: Invalid email format validation
1124
it('should show email validation error for invalid email format', () => {
1225
cy.intercept('POST', '**/auth/signup').as('signupRequest');
1326
visitSignup();
@@ -18,6 +31,7 @@ describe('Authentication Validation Errors', () => {
1831
cy.window().its('localStorage.token').should('not.exist');
1932
});
2033

34+
// Test: Weak password validation
2135
it('should show password strength error for weak password', () => {
2236
visitSignup();
2337
fillSignupForm({ name: 'Test User', email: getRandomEmail(), password: 'weak', confirmPassword: 'weak' });
@@ -26,6 +40,7 @@ describe('Authentication Validation Errors', () => {
2640
expectUrlToContain('/signup');
2741
});
2842

43+
// Test: Password confirmation mismatch
2944
it('should show error for mismatched password confirmation', () => {
3045
visitSignup();
3146
cy.get('[data-cy="input-name"]').clear().type('Test User');
@@ -37,6 +52,7 @@ describe('Authentication Validation Errors', () => {
3752
expectUrlToContain('/signup');
3853
});
3954

55+
// Test: Required fields validation
4056
it('should show required field errors for empty form submission', () => {
4157
visitSignup();
4258
submitForm();
@@ -61,7 +77,12 @@ describe('Authentication Validation Errors', () => {
6177
});
6278
});
6379

80+
/**
81+
* Login Authentication Error Tests
82+
* Tests wrong credentials, required fields, and invalid email.
83+
*/
6484
describe('Login Authentication Errors', () => {
85+
// Test: Invalid credentials returns auth error
6586
it('should show auth error for incorrect credentials', () => {
6687
cy.intercept('POST', '**/auth/login', { statusCode: 401, body: { success: false, message: 'Invalid credentials' } }).as('login');
6788
visitLogin();
@@ -88,7 +109,12 @@ describe('Authentication Validation Errors', () => {
88109
});
89110
});
90111

112+
/**
113+
* Protected Route Access Control Tests
114+
* Verifies unauthenticated users are redirected to login.
115+
*/
91116
describe('Protected Route Access Control - Unauthenticated', () => {
117+
// Routes requiring authentication
92118
const protectedRoutes = [
93119
{ path: '/recommendations', name: 'Recommendations' },
94120
{ path: '/profile', name: 'User Profile' },

src/App.jsx

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
1+
/**
2+
* @fileoverview Root Application Component.
3+
*
4+
* This is the main application component that sets up the entire application
5+
* structure including:
6+
* - Context providers (Theme, Language, Toast)
7+
* - React Router configuration
8+
* - Layout structure (Header, Main, Footer, Bottom Navigation)
9+
* - Authentication state management
10+
*
11+
* The component hierarchy ensures all child components have access to:
12+
* - Theme context for light/dark mode
13+
* - Language context for i18n translations
14+
* - Toast context for notifications
15+
* - Router context for navigation
16+
*
17+
* @module App
18+
* @requires react
19+
* @requires react-router-dom
20+
* @requires ./i18n - Language provider
21+
* @requires ./context - Theme provider
22+
*/
23+
124
import React, { useState, useEffect } from 'react';
225
import { BrowserRouter as Router } from 'react-router-dom';
326
import { LanguageProvider } from './i18n';
@@ -9,44 +32,78 @@ import ScrollToTop from './components/ScrollToTop.jsx';
932
import AppRoutes from './router/index.jsx';
1033
import './App.css';
1134

35+
/**
36+
* App Component
37+
*
38+
* The root component that wraps the entire application with necessary
39+
* providers and sets up the main layout structure. Tracks authentication
40+
* state for conditional rendering of navigation elements.
41+
*
42+
* Provider hierarchy (outermost to innermost):
43+
* 1. ThemeProvider - Dark/light mode
44+
* 2. LanguageProvider - Internationalization
45+
* 3. ToastProvider - Notification system
46+
* 4. Router - Navigation
47+
*
48+
* @function App
49+
* @returns {React.ReactElement} The complete application structure
50+
*/
1251
function App() {
52+
// Track user authentication state for conditional UI
1353
const [isAuthenticated, setIsAuthenticated] = useState(false);
1454

55+
/**
56+
* Sets up authentication state tracking on mount.
57+
* Listens for login/logout events and storage changes.
58+
*/
1559
useEffect(() => {
1660
// Check for existing token on mount
1761
const token = localStorage.getItem('token');
1862
setIsAuthenticated(!!token);
1963

20-
// Listen for login/logout events
64+
// Event handlers for auth state changes
2165
const handleLogin = () => setIsAuthenticated(true);
2266
const handleLogout = () => setIsAuthenticated(false);
2367

68+
// Listen for custom login/logout events
2469
window.addEventListener('user:login', handleLogin);
2570
window.addEventListener('user:logout', handleLogout);
71+
72+
// Listen for storage changes (handles logout from other tabs)
2673
window.addEventListener('storage', (e) => {
2774
if (e.key === 'token') {
2875
setIsAuthenticated(!!e.newValue);
2976
}
3077
});
3178

79+
// Cleanup event listeners on unmount
3280
return () => {
3381
window.removeEventListener('user:login', handleLogin);
3482
window.removeEventListener('user:logout', handleLogout);
3583
};
3684
}, []);
3785

3886
return (
87+
// Theme provider for dark/light mode support
3988
<ThemeProvider>
89+
{/* Language provider for internationalization */}
4090
<LanguageProvider>
91+
{/* Toast provider for notification system */}
4192
<ToastProvider>
93+
{/* React Router for client-side navigation */}
4294
<Router>
95+
{/* Scroll restoration on route change */}
4396
<ScrollToTop />
4497
<div className="App">
98+
{/* Site header with navigation */}
4599
<Header />
100+
{/* Main content area with routes */}
46101
<main className="main-content">
47102
<AppRoutes />
48103
</main>
104+
{/* Site footer */}
49105
<Footer />
106+
{/* Mobile bottom navigation bar */}
50107
<BottomNavigation isAuthenticated={isAuthenticated} />
51108
</div>
52109
</Router>
@@ -57,3 +114,4 @@ function App() {
57114
}
58115

59116
export default App;
117+

src/components/3d/TravelGlobe.jsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
/**
2+
* @fileoverview 3D Travel Globe component.
3+
* Interactive globe with orbiting satellites using Three.js.
4+
* @module components/3d/TravelGlobe
5+
*/
6+
17
import React, { useRef } from 'react';
28
import { Canvas, useFrame } from '@react-three/fiber';
39
import { Icosahedron, OrbitControls, Stars } from '@react-three/drei';

src/components/Carousel3D.jsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
/**
2+
* @fileoverview 3D Coverflow-style carousel component.
3+
* Features smooth animations, drag support, and keyboard navigation.
4+
* @module components/Carousel3D
5+
*/
6+
17
import React, { useState, useEffect, useRef, useCallback } from 'react';
28
import PropTypes from 'prop-types';
39
import Icon from './ui/Icon';

src/components/Footer.jsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
/**
2+
* @fileoverview Site footer component.
3+
* Contains branding, navigation links, and copyright.
4+
* @module components/Footer
5+
*/
6+
17
import React from 'react';
28
import { Link } from 'react-router-dom';
39
import { useTranslation } from '../i18n';

src/components/Header.jsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
/**
2+
* @fileoverview Site header component.
3+
* Professional navigation with glassmorphism, user dropdown, and scroll effects.
4+
* @module components/Header
5+
*/
6+
17
import React, { useState, useEffect } from 'react';
28
import { Link, useLocation } from 'react-router-dom';
39
import { useAuth } from '../hooks';
Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,52 @@
1+
/**
2+
* @fileoverview Language Switcher Component for internationalization support.
3+
*
4+
* Provides a button that allows users to toggle between English and Greek
5+
* languages in the application. Uses the translation context to manage
6+
* the current language state.
7+
*
8+
* @module components/LanguageSwitcher
9+
* @requires react
10+
* @requires ../i18n - Translation context and hooks
11+
*/
12+
113
import React from 'react';
214
import { useTranslation } from '../i18n';
315
import './LanguageSwitcher.css';
416

17+
/**
18+
* LanguageSwitcher Component
19+
*
20+
* A button component that toggles the application language between
21+
* English (EN) and Greek (EL). The button displays the opposite language
22+
* code from the currently active language, indicating what language
23+
* the user will switch to upon clicking.
24+
*
25+
* @component
26+
* @example
27+
* // Basic usage in a navigation bar
28+
* <LanguageSwitcher />
29+
*
30+
* @returns {React.ReactElement} A styled button for language toggling
31+
*
32+
* @see {@link module:i18n/LanguageContext} for language context implementation
33+
*/
534
const LanguageSwitcher = () => {
35+
// Get current language and toggle function from translation context
636
const { language, toggleLanguage } = useTranslation();
737

838
return (
9-
<button
10-
className="language-switcher"
39+
<button
40+
className="language-switcher"
1141
onClick={toggleLanguage}
1242
aria-label="Change language"
1343
>
44+
{/* Globe emoji followed by the target language code */}
45+
{/* Shows 'EL' when current language is English, 'EN' when Greek */}
1446
🌐 {language === 'en' ? 'EL' : 'EN'}
1547
</button>
1648
);
1749
};
1850

1951
export default LanguageSwitcher;
52+

src/components/UserDropdown.jsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
/**
2+
* @fileoverview User dropdown menu component.
3+
* Avatar with dropdown for profile, preferences, and logout.
4+
* @module components/UserDropdown
5+
*/
6+
17
import React, { useState, useEffect, useRef } from 'react';
28
import { Link } from 'react-router-dom';
39
import { useAuth } from '../hooks';

0 commit comments

Comments
 (0)