* Initial plan * feat: add Cypress E2E testing for auth flows Agent-Logs-Url: https://github.com/RMCampos/tasknote/sessions/f3b4e747-3e09-4b6c-8b4c-336cf45b59c4 Co-authored-by: RMCampos <2219519+RMCampos@users.noreply.github.com> * fix: use regex intercepts and unique emails in Cypress auth tests Agent-Logs-Url: https://github.com/RMCampos/tasknote/sessions/2a1225d9-9412-459e-bc97-93303454a461 Co-authored-by: RMCampos <2219519+RMCampos@users.noreply.github.com> * fix: use PUT method for sign-up intercepts in Cypress auth tests Agent-Logs-Url: https://github.com/RMCampos/tasknote/sessions/bda14dfc-a30d-4c01-aa74-e8c2690072e3 Co-authored-by: RMCampos <2219519+RMCampos@users.noreply.github.com> * chore: update tools.md file to include sql command --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: RMCampos <2219519+RMCampos@users.noreply.github.com> Co-authored-by: Ricardo Campos <ricardompcampos@gmail.com>
142 lines
4.9 KiB
TypeScript
142 lines
4.9 KiB
TypeScript
/**
|
|
* E2E tests for authentication flows: User Signup and Login.
|
|
*
|
|
* These tests cover the primary user journeys for account creation
|
|
* and logging in to the TaskNote application.
|
|
*/
|
|
describe('Authentication', () => {
|
|
/**
|
|
* User Signup (Registration) flow
|
|
*/
|
|
describe('Signup', () => {
|
|
beforeEach(() => {
|
|
cy.visit('/register');
|
|
});
|
|
|
|
it('displays the registration form', () => {
|
|
cy.contains('h2', 'Create account').should('be.visible');
|
|
cy.get('input[name="email"]').should('be.visible');
|
|
cy.get('input[name="password"]').should('be.visible');
|
|
cy.get('input[name="passwordAgain"]').should('be.visible');
|
|
cy.get('button[type="submit"]').should('be.visible').and('contain', 'Create account');
|
|
});
|
|
|
|
it('shows a validation error when the form is submitted empty', () => {
|
|
cy.get('button[type="submit"]').click();
|
|
cy.get('.alert-danger').should('be.visible');
|
|
});
|
|
|
|
it('shows a validation error when passwords do not match', () => {
|
|
cy.get('input[name="email"]').type('testuser@example.com');
|
|
cy.get('input[name="password"]').type('Password1!');
|
|
cy.get('input[name="passwordAgain"]').type('DifferentPass1!');
|
|
cy.get('button[type="submit"]').click();
|
|
cy.get('.alert-danger').should('be.visible');
|
|
});
|
|
|
|
it('navigates to the login page via the login link', () => {
|
|
cy.contains('a', 'Login').first().click();
|
|
cy.url().should('include', '/login');
|
|
});
|
|
|
|
it('navigates back to the landing page via the back-to-home link', () => {
|
|
cy.contains('a', 'Back to home').click();
|
|
cy.url().should('eq', `${Cypress.config('baseUrl')}/`);
|
|
});
|
|
|
|
it('submits the signup form and shows a confirmation message on success', () => {
|
|
cy.intercept({ method: 'PUT', url: /\/auth\/sign-up/ }, {
|
|
statusCode: 201,
|
|
body: { message: 'User created' }
|
|
}).as('signUp');
|
|
|
|
cy.get('input[name="email"]').type(`newuser${Date.now()}@example.com`);
|
|
cy.get('input[name="password"]').type('Password1!');
|
|
cy.get('input[name="passwordAgain"]').type('Password1!');
|
|
cy.get('button[type="submit"]').click();
|
|
|
|
cy.wait('@signUp');
|
|
cy.get('.alert-success').should('be.visible');
|
|
});
|
|
|
|
it('displays an error alert when the API returns an error on signup', () => {
|
|
cy.intercept({ method: 'PUT', url: /\/auth\/sign-up/ }, {
|
|
statusCode: 409,
|
|
body: { message: 'Email already in use' }
|
|
}).as('signUpFail');
|
|
|
|
cy.get('input[name="email"]').type(`existing${Date.now()}@example.com`);
|
|
cy.get('input[name="password"]').type('Password1!');
|
|
cy.get('input[name="passwordAgain"]').type('Password1!');
|
|
cy.get('button[type="submit"]').click();
|
|
|
|
cy.wait('@signUpFail');
|
|
cy.get('.alert-danger').should('be.visible');
|
|
});
|
|
});
|
|
|
|
/**
|
|
* User Login flow
|
|
*/
|
|
describe('Login', () => {
|
|
beforeEach(() => {
|
|
cy.visit('/login');
|
|
});
|
|
|
|
it('displays the login form', () => {
|
|
cy.contains('h2', 'Login').should('be.visible');
|
|
cy.get('input[name="email"]').should('be.visible');
|
|
cy.get('input[name="password"]').should('be.visible');
|
|
cy.get('button[type="submit"]').should('be.visible').and('contain', 'Login');
|
|
});
|
|
|
|
it('shows a validation error when the form is submitted empty', () => {
|
|
cy.get('button[type="submit"]').click();
|
|
cy.get('.alert-danger').should('be.visible');
|
|
});
|
|
|
|
it('navigates to the register page via the create account link', () => {
|
|
cy.contains('a', 'Create account').click();
|
|
cy.url().should('include', '/register');
|
|
});
|
|
|
|
it('navigates back to the landing page via the back-to-home link', () => {
|
|
cy.contains('a', 'Back to home').click();
|
|
cy.url().should('eq', `${Cypress.config('baseUrl')}/`);
|
|
});
|
|
|
|
it('navigates to the reset password page via the forgot password link', () => {
|
|
cy.contains('a', 'Forgot your password?').click();
|
|
cy.url().should('include', '/reset-password');
|
|
});
|
|
|
|
it('redirects to home after a successful login', () => {
|
|
cy.intercept({ method: 'POST', url: /\/auth\/sign-in/ }, {
|
|
statusCode: 200,
|
|
body: { token: 'fake-jwt-token', email: 'user@example.com' }
|
|
}).as('signIn');
|
|
|
|
cy.get('input[name="email"]').type('user@example.com');
|
|
cy.get('input[name="password"]').type('Password1!');
|
|
cy.get('button[type="submit"]').click();
|
|
|
|
cy.wait('@signIn');
|
|
cy.url().should('include', '/home');
|
|
});
|
|
|
|
it('displays an error alert when the API returns an error on login', () => {
|
|
cy.intercept({ method: 'POST', url: /\/auth\/sign-in/ }, {
|
|
statusCode: 401,
|
|
body: { message: 'Invalid credentials' }
|
|
}).as('signInFail');
|
|
|
|
cy.get('input[name="email"]').type('user@example.com');
|
|
cy.get('input[name="password"]').type('wrongpassword');
|
|
cy.get('button[type="submit"]').click();
|
|
|
|
cy.wait('@signInFail');
|
|
cy.get('.alert-danger').should('be.visible');
|
|
});
|
|
});
|
|
});
|