test frontend signup flow

This commit is contained in:
Yisroel Baum 2026-08-03 20:30:55 +03:00
parent 3dc9204979
commit e47535f91c
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
3 changed files with 145 additions and 15 deletions

View file

@ -0,0 +1,77 @@
const authenticatedUser = {
id: 7,
email: 'user@example.com',
}
describe('email confirmation', () => {
beforeEach(() => {
cy.intercept('GET', '**/api/me', {
statusCode: 401,
body: { error: 'unauthenticated' },
}).as('me')
})
it('chooses a password, confirms the account, and opens the dashboard', () => {
cy.intercept('POST', '**/api/confirm-email', (request) => {
expect(request.headers.accept).to.equal('application/json')
expect(request.body).to.deep.equal({
token: 'confirmation-token',
password: 'password123',
})
request.reply({
statusCode: 200,
body: { user: authenticatedUser },
})
}).as('confirmEmail')
cy.visit('/confirm-email?token=confirmation-token')
cy.get('#confirm-email-password').type('password123')
cy.get('#confirm-email-password-confirmation').type('password123')
cy.get('form').submit()
cy.wait('@confirmEmail')
cy.location('pathname').should('equal', '/dashboard')
cy.get('h1').should('have.text', 'Your next step starts here.')
})
it('validates password length and confirmation before submitting', () => {
cy.intercept('POST', '**/api/confirm-email').as('confirmEmail')
cy.visit('/confirm-email?token=confirmation-token')
cy.get('#confirm-email-password').type('short')
cy.get('#confirm-email-password-confirmation').type('different')
cy.get('form').submit()
cy.get('#confirm-email-password-error')
.should('have.text', 'Password must be at least 8 characters.')
.and('be.visible')
cy.get('#confirm-email-password-confirmation-error')
.should('have.text', 'Passwords do not match.')
.and('be.visible')
cy.get('@confirmEmail.all').should('have.length', 0)
})
it('shows confirmation errors from the backend', () => {
cy.intercept('POST', '**/api/confirm-email', {
statusCode: 409,
body: { error: 'token expired' },
}).as('confirmEmail')
cy.visit('/confirm-email?token=expired-token')
cy.get('#confirm-email-password').type('password123')
cy.get('#confirm-email-password-confirmation').type('password123')
cy.get('form').submit()
cy.wait('@confirmEmail')
cy.get('[role="alert"]')
.should('have.text', 'token expired')
.and('be.visible')
cy.location('pathname').should('equal', '/confirm-email')
})
it('redirects a confirmation route without a token to signup', () => {
cy.visit('/confirm-email')
cy.location('pathname').should('equal', '/signup')
})
})

View file

@ -42,28 +42,18 @@ describe('guest authentication pages', () => {
cy.visit('/signup') cy.visit('/signup')
cy.get('h1').should('have.text', 'Start your journey') cy.get('h1').should('have.text', 'Start your journey')
cy.get('label[for="signup-name"]').should('have.text', 'Full name')
cy.get('#signup-name').should('have.attr', 'autocomplete', 'name')
cy.get('label[for="signup-email"]').should('have.text', 'Email address') cy.get('label[for="signup-email"]').should('have.text', 'Email address')
cy.get('#signup-email').should('have.attr', 'autocomplete', 'email') cy.get('#signup-email').should('have.attr', 'autocomplete', 'email')
cy.get('label[for="signup-password"]').should('have.text', 'Password') cy.get('#signup-name').should('not.exist')
cy.get('#signup-password').should('have.attr', 'autocomplete', 'new-password') cy.get('#signup-password').should('not.exist')
cy.get('label[for="signup-password-confirmation"]').should( cy.get('#signup-password-confirmation').should('not.exist')
'have.text', cy.get('button[type="submit"]').should('have.text', 'Continue with email')
'Confirm password',
)
cy.get('#signup-password-confirmation').should(
'have.attr',
'autocomplete',
'new-password',
)
cy.get('button[type="submit"]').should('have.text', 'Create account')
cy.contains('a', 'Log in').click() cy.contains('a', 'Log in').click()
cy.location('pathname').should('equal', '/login') cy.location('pathname').should('equal', '/login')
}) })
it('keeps UI-only form submissions on their current route', () => { it('keeps invalid form submissions on their current route', () => {
cy.visit('/login') cy.visit('/login')
cy.get('form').submit() cy.get('form').submit()
cy.location('pathname').should('equal', '/login') cy.location('pathname').should('equal', '/login')

View file

@ -0,0 +1,63 @@
describe('email signup', () => {
beforeEach(() => {
cy.intercept('GET', '**/api/me', {
statusCode: 401,
body: { error: 'unauthenticated' },
}).as('me')
})
it('requests a confirmation email and shows the check-email page', () => {
cy.intercept('POST', '**/api/signup', (request) => {
expect(request.headers.accept).to.equal('application/json')
expect(request.body).to.deep.equal({ email: 'user@example.com' })
request.reply({ statusCode: 201 })
}).as('signup')
cy.visit('/signup')
cy.get('#signup-email').type(' user@example.com ')
cy.get('form').submit()
cy.wait('@signup')
cy.location('pathname').should('equal', '/check-email')
cy.get('h1').should('have.text', 'Check your email')
cy.contains('We sent you a link to confirm your signup.').should('be.visible')
})
it('validates the email before submitting', () => {
cy.intercept('POST', '**/api/signup').as('signup')
cy.visit('/signup')
cy.get('#signup-email').type('not-an-email')
cy.get('form').submit()
cy.get('#signup-email-error')
.should('have.text', 'Enter a valid email address.')
.and('be.visible')
cy.get('#signup-email').should('have.attr', 'aria-invalid', 'true')
cy.get('@signup.all').should('have.length', 0)
cy.location('pathname').should('equal', '/signup')
})
it('shows backend signup errors', () => {
cy.intercept('POST', '**/api/signup', {
statusCode: 409,
body: { error: 'user@example.com already has an account' },
}).as('signup')
cy.visit('/signup')
cy.get('#signup-email').type('user@example.com')
cy.get('form').submit()
cy.wait('@signup')
cy.get('[role="alert"]')
.should('have.text', 'user@example.com already has an account')
.and('be.visible')
cy.location('pathname').should('equal', '/signup')
})
it('redirects direct check-email visits back to signup', () => {
cy.visit('/check-email')
cy.location('pathname').should('equal', '/signup')
})
})