diff --git a/.gitignore b/.gitignore index d1502b0..b6c2c24 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ vendor/ +node_modules/ +cypress/screenshots +cypress/videos composer.lock +package-lock.json diff --git a/cypress.json b/cypress.json new file mode 100644 index 0000000..ba00f88 --- /dev/null +++ b/cypress.json @@ -0,0 +1,3 @@ +{ + "baseUrl": "http://localhost:3300" +} diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json new file mode 100644 index 0000000..da18d93 --- /dev/null +++ b/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} \ No newline at end of file diff --git a/cypress/integration/home_page_spec.js b/cypress/integration/home_page_spec.js new file mode 100644 index 0000000..c9fada9 --- /dev/null +++ b/cypress/integration/home_page_spec.js @@ -0,0 +1,5 @@ +describe('The Home Page', () => { + it('successfully loads', () => { + cy.visit('/') + }) +}) diff --git a/cypress/integration/login_spec.js b/cypress/integration/login_spec.js new file mode 100644 index 0000000..aa2f37d --- /dev/null +++ b/cypress/integration/login_spec.js @@ -0,0 +1,113 @@ +describe('user login', () => { + context('using login url', () => { + beforeEach(() => { + cy.visit('/login.php'); + }); + + it('says Burning Flipside Profile Login', () => { + cy.get('body').contains('Burning Flipside Profile Login'); + }); + + it('when submitting empty form', () => { + cy.get('#login_main_form').children('button[type=submit]').click(); + // there is no visible feedback that an error has occurred + }); + }); + + context('using login modal', () => { + let base = new URL(Cypress.config().baseUrl).pathname; + + beforeEach(() => { + cy.logout(); + cy.visit('/'); + + cy.server(); + cy.route({method: 'POST', url: base+'/api/v1/login', onAbort: () => {console.log(arguments);}}).as('authenticate'); + }); + + it('says Burning Flipside Profile Login', () => { + cy.get('a').contains('Login').click(); + cy.get('#login-dialog').contains('Login'); + }); + + it('when submitting empty form', () => { + cy.get('a').contains('Login').click(); + cy.get('#login_dialog_form').children('button[type=submit]').click(); + cy.wait('@authenticate').then((xhr) => { + expect(xhr.status).to.eq(403); + cy.location().should((loc) => { + expect(loc.pathname).to.eq(base+'/login.php'); + }); + cy.get('body').contains('Login Failed!'); + }); + }); + + it('form can be submitted by pressing the enter key', () => { + cy.get('a').contains('Login').click(); + cy.get('#login_dialog_form').children('input[name=username]').type('me@example.com{enter}'); + cy.wait('@authenticate').then((xhr) => { + expect(xhr.status).to.eq(403); + // I expect there should be visible feedback that an error has occurred + // there is none + }); + }); + + it('when submitting incomplete credentials', () => { + cy.get('a').contains('Login').click(); + cy.get('#login_dialog_form').children('input[name=username]').type('gooduser'); + cy.get('#login_dialog_form').children('button[type=submit]').click(); + cy.wait('@authenticate').then((xhr) => { + expect(xhr.status).to.eq(403); + // I expect there should be visible feedback that an error has occurred + // there is none + }); + }); + + it('when submitting invalid credentials', () => { + cy.get('a').contains('Login').click(); + cy.wait(200); //give the dialog time to render, otherwise this sometimes types in the wrong fields + cy.get('#login_dialog_form').children('input[name=username]').type('gooduser'); + cy.get('#login_dialog_form').children('input[name=password]').type('badpass'); + cy.get('#login_dialog_form').children('button[type=submit]').click(); + cy.wait('@authenticate').then((xhr) => { + expect(xhr.status).to.eq(403); + // I expect there should be visible feedback that an error has occurred + // there is none + }); + }); + + it('allows login using username', () => { + cy.get('a').contains('Login').click(); + cy.wait(200); //give the dialog time to render, otherwise this sometimes types in the wrong fields + cy.get('#login_dialog_form').children('input[name=username]').type('gooduser'); + cy.get('#login_dialog_form').children('input[name=password]').type('goodpass'); + cy.get('#login_dialog_form').children('button[type=submit]').click(); + cy.wait('@authenticate').then((xhr) => { + expect(xhr.status).to.eq(200); + + cy.location().should((location) => { + expect(location.pathname).to.eq(base+'/'); + }); + + cy.get('body').contains('Logout'); + }); + }); + + it('allows login using email sddress', () => { + cy.get('a').contains('Login').click(); + cy.wait(200); //give the dialog time to render, otherwise this sometimes types in the wrong fields + cy.get('#login_dialog_form').children('input[name=username]').type('good@example.org'); + cy.get('#login_dialog_form').children('input[name=password]').type('goodpass'); + cy.get('#login_dialog_form').children('button[type=submit]').click(); + cy.wait('@authenticate').then((xhr) => { + expect(xhr.status).to.eq(200); + + cy.location().should((location) => { + expect(location.pathname).to.eq(base+'/'); + }); + + cy.get('body').contains('Logout'); + }); + }); + }); +}); diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js new file mode 100644 index 0000000..aa9918d --- /dev/null +++ b/cypress/plugins/index.js @@ -0,0 +1,21 @@ +/// +// *********************************************************** +// This example plugins/index.js can be used to load plugins +// +// You can change the location of this file or turn off loading +// the plugins file with the 'pluginsFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/plugins-guide +// *********************************************************** + +// This function is called when a project is opened or re-opened (e.g. due to +// the project's config changing) + +/** + * @type {Cypress.PluginConfig} + */ +module.exports = (on, config) => { + // `on` is used to hook into various events Cypress emits + // `config` is the resolved Cypress config +} diff --git a/cypress/support/commands.js b/cypress/support/commands.js new file mode 100644 index 0000000..6b39638 --- /dev/null +++ b/cypress/support/commands.js @@ -0,0 +1,33 @@ +// *********************************************** +// This example commands.js shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add("login", (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) +Cypress.Commands.add('logout', () => { + cy.request({ + method: 'POST', + url: `/api/v1/logout`, + body: { + }, + }); +}); diff --git a/cypress/support/index.js b/cypress/support/index.js new file mode 100644 index 0000000..d68db96 --- /dev/null +++ b/cypress/support/index.js @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands')