Skip to content

Commit 21c8cf0

Browse files
NiloCKclaude
andcommitted
Add authentication tests for standalone-ui
- Create comprehensive auth.cy.js test suite with: - Login tests (form display, validation, success/failure cases) - Registration tests (new user creation, validation) - Logout functionality tests - Authentication protection tests for routes - Update commands.js with reusable authentication commands: - login: Handles user login flow - registerUser: Creates new test users These tests mirror the authentication testing approach from platform-ui while targeting the standalone-ui implementation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 7c33fcc commit 21c8cf0

File tree

2 files changed

+220
-5
lines changed

2 files changed

+220
-5
lines changed
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
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+
});
Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,36 @@
11
// standalone-ui/cypress/support/commands.js
2-
// Basic commands file - will be expanded with specific commands as needed
2+
// Custom commands for Cypress tests
33

4-
// Example of a custom command format:
5-
// Cypress.Commands.add('commandName', (param1, param2) => {
6-
// // Command implementation
7-
// });
4+
// Command for logging in a user
5+
Cypress.Commands.add('login', (username, password) => {
6+
cy.visit('/login');
7+
cy.get('input[name="username"]').type(username);
8+
cy.get('input[name="password"]').type(password);
9+
cy.contains('button', 'Log in').click();
10+
11+
// Optional: Wait for login to complete and redirect
12+
cy.url().should('not.include', '/login');
13+
});
14+
15+
// Command for registering a new user
16+
Cypress.Commands.add('registerUser', (username = null, password = 'securePassword123') => {
17+
// Generate a unique username if none provided
18+
const finalUsername = username || `testuser${Date.now()}`;
19+
20+
// Visit the signup page
21+
cy.visit('/signup');
22+
23+
// Fill out the registration form
24+
cy.get('input[name="username"]').type(finalUsername);
25+
cy.get('input[name="password"]').type(password);
26+
cy.get('input[name="retypedPassword"]').type(password);
27+
28+
// Submit the form
29+
cy.contains('button', 'Create Account').click();
30+
31+
// Wait for registration to complete
32+
cy.url().should('include', `/u/${finalUsername}/new`);
33+
34+
// Return the created username so it can be used in tests
35+
return cy.wrap(finalUsername);
36+
});

0 commit comments

Comments
 (0)