Skip to content

Commit

Permalink
test(e2e): add SPA tests for login and refactor tests to typescript
Browse files Browse the repository at this point in the history
  • Loading branch information
aeneasr committed Oct 19, 2021
1 parent 30423c9 commit d9a25df
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 93 deletions.
44 changes: 35 additions & 9 deletions test/e2e/cypress/integration/profiles/email/login/error.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,28 @@ import {routes as express} from "../../../../helpers/express";
import {routes as react} from "../../../../helpers/react";

describe('Basic email profile with failing login flows', () => {
[{
route: express.login,
app: 'express', profile: 'email'
}, {
route: react.login,
app: 'react', profile: 'spa'
}].forEach(({route, profile, app}) => {
[
{
route: express.login,
app: 'express', profile: 'email'
},
{
route: react.login,
app: 'react', profile: 'spa'
}
].forEach(({route, profile, app}) => {
describe(`for app ${app}`, () => {
before(() => {
cy.useConfigProfile(profile)
});

beforeEach(() => {
cy.clearCookies()
cy.visit(route)
})

it('fails when CSRF cookies are missing', () => {
cy.clearCookies()

cy.get('input[name="password_identifier"]').type('i-do-not-exist')
cy.get('input[name="password"]').type('invalid-password')

Expand All @@ -33,9 +36,32 @@ describe('Basic email profile with failing login flows', () => {

// We end up at a new flow
cy.location('search').should('not.eq', initial)
if (app === 'express') {
cy.location('pathname').should('include', '/error')
cy.get('code').should('contain.text', 'csrf_token')
} else {
cy.location('pathname').should('include', '/login')
cy.get('.Toastify').should('contain.text', 'A security violation was detected, please fill out the form again.')
}
})

it('fails when a disallowed return_to url is requested', () => {
cy.visit(route + '?return_to=https://not-allowed', {failOnStatusCode: false})
if (app === 'react') {
cy.location('pathname').should('include', '/login')
cy.get('.Toastify').should('contain.text', 'The return_to address is not allowed.')
} else {
cy.location('pathname').should('contain', 'error')
cy.get('code').should('contain.text', 'Requested return_to URL \\"https://not-allowed\\" is not whitelisted.')
}
})

describe('shows validation errors when invalid signup data is used', () => {
beforeEach(() => {
cy.clearCookies()
cy.visit(route)
})

it('should show an error when the identifier is missing', () => {
cy.get('button[type="submit"]').click()
cy.get('*[data-testid="ui.node.message.4000001"]').should(
Expand All @@ -52,7 +78,7 @@ describe('Basic email profile with failing login flows', () => {

cy.get('button[type="submit"]').click()

cy.get('*[data-testid^="ui.node.message."]').invoke('text').then((text)=> {
cy.get('*[data-testid^="ui.node.message."]').invoke('text').then((text) => {
expect(text).to.be.oneOf(['length must be >= 1, but got 0', 'Property password is missing.'])
})
})
Expand Down
115 changes: 62 additions & 53 deletions test/e2e/cypress/integration/profiles/email/login/success.spec.ts
Original file line number Diff line number Diff line change
@@ -1,77 +1,86 @@
import { APP_URL, gen, website } from '../../../../helpers'
import {routes} from "../../../../helpers/express";
import {APP_URL, gen, website} from '../../../../helpers'
import {routes as express, routes} from "../../../../helpers/express";
import {routes as react} from "../../../../helpers/react";

describe('Email Profile', () => {
describe('Login Flow Success', () => {
before(() => {
cy.useConfigProfile('email')
})
describe('Basic email profile with succeeding login flows', () => {
const email = gen.email()
const password = gen.password()

const email = gen.email()
const password = gen.password()
before(() => {
cy.registerApi({email, password, fields: {'traits.website': website}})
});

before(() => {
cy.registerApi({ email, password, fields: { 'traits.website': website } })
})
[{
route: express.login,
app: 'express', profile: 'email'
}, {
route: react.login,
app: 'react', profile: 'spa'
}].forEach(({route, profile, app}) => {
describe(`for app ${app}`, () => {
beforeEach(() => {
cy.useConfigProfile(profile)
cy.clearCookies()
cy.visit(route)
})

beforeEach(() => {
cy.clearCookies()
cy.visit(routes.login)
})
it('should sign in and be logged in', () => {
cy.get('input[name="password_identifier"]').type(email)
cy.get('input[name="password"]').type(password)
cy.get('button[type="submit"]').click()

it('should sign up and be logged in', () => {
cy.get('input[name="password_identifier"]').type(email)
cy.get('input[name="password"]').type(password)
cy.get('button[type="submit"]').click()
cy.getSession().should((session) => {
const {identity} = session
expect(identity.id).to.not.be.empty
expect(identity.schema_id).to.equal('default')
expect(identity.schema_url).to.equal(`${APP_URL}/schemas/default`)
expect(identity.traits.website).to.equal(website)
expect(identity.traits.email).to.equal(email)
})
})

it('should sign in with case insensitive identifier', () => {
cy.get('input[name="password_identifier"]').type(email.toUpperCase())
cy.get('input[name="password"]').type(password)
cy.get('button[type="submit"]').click()

cy.getSession().should((session) => {
const { identity } = session
expect(identity.id).to.not.be.empty
expect(identity.schema_id).to.equal('default')
expect(identity.schema_url).to.equal(`${APP_URL}/schemas/default`)
expect(identity.traits.website).to.equal(website)
expect(identity.traits.email).to.equal(email)
cy.getSession().should((session) => {
const {identity} = session
expect(identity.id).to.not.be.empty
expect(identity.schema_id).to.equal('default')
expect(identity.schema_url).to.equal(`${APP_URL}/schemas/default`)
expect(identity.traits.website).to.equal(website)
expect(identity.traits.email).to.equal(email)
})
})
})

it('should sign in with case insensitive identifier', () => {
cy.get('input[name="password_identifier"]').type(email.toUpperCase())
cy.get('input[name="password"]').type(password)
cy.get('button[type="submit"]').click()
it('should sign in and be redirected', () => {
cy.browserReturnUrlOry()
cy.visit(
route + '?return_to=https://www.ory.sh/'
)

cy.get('input[name="password_identifier"]').type(email.toUpperCase())
cy.get('input[name="password"]').type(password)
cy.get('button[type="submit"]').click()

cy.getSession().should((session) => {
const { identity } = session
expect(identity.id).to.not.be.empty
expect(identity.schema_id).to.equal('default')
expect(identity.schema_url).to.equal(`${APP_URL}/schemas/default`)
expect(identity.traits.website).to.equal(website)
expect(identity.traits.email).to.equal(email)
cy.url().should('eq', 'https://www.ory.sh/')
})
})
})
describe('Login Flow Success with return_to url after flow expires', () => {
before(() => {
cy.useConfigProfile('email')
})

const email = gen.email()
const password = gen.password()

describe('for ap express handle return_to correctly for expired flows', () => {
before(() => {
cy.registerApi({ email, password, fields: { 'traits.website': website } })
})

beforeEach(() => {
cy.shortLoginLifespan()
cy.browserReturnUrlOry()
cy.clearCookies()

cy.visit(
APP_URL + '/self-service/login/browser?return_to=https://www.ory.sh/'
express.login + "?return_to=https://www.ory.sh/"
)
})

it('should redirect to return_to after flow expires', () => {
cy.wait(105)
it('should redirect to return_to when retrying expired flow', () => {
cy.get('input[name="password_identifier"]').type(email.toUpperCase())
cy.get('input[name="password"]').type(password)

Expand Down
31 changes: 0 additions & 31 deletions test/e2e/cypress/integration/profiles/email/login/ui.spec.js

This file was deleted.

41 changes: 41 additions & 0 deletions test/e2e/cypress/integration/profiles/email/login/ui.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {routes as express} from "../../../../helpers/express";
import {routes as react} from "../../../../helpers/react";

context('UI tests using the email profile', () => {
[{
route: express.login,
app: 'express', profile: 'email'
}, {
route: react.login,
app: 'react', profile: 'spa'
}].forEach(({route, profile, app}) => {
describe(`for app ${app}`, () => {
before(() => {
cy.useConfigProfile(profile)
})

beforeEach(() => {
cy.visit(route)
})

it('should use the json schema titles', () => {
cy.get('input[name="password_identifier"]')
.parent()
.should('contain.text', 'ID')
cy.get('input[name="password"]')
.parent()
.should('contain.text', 'Password')
cy.get('button[value="password"]').should('contain.text', 'Sign in')
})

it('clicks the log in link', () => {
cy.get('a[href*="registration"]').click()
cy.location('pathname').should('include', 'registration')

if (app === 'express') {
cy.location('search').should('not.be.empty')
}
})
})
})
})

0 comments on commit d9a25df

Please sign in to comment.