From a1bfaa01f3d7e8d511d4c3b84bd35eb2d2b67a25 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Fri, 8 Dec 2017 00:15:54 -0500 Subject: [PATCH 01/10] add simple e2e tests using Cypress --- cypress.json | 3 ++ cypress/fixtures/example.json | 5 +++ cypress/integration/simple_spec.js | 67 ++++++++++++++++++++++++++++++ cypress/plugins/index.js | 17 ++++++++ cypress/support/commands.js | 25 +++++++++++ cypress/support/index.js | 55 ++++++++++++++++++++++++ package.json | 1 + 7 files changed, 173 insertions(+) create mode 100644 cypress.json create mode 100644 cypress/fixtures/example.json create mode 100644 cypress/integration/simple_spec.js create mode 100644 cypress/plugins/index.js create mode 100644 cypress/support/commands.js create mode 100644 cypress/support/index.js diff --git a/cypress.json b/cypress.json new file mode 100644 index 000000000..05d095b8b --- /dev/null +++ b/cypress.json @@ -0,0 +1,3 @@ +{ + "baseUrl": "http://localhost:4600" +} diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json new file mode 100644 index 000000000..da18d9352 --- /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/simple_spec.js b/cypress/integration/simple_spec.js new file mode 100644 index 000000000..c323c2cdd --- /dev/null +++ b/cypress/integration/simple_spec.js @@ -0,0 +1,67 @@ +import { Arrows, slide, checkActiveSlide, activeSlide } from '../support' + +describe('simple example', () => { + beforeEach(() => { + cy.visit('/examples/simple') + cy.get('#fullpage').should('be.visible') + }) + + it('loads', () => { + cy.contains('fullPage.js') + }) + + it('hides second page', () => { + cy.contains('Only text').should('not.be', 'visible') + }) + + it('goes down to second slide', () => { + cy.document().its('body').trigger('keydown', { which: Arrows.down }) + cy.contains('.section', 'Only text').should('have.class', 'active') + }) + + it('goes down to 4th slide', () => { + slide.down() + slide.down() + slide.down() + slide.down() + checkActiveSlide('Just the simplest demo ever') + }) + + it('does not have left or right arrows on the first slide', () => { + activeSlide().find('.fp-prev').should('not.exist') + activeSlide().find('.fp-next').should('not.exist') + }) + + it('shows left and right arrows', () => { + slide.down() + checkActiveSlide('Only text') + activeSlide().find('.fp-prev').should('be.visible') + activeSlide().find('.fp-next').should('be.visible') + }) + + it('goes horizontally', () => { + slide.down() + checkActiveSlide('Only text') + slide.right() + checkActiveSlide('And text') + slide.right() + checkActiveSlide('And more text') + slide.left() + checkActiveSlide('And text') + slide.down() + checkActiveSlide('No wraps, no extra markup') + }) + + it('loops horizontally', () => { + slide.down() + checkActiveSlide('Only text') + slide.right() + checkActiveSlide('And text') + slide.right() + checkActiveSlide('And more text') + slide.right() + checkActiveSlide('Simple Demo') + slide.right() + checkActiveSlide('Only text') + }) +}) diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js new file mode 100644 index 000000000..fd170fba6 --- /dev/null +++ b/cypress/plugins/index.js @@ -0,0 +1,17 @@ +// *********************************************************** +// 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) + +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 000000000..c1f5a772e --- /dev/null +++ b/cypress/support/commands.js @@ -0,0 +1,25 @@ +// *********************************************** +// 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 is will overwrite an existing command -- +// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/cypress/support/index.js b/cypress/support/index.js new file mode 100644 index 000000000..49b000b54 --- /dev/null +++ b/cypress/support/index.js @@ -0,0 +1,55 @@ +// *********************************************************** +// 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') + +export const Arrows = { + up: 38, + down: 40, + left: 37, + right: 39 +} + +function triggerArrow (which) { + cy.document().its('body').trigger('keydown', { which }).wait(1000) +} + +export const slide = { + down () { + triggerArrow(Arrows.down) + }, + + up () { + triggerArrow(Arrows.up) + }, + + left () { + triggerArrow(Arrows.left) + }, + + right () { + triggerArrow(Arrows.right) + } +} + +export function checkActiveSlide (text) { + cy.contains('.section', text).should('have.class', 'active') +} + +export const activeSlide = () => cy.get('.section.active') diff --git a/package.json b/package.json index a5af685c0..e37eba996 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "homepage": "https://github.com/alvarotrigo/fullPage.js", "namespace": "$.fn.fullpage", "devDependencies": { + "cypress": "^1.1.4", "gulp": "^3.9.0", "gulp-clean-css": "^2.0.8", "gulp-rename": "^1.2.2", From df1c5cc992b190ebd371a9fc92281e7f8b71ddc6 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Fri, 8 Dec 2017 12:14:36 -0500 Subject: [PATCH 02/10] ignore recorded videos folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c6d3a6717..bd1efedd1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .idea bower_components/ /node_modules +cypress/videos From 923fb7ed9d58ee1b083c5a818a01c96f4cc61027 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Sat, 9 Dec 2017 11:24:55 -0500 Subject: [PATCH 03/10] add npm test and npm run test:ci commands --- README.md | 18 ++++++++++++++++++ package.json | 10 ++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 98428169d..301e024c0 100644 --- a/README.md +++ b/README.md @@ -877,6 +877,24 @@ To see the list of recent changes, see [Releases section](https://github.com/alv # Build tasks Want to build fullpage.js distribution files? Please see [Build Tasks](https://github.com/alvarotrigo/fullPage.js/wiki/Build-tasks) +# Testing + +To run end to end tests in a real browser (Electron / Chrome) this project uses [Cypress.io](https://github.com/cypress-io/cypress). To run tests on CI simple execute + +```shell +$ npm test +``` + +Which starts static server (using `npm start`), runs E2E tests and then closes the server. + +To see E2E tests live use + +```shell +$ npm run test:gui +``` + +The Cypress runner keeps watching your test files, rerunning the tests as you are editing the spec files. Find the spec files in the [cypress/integration](cypress/integration) folder. + # Resources - [Wordpress theme](http://alvarotrigo.com/fullPage/utils/wordpress.html) - [CSS Easing Animation Tool - Matthew Lein](http://matthewlein.com/ceaser/) (useful to define the `easingcss3` value) diff --git a/package.json b/package.json index e37eba996..a486b7796 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,11 @@ "description": "Create beautiful fullscreen scrolling websites", "main": "dist/jquery.fullpage.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "run-p --race start cy:run", + "test:gui": "run-p --race start cy:open", + "start": "http-server -c-1 -p 4600 --silent", + "cy:open": "cypress open", + "cy:run": "cypress run" }, "repository": { "type": "git", @@ -48,6 +52,8 @@ "gulp-rename": "^1.2.2", "gulp-sass": "^2.0.4", "gulp-sourcemaps": "^1.6.0", - "gulp-uglify": "^2.1.2" + "gulp-uglify": "^2.1.2", + "http-server": "^0.10.0", + "npm-run-all": "^4.1.2" } } From 06584d10718110f4c46fe684f1ac65b1b4cd795b Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Sat, 9 Dec 2017 11:27:05 -0500 Subject: [PATCH 04/10] add Cypress.io tests badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 301e024c0..968e78a82 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ [![License](http://img.shields.io/badge/License-MIT-blue.svg)](http://opensource.org/licenses/MIT) [![PayPal Donate](https://img.shields.io/badge/donate-PayPal.me-ff69b4.svg)](https://www.paypal.me/alvarotrigo/9.95) [![jsDelivr Hits](https://data.jsdelivr.com/v1/package/npm/fullpage.js/badge?style=rounded)](https://www.jsdelivr.com/package/npm/fullpage.js) +[![Cypress.io tests](https://img.shields.io/badge/cypress.io-tests-green.svg?style=flat-square)](https://cypress.io)    **|**   *7Kb gziped*   **|**   *Created by [@imac2](https://twitter.com/imac2)* - [Live demo](http://alvarotrigo.com/fullPage/) From eb02503737242da28e5370b727b94fcaab025a04 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Sat, 9 Dec 2017 11:45:25 -0500 Subject: [PATCH 05/10] add methods page tests --- cypress/integration/methods_spec.js | 81 +++++++++++++++++++++++++++++ cypress/integration/simple_spec.js | 2 + 2 files changed, 83 insertions(+) create mode 100644 cypress/integration/methods_spec.js diff --git a/cypress/integration/methods_spec.js b/cypress/integration/methods_spec.js new file mode 100644 index 000000000..a72682028 --- /dev/null +++ b/cypress/integration/methods_spec.js @@ -0,0 +1,81 @@ +import { checkActiveSlide } from '../support' + +/* eslint-env mocha */ +/* global cy */ +describe('simple example', () => { + beforeEach(() => { + cy.visit('/examples/methods') + cy.get('.fullpage-wrapper').should('be.visible') + }) + + const getMenuButtons = () => cy.get('ul#menu li') + + const getMenuButton = title => getMenuButtons().contains(title) + + it('has slide buttons', () => { + // 4 buttons on the top + getMenuButtons().should('have.length', 4) + getMenuButtons().contains('First slide') + getMenuButton('Second slide') + getMenuButton('Third slide') + getMenuButton('Fourth slide') + }) + + it('is at first slide at first', () => { + checkActiveSlide('Section 1') + }) + + it('goes to second slide by clicking on menu button', () => { + getMenuButton('Second slide').click() + checkActiveSlide('Section 2') + }) + + it('goes to third slide and fourth slide', () => { + getMenuButton('Third slide').click() + checkActiveSlide('Section 3') + + getMenuButton('Fourth slide').click() + checkActiveSlide('Section 4') + }) + + it('does not url hash initially', () => { + cy.hash().should('eq', '') + }) + + it('changes url hash after transition', () => { + getMenuButton('Second slide').click() + checkActiveSlide('Section 2') + cy.hash().should('eq', '#secondPage') + }) + + context('actions', () => { + const getActions = () => cy.get('#actions').should('not.be', 'empty') + + const getAction = title => getActions().contains(title) + + it('has actions', () => { + getActions() + }) + + it('slides down', () => { + getAction('moveSectionDown').click() + checkActiveSlide('Section 2') + }) + + it('moves to slide 2/3', () => { + getAction('moveTo(2,3)').click() + checkActiveSlide('Slide 2.3') + cy.hash().should('eq', '#secondPage/3') + }) + + it('destroys all', () => { + getAction("destroy('all')").click() + cy.get('.fullpage-wrapper').should('have.class', 'fp-destroyed') + }) + + it('undestroys', () => { + getAction('undestroy').click() + cy.get('.fullpage-wrapper').should('not.have.class', 'fp-destroyed') + }) + }) +}) diff --git a/cypress/integration/simple_spec.js b/cypress/integration/simple_spec.js index c323c2cdd..8ea7bed80 100644 --- a/cypress/integration/simple_spec.js +++ b/cypress/integration/simple_spec.js @@ -1,5 +1,7 @@ import { Arrows, slide, checkActiveSlide, activeSlide } from '../support' +/* eslint-env mocha */ +/* global cy */ describe('simple example', () => { beforeEach(() => { cy.visit('/examples/simple') From d94238ae9cb7f0ad3d917a7dc71c31e5ab1396fc Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Sat, 9 Dec 2017 11:49:49 -0500 Subject: [PATCH 06/10] add travis CI build, setup Cypress dashboard --- .travis.yml | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..63c5f4456 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,39 @@ +language: node_js + +node_js: + - 6.5.0 + +install: + - npm install + +before_script: + ## runs the 'start' script which + ## boots our local app server on port 8080 + ## which cypress expects to be running + ## ----------------------------------- + ## the '-- --silent' passes arguments + ## to http-server which silences its output + ## else our travis logs would be cluttered + ## with output from HTTP requests + ## https://docs.npmjs.com/cli/start + ## https://github.com/indexzero/http-server + ## --------------------------------------- + ## we use the '&' ampersand which tells + ## travis to run this process in the background + ## else it would block execution and hang travis + - npm start -- --silent & + +script: + ## now run cypress headlessly + ## and record all of the tests. + ## Cypress will search for a + ## CYPRESS_RECORD_KEY environment + ## variable by default and apply + ## this to the run. + - $(npm bin)/cypress run --record + + ## alternatively we could specify + ## a specific record key to use + ## like this without having to + ## configure environment variables + ## - cypress run --record --key From 58e3796aad947d23e15c69ae90ca399228e4dd1d Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Sat, 9 Dec 2017 11:56:01 -0500 Subject: [PATCH 07/10] add links to the project's Cypress dashboard page --- .travis.yml | 33 +++++---------------------------- README.md | 5 +++-- 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/.travis.yml b/.travis.yml index 63c5f4456..485c3fbd1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,39 +1,16 @@ language: node_js node_js: - - 6.5.0 + - 8 install: - npm install -before_script: - ## runs the 'start' script which - ## boots our local app server on port 8080 - ## which cypress expects to be running - ## ----------------------------------- - ## the '-- --silent' passes arguments - ## to http-server which silences its output - ## else our travis logs would be cluttered - ## with output from HTTP requests - ## https://docs.npmjs.com/cli/start - ## https://github.com/indexzero/http-server - ## --------------------------------------- - ## we use the '&' ampersand which tells - ## travis to run this process in the background - ## else it would block execution and hang travis - - npm start -- --silent & - script: ## now run cypress headlessly ## and record all of the tests. ## Cypress will search for a - ## CYPRESS_RECORD_KEY environment - ## variable by default and apply - ## this to the run. - - $(npm bin)/cypress run --record - - ## alternatively we could specify - ## a specific record key to use - ## like this without having to - ## configure environment variables - ## - cypress run --record --key + ## CYPRESS_PROJECT_ID and CYPRESS_RECORD_KEY environment variables + - npm test -- --record + ## see recording of the test run at + ## https://dashboard.cypress.io/#/projects/p7bh2z/runs diff --git a/README.md b/README.md index 968e78a82..a3f9f06cb 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ [![License](http://img.shields.io/badge/License-MIT-blue.svg)](http://opensource.org/licenses/MIT) [![PayPal Donate](https://img.shields.io/badge/donate-PayPal.me-ff69b4.svg)](https://www.paypal.me/alvarotrigo/9.95) [![jsDelivr Hits](https://data.jsdelivr.com/v1/package/npm/fullpage.js/badge?style=rounded)](https://www.jsdelivr.com/package/npm/fullpage.js) -[![Cypress.io tests](https://img.shields.io/badge/cypress.io-tests-green.svg?style=flat-square)](https://cypress.io) +[![Cypress.io tests](https://img.shields.io/badge/cypress.io-tests-green.svg?style=flat-square)](https://dashboard.cypress.io/#/projects/p7bh2z/runs) +[![Build Status](https://travis-ci.org/bahmutov/fullPage.js.svg?branch=master)](https://travis-ci.org/bahmutov/fullPage.js)    **|**   *7Kb gziped*   **|**   *Created by [@imac2](https://twitter.com/imac2)* - [Live demo](http://alvarotrigo.com/fullPage/) @@ -894,7 +895,7 @@ To see E2E tests live use $ npm run test:gui ``` -The Cypress runner keeps watching your test files, rerunning the tests as you are editing the spec files. Find the spec files in the [cypress/integration](cypress/integration) folder. +The Cypress runner keeps watching your test files, rerunning the tests as you are editing the spec files. Find the spec files in the [cypress/integration](cypress/integration) folder. The tests are also running on [CI](https://travis-ci.org/bahmutov/fullPage.js) and the output and video recordings can be found on [Cypress dashboard](https://dashboard.cypress.io/#/projects/p7bh2z/runs) # Resources - [Wordpress theme](http://alvarotrigo.com/fullPage/utils/wordpress.html) From 1decd67122582ece676f28f3f92deb8180f8686b Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Sat, 9 Dec 2017 12:08:35 -0500 Subject: [PATCH 08/10] pass record option on CI --- .travis.yml | 2 +- package.json | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 485c3fbd1..1bf887728 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,6 @@ script: ## and record all of the tests. ## Cypress will search for a ## CYPRESS_PROJECT_ID and CYPRESS_RECORD_KEY environment variables - - npm test -- --record + - npm run test:record ## see recording of the test run at ## https://dashboard.cypress.io/#/projects/p7bh2z/runs diff --git a/package.json b/package.json index a486b7796..c03f47c70 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,12 @@ "main": "dist/jquery.fullpage.js", "scripts": { "test": "run-p --race start cy:run", + "test:record": "run-p --race start cy:run:record", "test:gui": "run-p --race start cy:open", "start": "http-server -c-1 -p 4600 --silent", "cy:open": "cypress open", - "cy:run": "cypress run" + "cy:run": "cypress run", + "cy:run:record": "cypress run --record" }, "repository": { "type": "git", From 272736d837207590aa42c95b16e32b9f9152e188 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Sat, 9 Dec 2017 12:12:22 -0500 Subject: [PATCH 09/10] cache node_modules for speed --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1bf887728..11e7b1f03 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,10 @@ language: node_js node_js: - 8 +cache: + directories: + - node_modules + install: - npm install From bcc56da2273c06d407e1773d43f8614b33d6e54e Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Mon, 11 Dec 2017 15:41:51 -0500 Subject: [PATCH 10/10] use body.type instead of trigger event --- cypress/integration/simple_spec.js | 9 +++++++-- cypress/support/index.js | 17 +++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/cypress/integration/simple_spec.js b/cypress/integration/simple_spec.js index 8ea7bed80..a76b05fda 100644 --- a/cypress/integration/simple_spec.js +++ b/cypress/integration/simple_spec.js @@ -17,12 +17,17 @@ describe('simple example', () => { }) it('goes down to second slide', () => { - cy.document().its('body').trigger('keydown', { which: Arrows.down }) + // cy.document().its('body').trigger('keydown', { which: Arrows.down }) + cy.document().its('body').type('{downarrow}') cy.contains('.section', 'Only text').should('have.class', 'active') }) - it('goes down to 4th slide', () => { + it('goes down to 2nd slide - auto wait', () => { slide.down() + checkActiveSlide('Only text') + }) + + it('goes down to 4th slide', () => { slide.down() slide.down() slide.down() diff --git a/cypress/support/index.js b/cypress/support/index.js index 49b000b54..eb12f09e0 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -18,16 +18,21 @@ import './commands' // Alternatively you can use CommonJS syntax: // require('./commands') +/* global cy */ export const Arrows = { - up: 38, - down: 40, - left: 37, - right: 39 + up: '{uparrow}', + down: '{downarrow}', + left: '{leftarrow}', + right: '{rightarrow}' } -function triggerArrow (which) { - cy.document().its('body').trigger('keydown', { which }).wait(1000) +function triggerArrow (arrow) { + cy.document().its('body').type(arrow) + // wait for a second. If there was consistent _unique_ CSS selector + // for "transition going on", and then "transition finished" + // we could select on that to avoid hard coded duration + cy.wait(1000) } export const slide = {