1+ // standalone-ui/cypress/e2e/auth.cy.js
2+ // Tests for authentication flow including login, registration, and logout
3+
4+ describe ( 'Authentication' , ( ) => {
5+ // Helper function to create a random username
6+ const generateUsername = ( ) => `testuser${ Date . now ( ) } ` ;
7+
8+ // Setup for each test
9+ beforeEach ( ( ) => {
10+ // Any test setup can go here
11+ } ) ;
12+
13+ describe ( 'Login' , ( ) => {
14+ it ( 'should display login form' , ( ) => {
15+ cy . visit ( '/login' ) ;
16+
17+ // Check that the login form exists
18+ cy . get ( 'input[name="username"]' ) . should ( 'be.visible' ) ;
19+ cy . get ( 'input[name="password"]' ) . should ( 'be.visible' ) ;
20+ cy . contains ( 'button' , 'Log in' ) . should ( 'be.visible' ) ;
21+ } ) ;
22+
23+ it ( 'should show error message with invalid credentials' , ( ) => {
24+ const nonExistentUser = `nonexistent${ Date . now ( ) } ` ;
25+
26+ cy . visit ( '/login' ) ;
27+ cy . get ( 'input[name="username"]' ) . type ( nonExistentUser ) ;
28+ cy . get ( 'input[name="password"]' ) . type ( 'wrongpassword' ) ;
29+ cy . contains ( 'button' , 'Log in' ) . click ( ) ;
30+
31+ // Check for error message
32+ cy . contains ( 'Invalid username or password' ) . should ( 'be.visible' ) ;
33+
34+ // Should still be on login page
35+ cy . url ( ) . should ( 'include' , '/login' ) ;
36+ } ) ;
37+
38+ it ( 'should successfully log in with valid credentials' , ( ) => {
39+ // Create a user first
40+ cy . registerUser ( ) . then ( ( username ) => {
41+ // Log out first to ensure we're starting from a clean state
42+ cy . contains ( 'Log out' ) . click ( ) ;
43+
44+ // Wait for logout to complete
45+ cy . url ( ) . should ( 'include' , '/login' ) ;
46+
47+ // Now log in with the created user
48+ cy . login ( username , 'securePassword123' ) ;
49+
50+ // Check that we're redirected to the study page
51+ cy . url ( ) . should ( 'include' , '/study' ) ;
52+
53+ // Check that user is logged in
54+ cy . contains ( username ) . should ( 'be.visible' ) ;
55+ } ) ;
56+ } ) ;
57+
58+ it ( 'should redirect to intended page after login' , ( ) => {
59+ // Visit a protected route
60+ cy . visit ( '/study' ) ;
61+
62+ // Should be redirected to login
63+ cy . url ( ) . should ( 'include' , '/login' ) ;
64+
65+ // Log in
66+ cy . registerUser ( ) . then ( ( username ) => {
67+ // Should be redirected back to the originally requested page
68+ cy . url ( ) . should ( 'include' , '/study' ) ;
69+ } ) ;
70+ } ) ;
71+ } ) ;
72+
73+ describe ( 'Registration' , ( ) => {
74+ it ( 'should allow new user registration' , ( ) => {
75+ const username = generateUsername ( ) ;
76+ const password = 'securePassword123' ;
77+
78+ cy . visit ( '/signup' ) ;
79+
80+ // Fill out registration form
81+ cy . get ( 'input[name="username"]' ) . type ( username ) ;
82+ cy . get ( 'input[name="password"]' ) . type ( password ) ;
83+ cy . get ( 'input[name="retypedPassword"]' ) . type ( password ) ;
84+ cy . contains ( 'button' , 'Create Account' ) . click ( ) ;
85+
86+ // Check that registration was successful by checking URL or welcome message
87+ cy . url ( ) . should ( 'include' , `/u/${ username } /new` ) ;
88+ cy . contains ( `Welcome, ${ username } ` ) . should ( 'be.visible' ) ;
89+ } ) ;
90+
91+ it ( 'should validate password match during registration' , ( ) => {
92+ const username = generateUsername ( ) ;
93+
94+ cy . visit ( '/signup' ) ;
95+
96+ // Fill out form with mismatched passwords
97+ cy . get ( 'input[name="username"]' ) . type ( username ) ;
98+ cy . get ( 'input[name="password"]' ) . type ( 'password123' ) ;
99+ cy . get ( 'input[name="retypedPassword"]' ) . type ( 'differentPassword' ) ;
100+ cy . contains ( 'button' , 'Create Account' ) . click ( ) ;
101+
102+ // Should show error message
103+ cy . contains ( 'Passwords do not match' ) . should ( 'be.visible' ) ;
104+
105+ // Should still be on registration page
106+ cy . url ( ) . should ( 'include' , '/signup' ) ;
107+ } ) ;
108+
109+ it ( 'should prevent registration with existing username' , ( ) => {
110+ // First create a user
111+ cy . registerUser ( ) . then ( ( existingUsername ) => {
112+ // Log out
113+ cy . contains ( 'Log out' ) . click ( ) ;
114+
115+ // Try to register with the same username
116+ cy . visit ( '/signup' ) ;
117+ cy . get ( 'input[name="username"]' ) . type ( existingUsername ) ;
118+ cy . get ( 'input[name="password"]' ) . type ( 'password123' ) ;
119+ cy . get ( 'input[name="retypedPassword"]' ) . type ( 'password123' ) ;
120+ cy . contains ( 'button' , 'Create Account' ) . click ( ) ;
121+
122+ // Should show error message
123+ cy . contains ( `The name ${ existingUsername } is taken!` ) . should ( 'be.visible' ) ;
124+ } ) ;
125+ } ) ;
126+ } ) ;
127+
128+ describe ( 'Logout' , ( ) => {
129+ it ( 'should successfully logout' , ( ) => {
130+ // First login
131+ cy . registerUser ( ) . then ( ( ) => {
132+ // Perform logout
133+ cy . contains ( 'Log out' ) . click ( ) ;
134+
135+ // Verify logout was successful
136+ cy . url ( ) . should ( 'include' , '/login' ) ;
137+
138+ // Verify login form is visible again
139+ cy . get ( 'input[name="username"]' ) . should ( 'be.visible' ) ;
140+ cy . get ( 'input[name="password"]' ) . should ( 'be.visible' ) ;
141+ } ) ;
142+ } ) ;
143+
144+ it ( 'should clear user session after logout' , ( ) => {
145+ cy . registerUser ( ) . then ( ( ) => {
146+ // Logout first
147+ cy . contains ( 'Log out' ) . click ( ) ;
148+
149+ // Try to access protected route
150+ cy . visit ( '/study' ) ;
151+
152+ // Should be redirected to login page
153+ cy . url ( ) . should ( 'include' , '/login' ) ;
154+ } ) ;
155+ } ) ;
156+ } ) ;
157+
158+ describe ( 'Authentication Protection' , ( ) => {
159+ it ( 'should redirect unauthenticated users to login page' , ( ) => {
160+ // Visit protected routes without authentication
161+ cy . visit ( '/study' ) ;
162+ cy . url ( ) . should ( 'include' , '/login' ) ;
163+
164+ cy . visit ( '/progress' ) ;
165+ cy . url ( ) . should ( 'include' , '/login' ) ;
166+ } ) ;
167+
168+ it ( 'should not show login/signup forms when logged in' , ( ) => {
169+ cy . registerUser ( ) . then ( ( ) => {
170+ // Visit login page while logged in
171+ cy . visit ( '/login' ) ;
172+
173+ // Should not see login form
174+ cy . get ( 'input[name="username"]' ) . should ( 'not.exist' ) ;
175+ cy . contains ( 'Already logged in' ) . should ( 'be.visible' ) ;
176+
177+ // Visit signup page while logged in
178+ cy . visit ( '/signup' ) ;
179+
180+ // Should not see signup form
181+ cy . get ( 'input[name="retypedPassword"]' ) . should ( 'not.exist' ) ;
182+ cy . contains ( 'Already logged in' ) . should ( 'be.visible' ) ;
183+ } ) ;
184+ } ) ;
185+ } ) ;
186+ } ) ;
0 commit comments