diff --git a/.eslintignore b/.eslintignore
index c2f60820..d5a2cd70 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -2,3 +2,4 @@
scripts/install.js
scripts/verify.js
coverage
+client/cypress/examples/**
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index f0929ee7..28499311 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ build
*.log
npm-debug.log*
.mongo-db
+client/cypress/videos
diff --git a/client/cypress.json b/client/cypress.json
new file mode 100644
index 00000000..0967ef42
--- /dev/null
+++ b/client/cypress.json
@@ -0,0 +1 @@
+{}
diff --git a/client/cypress/examples/fixtures/example.json b/client/cypress/examples/fixtures/example.json
new file mode 100644
index 00000000..da18d935
--- /dev/null
+++ b/client/cypress/examples/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/client/cypress/examples/fixtures/profile.json b/client/cypress/examples/fixtures/profile.json
new file mode 100644
index 00000000..b6c355ca
--- /dev/null
+++ b/client/cypress/examples/fixtures/profile.json
@@ -0,0 +1,5 @@
+{
+ "id": 8739,
+ "name": "Jane",
+ "email": "jane@example.com"
+}
\ No newline at end of file
diff --git a/client/cypress/examples/fixtures/users.json b/client/cypress/examples/fixtures/users.json
new file mode 100644
index 00000000..79b699aa
--- /dev/null
+++ b/client/cypress/examples/fixtures/users.json
@@ -0,0 +1,232 @@
+[
+ {
+ "id": 1,
+ "name": "Leanne Graham",
+ "username": "Bret",
+ "email": "Sincere@april.biz",
+ "address": {
+ "street": "Kulas Light",
+ "suite": "Apt. 556",
+ "city": "Gwenborough",
+ "zipcode": "92998-3874",
+ "geo": {
+ "lat": "-37.3159",
+ "lng": "81.1496"
+ }
+ },
+ "phone": "1-770-736-8031 x56442",
+ "website": "hildegard.org",
+ "company": {
+ "name": "Romaguera-Crona",
+ "catchPhrase": "Multi-layered client-server neural-net",
+ "bs": "harness real-time e-markets"
+ }
+ },
+ {
+ "id": 2,
+ "name": "Ervin Howell",
+ "username": "Antonette",
+ "email": "Shanna@melissa.tv",
+ "address": {
+ "street": "Victor Plains",
+ "suite": "Suite 879",
+ "city": "Wisokyburgh",
+ "zipcode": "90566-7771",
+ "geo": {
+ "lat": "-43.9509",
+ "lng": "-34.4618"
+ }
+ },
+ "phone": "010-692-6593 x09125",
+ "website": "anastasia.net",
+ "company": {
+ "name": "Deckow-Crist",
+ "catchPhrase": "Proactive didactic contingency",
+ "bs": "synergize scalable supply-chains"
+ }
+ },
+ {
+ "id": 3,
+ "name": "Clementine Bauch",
+ "username": "Samantha",
+ "email": "Nathan@yesenia.net",
+ "address": {
+ "street": "Douglas Extension",
+ "suite": "Suite 847",
+ "city": "McKenziehaven",
+ "zipcode": "59590-4157",
+ "geo": {
+ "lat": "-68.6102",
+ "lng": "-47.0653"
+ }
+ },
+ "phone": "1-463-123-4447",
+ "website": "ramiro.info",
+ "company": {
+ "name": "Romaguera-Jacobson",
+ "catchPhrase": "Face to face bifurcated interface",
+ "bs": "e-enable strategic applications"
+ }
+ },
+ {
+ "id": 4,
+ "name": "Patricia Lebsack",
+ "username": "Karianne",
+ "email": "Julianne.OConner@kory.org",
+ "address": {
+ "street": "Hoeger Mall",
+ "suite": "Apt. 692",
+ "city": "South Elvis",
+ "zipcode": "53919-4257",
+ "geo": {
+ "lat": "29.4572",
+ "lng": "-164.2990"
+ }
+ },
+ "phone": "493-170-9623 x156",
+ "website": "kale.biz",
+ "company": {
+ "name": "Robel-Corkery",
+ "catchPhrase": "Multi-tiered zero tolerance productivity",
+ "bs": "transition cutting-edge web services"
+ }
+ },
+ {
+ "id": 5,
+ "name": "Chelsey Dietrich",
+ "username": "Kamren",
+ "email": "Lucio_Hettinger@annie.ca",
+ "address": {
+ "street": "Skiles Walks",
+ "suite": "Suite 351",
+ "city": "Roscoeview",
+ "zipcode": "33263",
+ "geo": {
+ "lat": "-31.8129",
+ "lng": "62.5342"
+ }
+ },
+ "phone": "(254)954-1289",
+ "website": "demarco.info",
+ "company": {
+ "name": "Keebler LLC",
+ "catchPhrase": "User-centric fault-tolerant solution",
+ "bs": "revolutionize end-to-end systems"
+ }
+ },
+ {
+ "id": 6,
+ "name": "Mrs. Dennis Schulist",
+ "username": "Leopoldo_Corkery",
+ "email": "Karley_Dach@jasper.info",
+ "address": {
+ "street": "Norberto Crossing",
+ "suite": "Apt. 950",
+ "city": "South Christy",
+ "zipcode": "23505-1337",
+ "geo": {
+ "lat": "-71.4197",
+ "lng": "71.7478"
+ }
+ },
+ "phone": "1-477-935-8478 x6430",
+ "website": "ola.org",
+ "company": {
+ "name": "Considine-Lockman",
+ "catchPhrase": "Synchronised bottom-line interface",
+ "bs": "e-enable innovative applications"
+ }
+ },
+ {
+ "id": 7,
+ "name": "Kurtis Weissnat",
+ "username": "Elwyn.Skiles",
+ "email": "Telly.Hoeger@billy.biz",
+ "address": {
+ "street": "Rex Trail",
+ "suite": "Suite 280",
+ "city": "Howemouth",
+ "zipcode": "58804-1099",
+ "geo": {
+ "lat": "24.8918",
+ "lng": "21.8984"
+ }
+ },
+ "phone": "210.067.6132",
+ "website": "elvis.io",
+ "company": {
+ "name": "Johns Group",
+ "catchPhrase": "Configurable multimedia task-force",
+ "bs": "generate enterprise e-tailers"
+ }
+ },
+ {
+ "id": 8,
+ "name": "Nicholas Runolfsdottir V",
+ "username": "Maxime_Nienow",
+ "email": "Sherwood@rosamond.me",
+ "address": {
+ "street": "Ellsworth Summit",
+ "suite": "Suite 729",
+ "city": "Aliyaview",
+ "zipcode": "45169",
+ "geo": {
+ "lat": "-14.3990",
+ "lng": "-120.7677"
+ }
+ },
+ "phone": "586.493.6943 x140",
+ "website": "jacynthe.com",
+ "company": {
+ "name": "Abernathy Group",
+ "catchPhrase": "Implemented secondary concept",
+ "bs": "e-enable extensible e-tailers"
+ }
+ },
+ {
+ "id": 9,
+ "name": "Glenna Reichert",
+ "username": "Delphine",
+ "email": "Chaim_McDermott@dana.io",
+ "address": {
+ "street": "Dayna Park",
+ "suite": "Suite 449",
+ "city": "Bartholomebury",
+ "zipcode": "76495-3109",
+ "geo": {
+ "lat": "24.6463",
+ "lng": "-168.8889"
+ }
+ },
+ "phone": "(775)976-6794 x41206",
+ "website": "conrad.com",
+ "company": {
+ "name": "Yost and Sons",
+ "catchPhrase": "Switchable contextually-based project",
+ "bs": "aggregate real-time technologies"
+ }
+ },
+ {
+ "id": 10,
+ "name": "Clementina DuBuque",
+ "username": "Moriah.Stanton",
+ "email": "Rey.Padberg@karina.biz",
+ "address": {
+ "street": "Kattie Turnpike",
+ "suite": "Suite 198",
+ "city": "Lebsackbury",
+ "zipcode": "31428-2261",
+ "geo": {
+ "lat": "-38.2386",
+ "lng": "57.2232"
+ }
+ },
+ "phone": "024-648-3804",
+ "website": "ambrose.net",
+ "company": {
+ "name": "Hoeger LLC",
+ "catchPhrase": "Centralized empowering task-force",
+ "bs": "target end-to-end models"
+ }
+ }
+]
\ No newline at end of file
diff --git a/client/cypress/examples/integration/example_spec.js b/client/cypress/examples/integration/example_spec.js
new file mode 100644
index 00000000..43b840fa
--- /dev/null
+++ b/client/cypress/examples/integration/example_spec.js
@@ -0,0 +1,1568 @@
+//
+// **** Kitchen Sink Tests ****
+//
+// This app was developed to demonstrate
+// how to write tests in Cypress utilizing
+// all of the available commands
+//
+// Feel free to modify this spec in your
+// own application as a jumping off point
+
+// **** Test Structure ****
+//
+// Cypress has adopted Mocha's bdd syntax.
+// https://on.cypress.io/guides/bundled-tools#section-mocha
+//
+
+describe('Kitchen Sink', function(){
+
+ beforeEach(function(){
+ // **** Resetting State Before Each Test ****
+ //
+ // Visiting our app before each test
+ // removes any state build up from
+ // previous tests. Visiting acts as if
+ // we closed a tab and opened a fresh one
+ //
+ // By default Cypress also automatically
+ // clears the Local Storage and Cookies
+ // before each test.
+ })
+
+ it('cy.should - assert that
is correct', function(){
+
+ // https://on.cypress.io/api/visit
+ cy.visit('https://example.cypress.io')
+
+ // **** Making Assertions ****
+ //
+ // Here we've made our first assertion using a 'cy.should()' command.
+ // An assertion is comprised of a chainer, subject, and optional value.
+ // Chainers are available from Chai, Chai-jQuery, and Chai-Sinon.
+ // https://on.cypress.io/guides/making-assertions
+ //
+ // https://on.cypress.io/api/should
+ // https://on.cypress.io/api/and
+
+ // https://on.cypress.io/api/title
+ cy.title().should('include', 'Kitchen Sink')
+ // ↲ ↲ ↲
+ // subject chainer value
+ })
+
+ context('Querying', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/commands/querying')
+ })
+
+ // **** Querying DOM Elements ****
+ //
+ // Let's query for some DOM elements and make assertions
+ // The most commonly used query is 'cy.get()', you can
+ // think of this like the '$' in jQueury
+
+ it('cy.get() - query DOM elements', function(){
+
+ // https://on.cypress.io/api/get
+ // We can get DOM elements by id
+ cy.get('#query-btn').should('contain', 'Button')
+
+ // We can get DOM elements by class
+ cy.get('.query-btn').should('contain', 'Button')
+
+ cy.get('#querying .well>button:first').should('contain', 'Button')
+ // ↲
+ // we can CSS selectors just like jQuery
+ })
+
+ it('cy.contains() - query DOM elements with matching content', function(){
+
+ // https://on.cypress.io/api/contains
+ cy
+ .get('.query-list')
+ .contains('bananas').should('have.class', 'third')
+
+ // we can even pass a regexp to `cy.contains()`
+ .get('.query-list')
+ .contains(/^b\w+/).should('have.class', 'third')
+
+ // `cy.contains()` will return the first matched element
+ .get('.query-list')
+ .contains('apples').should('have.class', 'first')
+
+ // passing a selector to contains will return the parent
+ // selector containing the text
+ .get('#querying')
+ .contains('ul', 'oranges').should('have.class', 'query-list')
+
+ // `cy.contains()` will favor input[type='submit'],
+ // button, a, and label over deeper elements inside them
+ // this will not return the inside the button,
+ // but the itself
+ .get('.query-button')
+ .contains('Save Form').should('have.class', 'btn')
+ })
+
+ it('cy.within() - query DOM elements within a specific element', function(){
+
+ // https://on.cypress.io/api/within
+ cy.get('.query-form').within(function(){
+ cy
+ .get('input:first').should('have.attr', 'placeholder', 'Email')
+ .get('input:last').should('have.attr', 'placeholder', 'Password')
+ })
+ })
+
+ it('cy.root() - query the root DOM element', function(){
+
+ // https://on.cypress.io/api/root
+ // By default, root is the document
+ cy.root().should('match', 'html')
+
+ cy.get('.query-ul').within(function(){
+ // In this within, the root is now the ul DOM element
+ cy.root().should('have.class', 'query-ul')
+ })
+ })
+ })
+
+ context('Traversal', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/commands/traversal')
+ })
+
+ // **** Traversing DOM Elements ****
+ //
+ // Let's query for some DOM elements and make assertions
+ // The most commonly used query is 'cy.get()', you can
+ // think of this like the '$' in jQueury
+
+ it('cy.children() - get child DOM elements', function(){
+
+ // https://on.cypress.io/api/children
+ cy.get('.traversal-breadcrumb').children('.active').should('contain', 'Data')
+ })
+
+ it('cy.closest() - get closest ancestor DOM element', function(){
+
+ // https://on.cypress.io/api/closest
+ cy.get('.traversal-badge').closest('ul').should('have.class', 'list-group')
+ })
+
+ it('cy.eq() - get a DOM element at a specific index', function(){
+
+ // https://on.cypress.io/api/eq
+ cy.get('.traversal-list>li').eq(1).should('contain', 'siamese')
+ })
+
+ it('cy.filter() - get DOM elements that match the selector', function(){
+
+ // https://on.cypress.io/api/filter
+ cy.get('.traversal-nav>li').filter('.active').should('contain', 'About')
+ })
+
+ it('cy.find() - get descendant DOM elements of the selector', function(){
+
+ // https://on.cypress.io/api/find
+ cy.get('.traversal-pagination').find('li').find('a').should('have.length', 7)
+ })
+
+ it('cy.first() - get first DOM element', function(){
+
+ // https://on.cypress.io/api/first
+ cy.get('.traversal-table td').first().should('contain', '1')
+ })
+
+ it('cy.last() - get last DOM element', function(){
+
+ // https://on.cypress.io/api/last
+ cy.get('.traversal-buttons .btn').last().should('contain', 'Submit')
+ })
+
+ it('cy.next() - get next sibling DOM element', function(){
+
+ // https://on.cypress.io/api/next
+ cy.get('.traversal-ul').contains('apples').next().should('contain', 'oranges')
+ })
+
+ it('cy.not() - remove DOM elements from set of DOM elements', function(){
+
+ // https://on.cypress.io/api/not
+ cy.get('.traversal-disabled .btn').not('[disabled]').should('not.contain', 'Disabled')
+ })
+
+ it('cy.parents() - get parents DOM element from set of DOM elements', function(){
+
+ // https://on.cypress.io/api/parents
+ cy.get('.traversal-cite').parents().should('match', 'blockquote')
+ })
+
+ it('cy.siblings() - get all sibling DOM elements from set of DOM elements', function(){
+
+ // https://on.cypress.io/api/siblings
+ cy.get('.traversal-pills .active').siblings().should('have.length', 2)
+ })
+ })
+
+ context('Actions', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/commands/actions')
+ })
+
+ // **** Actions ****
+ //
+ // Let's perform some actions on DOM elements
+ // Move of these involve filling in form elements
+ // But some actions, like click, will often be
+ // used throughout an application
+
+ it('cy.type() - type into a DOM element', function(){
+
+ // https://on.cypress.io/api/type
+ cy
+ .get('.action-email')
+ .type('fake@email.com').should('have.value', 'fake@email.com')
+
+ // cy.type() may include special character sequences
+ .type('{leftarrow}{rightarrow}{uparrow}{downarrow}{del}{selectall}{backspace}')
+
+ // cy.type() may additionally include key modifiers
+ .type('{alt}{option}') //these are equivalent
+ .type('{ctrl}{control}') //these are equivalent
+ .type('{meta}{command}{cmd}') //these are equivalent
+ .type('{shift}')
+
+ // **** Type Options ****
+ //
+ // cy.type() accepts options that control typing
+ //
+ // Delay each keypress by 0.1 sec
+ // You may want to set the delay which
+ // causes the keystrokes to happen much slower
+ // in some situations if the application under
+ // test is not able to handle rapid firing events.
+ // (generally due to the app not properly throttling events)
+ .type('slow.typing@email.com', {delay: 100})
+ .should('have.value', 'slow.typing@email.com')
+
+ .get('.action-disabled')
+
+ // Ignore error checking prior to type
+ // like whether the input is visible or disabled
+ .type('disabled error checking', {force: true})
+ .should('have.value', 'disabled error checking')
+ })
+
+ it('cy.focus() - focus on a DOM element', function(){
+
+ // https://on.cypress.io/api/focus
+ cy
+ .get('.action-focus').focus()
+ .should('have.class', 'focus')
+ .prev().should('have.attr', 'style', 'color: orange;')
+ })
+
+ it('cy.blur() - blur off a DOM element', function(){
+
+ // https://on.cypress.io/api/blur
+ cy
+ .get('.action-blur').type('I\'m about to blur').blur()
+ .should('have.class', 'error')
+ .prev().should('have.attr', 'style', 'color: red;')
+ })
+
+
+ it('cy.clear() - clears the value of an input or textarea element', function(){
+
+ // https://on.cypress.io/api/clear
+ cy
+ .get('.action-clear').type('We are going to clear this text')
+ .should('have.value', 'We are going to clear this text')
+ .clear()
+ .should('have.value', '')
+ })
+
+ it('cy.submit() - submit a form', function(){
+
+ // https://on.cypress.io/api/submit
+ cy
+ .get('.action-form')
+ .find('[type="text"]').type('HALFOFF')
+ .get('.action-form').submit()
+ .next().should('contain', 'Your form has been submitted!')
+ })
+
+ it('cy.click() - click on a DOM element', function(){
+
+ // https://on.cypress.io/api/click
+ cy.get('.action-btn').click()
+
+ // **** Click Position ****
+ //
+ // cy.click() accepts a position argument
+ // that controls where the click occurs
+ //
+ // clicking in the center of the element is the default
+ cy.get('#action-canvas').click()
+
+ // click the top left corner of the element
+ cy.get('#action-canvas').click('topLeft')
+
+ // click the top right corner of the element
+ cy.get('#action-canvas').click('topRight')
+
+ // click the bottom left corner of the element
+ cy.get('#action-canvas').click('bottomLeft')
+
+ // click the bottom right corner of the element
+ cy.get('#action-canvas').click('bottomRight')
+
+ // **** Click Coordinate ****
+ //
+ // cy.click() accepts a an x and y coordinate
+ // that controls where the click occurs :)
+
+ cy
+ .get('#action-canvas')
+ // click 80px on x coord and 75px on y coord
+ .click(80, 75)
+ .click(170, 75)
+ .click(80, 165)
+ .click(100, 185)
+ .click(125, 190)
+ .click(150, 185)
+ .click(170, 165)
+
+ // **** Click Options ****
+ //
+ // cy.click() accepts options that control clicking
+ //
+ // click multiple elements by passing multiple: true
+ // otherwise an error will be thrown if multiple
+ // elements are the subject of cy.click
+ cy.get('.action-labels>.label').click({multiple: true})
+
+ // Ignore error checking prior to clicking
+ // like whether the element is visible, clickable or disabled
+ // this button below is covered by another element.
+ cy.get('.action-opacity>.btn').click({force: true})
+ })
+
+ it('cy.dblclick() - double click on a DOM element', function(){
+
+ // We have a listener on 'dblclick' event in our 'scripts.js'
+ // that hides the div and shows an input on double click
+
+ // https://on.cypress.io/api/dblclick
+ cy
+ .get('.action-div').dblclick().should('not.be.visible')
+ .get('.action-input-hidden').should('be.visible')
+ })
+
+ it('cy.check() - check a checkbox or radio element', function(){
+
+ // By default, cy.check() will check all
+ // matching checkbox or radio elements in succession, one after another
+
+ // https://on.cypress.io/api/check
+ cy
+ .get('.action-checkboxes [type="checkbox"]').not('[disabled]').check().should('be.checked')
+
+ .get('.action-radios [type="radio"]').not('[disabled]').check().should('be.checked')
+
+ // **** Check Value ****
+ //
+ // cy.check() accepts a value argument
+ // that checks only checkboxes or radios
+ // with matching values
+ //
+ .get('.action-radios [type="radio"]').check('radio1').should('be.checked')
+
+ // **** Check Values ****
+ //
+ // cy.check() accepts an array of values
+ // that checks only checkboxes or radios
+ // with matching values
+ //
+ .get('.action-multiple-checkboxes [type="checkbox"]').check(['checkbox1', 'checkbox2']).should('be.checked')
+
+ // **** Check Options ****
+ //
+ // cy.check() accepts options that control checking
+ //
+ // Ignore error checking prior to checking
+ // like whether the element is visible, clickable or disabled
+ // this checkbox below is disabled.
+ .get('.action-checkboxes [disabled]')
+ .check({force: true}).should('be.checked')
+
+ .get('.action-radios [type="radio"]').check('radio3', {force: true}).should('be.checked')
+ })
+
+
+ it('cy.uncheck() - uncheck a checkbox element', function(){
+
+ // By default, cy.uncheck() will uncheck all matching
+ // checkbox elements in succession, one after another
+
+ // https://on.cypress.io/api/uncheck
+ cy
+ .get('.action-check [type="checkbox"]')
+ .not('[disabled]')
+ .uncheck().should('not.be.checked')
+
+ // **** Check Value ****
+ //
+ // cy.uncheck() accepts a value argument
+ // that unchecks only checkboxes
+ // with matching values
+ //
+ .get('.action-check [type="checkbox"]')
+ .check('checkbox1')
+ .uncheck('checkbox1').should('not.be.checked')
+
+ // **** Uncheck Values ****
+ //
+ // cy.uncheck() accepts an array of values
+ // that unchecks only checkboxes or radios
+ // with matching values
+ //
+ .get('.action-check [type="checkbox"]')
+ .check(['checkbox1', 'checkbox3'])
+ .uncheck(['checkbox1', 'checkbox3']).should('not.be.checked')
+
+ // **** Uncheck Options ****
+ //
+ // cy.uncheck() accepts options that control unchecking
+ //
+ // Ignore error checking prior to unchecking
+ // like whether the element is visible, clickable or disabled
+ // this checkbox below is disabled.
+ .get('.action-check [disabled]')
+ .uncheck({force: true}).should('not.be.checked')
+ })
+
+ it('cy.select() - select an option in a element', function(){
+
+ // https://on.cypress.io/api/select
+
+ // Select the option with matching text content
+ cy.get('.action-select').select('apples')
+
+ // Select the option with matching value
+ cy.get('.action-select').select('fr-bananas')
+
+ // Select the options with matching text content
+ cy.get('.action-select-multiple').select(['apples', 'oranges', 'bananas'])
+
+ // Select the options with matching values
+ cy.get('.action-select-multiple').select(['fr-apples', 'fr-oranges', 'fr-bananas'])
+ })
+ })
+
+ context('Window', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/commands/window')
+ })
+
+ // **** Window ****
+ //
+ // Cypress has commands to help you get
+ // access to window, document, and title
+
+ it('cy.window() - get the global window object', function(){
+
+ // https://on.cypress.io/api/window
+ cy.window().should('have.property', 'top')
+ })
+
+ it('cy.document() - get the document object', function(){
+
+ // https://on.cypress.io/api/document
+ cy.document().should('have.property', 'charset').and('eq', 'UTF-8')
+ })
+
+ it('cy.title() - get the title', function(){
+
+ // https://on.cypress.io/api/title
+ cy.title().should('include', 'Kitchen Sink')
+ })
+ })
+
+ context('Viewport', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/commands/viewport')
+ })
+
+ // **** Viewport ****
+ //
+ // Let's make some assertions based on
+ // the size of our screen. This command
+ // is great for checking responsive logic
+
+ it('cy.viewport() - set the viewport size and dimension', function(){
+
+ cy
+ .get('#navbar').should('be.visible')
+
+ // https://on.cypress.io/api/viewport
+ cy.viewport(320, 480)
+
+ // the navbar should have collapse since our screen is smaller
+ cy
+ .get('#navbar').should('not.be.visible')
+ .get('.navbar-toggle').should('be.visible').click()
+ .get('.nav').find('a').should('be.visible')
+
+ // lets see what our app looks like on a super large screen
+ cy.viewport(2999, 2999)
+
+ // **** Viewport Presets ****
+ //
+ // cy.viewport() accepts a set of preset sizes
+ // to easily set the screen to a device's width and height
+
+ // We added a cy.wait() between each viewport change so you can see
+ // the change otherwise it's a little too fast to see :)
+ //
+ cy
+ .viewport('macbook-15')
+ .wait(200)
+ .viewport('macbook-13')
+ .wait(200)
+ .viewport('macbook-11')
+ .wait(200)
+ .viewport('ipad-2')
+ .wait(200)
+ .viewport('ipad-mini')
+ .wait(200)
+ .viewport('iphone-6+')
+ .wait(200)
+ .viewport('iphone-6')
+ .wait(200)
+ .viewport('iphone-5')
+ .wait(200)
+ .viewport('iphone-4')
+ .wait(200)
+ .viewport('iphone-3')
+ .wait(200)
+
+ // **** Viewport Orientation ****
+ //
+ // cy.viewport() accepts an orientation for all presets
+ // the default orientation is 'portrait'
+ //
+ cy
+ .viewport('ipad-2', 'portrait')
+ .wait(200)
+ .viewport('iphone-4', 'landscape')
+ .wait(200)
+
+ // The viewport will be reset back to the default dimensions
+ // in between tests (the default is set in cypress.json)
+ })
+ })
+
+ context('Location', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/commands/location')
+ })
+
+ // **** Location ****
+ //
+ // We look at the url to make assertions
+ // about the page's state
+
+ it('cy.hash() - get the current URL hash', function(){
+
+ // https://on.cypress.io/api/hash
+ cy.hash().should('be.empty')
+ })
+
+ it('cy.location() - get window.location', function(){
+
+ // https://on.cypress.io/api/location
+ cy.location().then(function(location){
+ expect(location.hash).to.be.empty
+ expect(location.href).to.eq('https://example.cypress.io/commands/location')
+ expect(location.host).to.eq('example.cypress.io')
+ expect(location.hostname).to.eq('example.cypress.io')
+ expect(location.origin).to.eq('https://example.cypress.io')
+ expect(location.pathname).to.eq('/commands/location')
+ expect(location.port).to.eq('')
+ expect(location.protocol).to.eq('https:')
+ expect(location.search).to.be.empty
+ })
+ })
+
+ it('cy.url() - get the current URL', function(){
+
+ // https://on.cypress.io/api/url
+ cy.url().should('eq', 'https://example.cypress.io/commands/location')
+ })
+ })
+
+ context('Navigation', function(){
+ beforeEach(function(){
+ cy
+ .visit('https://example.cypress.io')
+ .get('.navbar-nav').contains('Commands').click()
+ .get('.dropdown-menu').contains('Navigation').click()
+ })
+
+ // **** Navigation ****
+ //
+ // We can issue commands to visit, reload the page,
+ // navigate in the browser's history
+
+ it('cy.go() - go back or forward in the browser\'s history', function(){
+
+ cy.location().its('pathname').should('include', 'navigation')
+
+ // https://on.cypress.io/api/go
+ cy.go('back')
+ cy.location().its('pathname').should('not.include', 'navigation')
+
+ cy.go('forward')
+ cy.location().its('pathname').should('include', 'navigation')
+
+ // equivalent to clicking back
+ cy.go(-1)
+ cy.location().its('pathname').should('not.include', 'navigation')
+
+ // equivalent to clicking forward
+ cy.go(1)
+ cy.location().its('pathname').should('include', 'navigation')
+
+ })
+
+ it('cy.reload() - reload the page', function(){
+ // https://on.cypress.io/api/reload
+ cy.reload()
+
+ // reload the page without using the cache
+ cy.reload(true)
+ })
+
+ it('cy.visit() - visit a remote url', function(){
+
+ // Visit any sub-domain of your current domain
+ // https://on.cypress.io/api/visit
+
+ // Pass options to the visit
+ cy.visit('https://example.cypress.io/commands/navigation', {
+ timeout: 50000, // increase total time for the visit to resolve
+ onBeforeLoad: function(contentWindow){
+ // contentWindow is the remote page's window object
+ },
+ onLoad: function(contentWindow){
+ // contentWindow is the remote page's window object
+ }
+ })
+ })
+ })
+
+ context('Assertions', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/commands/assertions')
+ })
+ // **** Assertions ****
+ //
+ describe('Implicit Assertions', function(){
+
+ it('cy.should - make an assertion about the current subject', function(){
+
+ // https://on.cypress.io/api/should
+ cy
+ .get('.assertion-table')
+ .find('tbody tr:last').should('have.class', 'success')
+ })
+
+ it('cy.and - chain multiple assertions together', function(){
+
+ // https://on.cypress.io/api/and
+ cy
+ .get('.assertions-link')
+ .should('have.class', 'active')
+ .and('have.attr', 'href')
+ .and('include', 'cypress.io')
+ })
+
+ })
+
+ describe('Explicit Assertions', function(){
+
+ it('expect - make an assertion about a specified subject', function(){
+
+ // We can use Chai's BDD style assertions
+ expect(true).to.be.true
+
+ // Pass a function to should that can have any number
+ // of explicit assertions within it.
+ cy
+ .get('.assertions-p').find('p')
+ .should(function($p){
+ // return an array of texts from all of the p's
+ var texts = $p.map(function(i, el){
+ // https://on.cypress.io/api/cypress-jquery
+ return Cypress.$(el).text()
+ })
+
+ // jquery map returns jquery object
+ // and .get() convert this to simple array
+ var texts = texts.get()
+
+ // array should have length of 3
+ expect(texts).to.have.length(3)
+
+ // set this specific subject
+ expect(texts).to.deep.eq([
+ 'Some text from first p',
+ 'More text from second p',
+ 'And even more text from third p'
+ ])
+ })
+ })
+ })
+ })
+
+ context('Misc', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/commands/misc')
+ })
+
+ it('cy.end() - end the command chain', function(){
+
+ // cy.end is useful when you want to end a chain of commands
+ // and force Cypress to re-query from the root element
+ //
+ // https://on.cypress.io/api/end
+ cy
+ .get('.misc-table').within(function(){
+ cy
+ // ends the current chain and returns null
+ .contains("Cheryl").click().end()
+
+ // queries the entire table again
+ .contains("Charles").click()
+ })
+ })
+
+ it('cy.exec() - execute a system command', function(){
+
+ // cy.exec allows you to execute a system command.
+ // so you can take actions necessary for your test,
+ // but outside the scope of Cypress.
+ //
+ // https://on.cypress.io/api/exec
+ cy
+ .exec('echo Jane Lane')
+ .its('stdout').should('contain', 'Jane Lane')
+
+ .exec('cat cypress.json')
+ .its('stderr').should('be.empty')
+
+ .exec('pwd')
+ .its('code').should('eq', 0)
+ })
+
+ it('cy.focused() - get the DOM element that has focus', function(){
+
+ // https://on.cypress.io/api/focused
+ cy
+ .get('.misc-form').find('#name').click()
+ .focused().should('have.id', 'name')
+
+ .get('.misc-form').find('#description').click()
+ .focused().should('have.id', 'description')
+ })
+
+ it("cy.screenshot() - take a screenshot", function(){
+
+ // https://on.cypress.io/api/screenshot
+ cy.screenshot("my-image")
+ })
+
+ it('cy.wrap() - wrap an object', function(){
+
+ // https://on.cypress.io/api/wrap
+ cy
+ .wrap({foo: 'bar'})
+ .should('have.property', 'foo')
+ .and('include', 'bar')
+ })
+
+ })
+
+ context('Connectors', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/commands/connectors')
+ })
+
+ // **** Connectors ****
+ //
+ // Some commands are just used to manipulate elements,
+ // properties or invoke functions on the current subject
+
+ it('cy.each() - iterate over an array of elements', function(){
+
+ // https://on.cypress.io/api/each
+
+ cy
+ .get('.connectors-each-ul>li')
+ .each(function($el, index, $list){
+ console.log($el, index, $list)
+ })
+ })
+
+ it('cy.its() - get properties on the current subject', function(){
+
+ // https://on.cypress.io/api/its
+ cy
+ .get('.connectors-its-ul>li')
+ // calls the 'length' property returning that value
+ .its('length')
+ .should('be.gt', 2)
+ })
+
+ it('cy.invoke() - invoke a function on the current subject', function(){
+
+ // our div is hidden in our script.js
+ // $('.connectors-div').hide()
+
+ // https://on.cypress.io/api/invoke
+ cy
+ .get('.connectors-div').should('be.hidden')
+
+ // call the jquery method 'show' on the 'div.container'
+ .invoke('show')
+ .should('be.visible')
+ })
+
+ it('cy.spread() - spread an array as individual arguments to a callback function', function(){
+
+ // https://on.cypress.io/api/spread
+ var arr = ['foo', 'bar', 'baz']
+
+ cy.wrap(arr).spread(function(foo, bar, baz){
+ expect(foo).to.eq('foo')
+ expect(bar).to.eq('bar')
+ expect(baz).to.eq('baz')
+ })
+ })
+
+ it('cy.then() - invoke a callback function with the current subject', function(){
+
+ // https://on.cypress.io/api/then
+ cy.get('.connectors-list>li').then(function($lis){
+ expect($lis).to.have.length(3)
+ expect($lis.eq(0)).to.contain('Walk the dog')
+ expect($lis.eq(1)).to.contain('Feed the cat')
+ expect($lis.eq(2)).to.contain('Write JavaScript')
+ })
+ })
+ })
+
+ context('Aliasing', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/commands/aliasing')
+ })
+
+ // **** Aliasing ****
+ //
+ // We alias a DOM element for use later
+ // We don't have to traverse to the element
+ // later in our code, we just reference it with @
+
+ it('cy.as() - alias a route or DOM element for later use', function(){
+
+ // this is a good use case for an alias,
+ // we don't want to write this long traversal again
+ //
+ // https://on.cypress.io/api/as
+ cy
+ .get('.as-table').find('tbody>tr')
+ .first().find('td').first().find('button').as('firstBtn')
+
+ // maybe do some more testing here...
+
+ // when we reference the alias, we place an
+ // @ in front of it's name
+ .get('@firstBtn').click()
+
+ .get('@firstBtn')
+ .should('have.class', 'btn-success')
+ .and('contain', 'Changed')
+ })
+ })
+
+ context('Waiting', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/commands/waiting')
+ })
+ // **** Waiting ****
+ //
+ // Wait for a specific amount of ms before
+ // continuing to the next command
+ //
+ // BE CAREFUL of adding unnecessary wait times:
+ // https://on.cypress.io/guides/anti-patterns#section-adding-unnecessary-waits
+ //
+ // https://on.cypress.io/api/wait
+ it('cy.wait() - wait for a specific amount of time', function(){
+
+ cy
+ .get(".wait-input1").type('Wait 1000ms after typing')
+ .wait(1000)
+ .get(".wait-input2").type('Wait 1000ms after typing')
+ .wait(1000)
+ .get(".wait-input3").type('Wait 1000ms after typing')
+ .wait(1000)
+ })
+ //
+ // Waiting for a specific resource to resolve
+ // is covered within the cy.route() test below
+ //
+ })
+
+ context('Network Requests', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/commands/network-requests')
+ })
+
+ // **** Network Requests ****
+ //
+ // Manage AJAX / XHR requests in your app
+
+ it('cy.server() - control the behavior of network requests and responses', function(){
+
+ // https://on.cypress.io/api/server
+ cy.server().then(function(server){
+ // the default options on server
+ // you can override any of these options
+ expect(server.delay).to.eq(0)
+ expect(server.method).to.eq('GET')
+ expect(server.status).to.eq(200)
+ expect(server.headers).to.be.null
+ expect(server.response).to.be.null
+ expect(server.onRequest).to.be.undefined
+ expect(server.onResponse).to.be.undefined
+ expect(server.onAbort).to.be.undefined
+
+ // These options control the server behavior
+ // affecting all requests
+ expect(server.enable).to.be.true // pass false to disable existing route stubs
+ expect(server.force404).to.be.false // forces requests that don't match your routes to 404
+ expect(server.whitelist).to.be.a('function') // whitelists requests from ever being logged or stubbed
+ })
+
+ cy
+ .server({
+ method: 'POST',
+ delay: 1000,
+ status: 422,
+ response: {}
+ })
+
+ // any route commands will now inherit the above options
+ // from the server. anything we pass specifically
+ // to route will override the defaults though.
+ })
+
+ it('cy.request() - make an XHR request', function(){
+
+ // https://on.cypress.io/api/request
+ cy
+ .request('https://jsonplaceholder.typicode.com/comments').then(function(response){
+ expect(response.status).to.eq(200)
+ expect(response.body).to.have.length(500)
+ expect(response).to.have.property('headers')
+ expect(response).to.have.property('duration')
+ })
+ })
+
+ it('cy.route() - route responses to matching requests', function(){
+ var message = 'whoa, this comment doesn\'t exist'
+
+ cy.server()
+
+ // **** GET comments route ****
+ //
+ // https://on.cypress.io/api/route
+ cy
+ .route(/comments\/1/).as('getComment')
+
+ // we have code that fetches a comment when
+ // the button is clicked in scripts.js
+ .get('.network-btn').click()
+
+ // **** Wait ****
+ //
+ // Wait for a specific resource to resolve
+ // continuing to the next command
+ //
+ // https://on.cypress.io/api/wait
+ .wait('@getComment').its('status').should('eq', 200)
+
+ // **** POST comment route ****
+ //
+ // Specify the route to listen to method 'POST'
+ cy
+ .route('POST', '/comments').as('postComment')
+
+ // we have code that posts a comment when
+ // the button is clicked in scripts.js
+ .get('.network-post').click()
+ .wait('@postComment')
+
+ // get the route
+ .get('@postComment').then(function(xhr){
+ expect(xhr.requestBody).to.include('email')
+ expect(xhr.requestHeaders).to.have.property('Content-Type')
+ expect(xhr.responseBody).to.have.property('name', 'Using POST in cy.route()')
+ })
+
+ // **** Stubbed PUT comment route ****
+ //
+ cy
+ .route({
+ method: 'PUT',
+ url: /comments\/\d+/,
+ status: 404,
+ response: {error: message},
+ delay: 500
+ }).as('putComment')
+
+ // we have code that puts a comment when
+ // the button is clicked in scripts.js
+ .get('.network-put').click()
+
+ .wait('@putComment')
+
+ // our 404 statusCode logic in scripts.js executed
+ .get('.network-put-comment').should('contain', message)
+ })
+ })
+
+ context('Files', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/commands/files')
+ })
+ // **** Files ****
+ //
+ // Use files to represent data
+ // or read / write files in your project
+
+ it('cy.fixture() - load a fixture', function(){
+
+ // Instead of writing a response inline you can
+ // connect a response with a fixture file
+ // located in fixtures folder.
+
+ cy.server()
+
+ // https://on.cypress.io/api/fixture
+ cy
+ .fixture('example.json').as('comment')
+
+ .route(/comments/, '@comment').as('getComment')
+
+ // we have code that gets a comment when
+ // the button is clicked in scripts.js
+ .get('.fixture-btn').click()
+
+ .wait('@getComment').its('responseBody')
+ .should('have.property', 'name')
+ .and('include', 'Using fixtures to represent data')
+
+ // you can also just write the fixture in the route
+ cy
+ .route(/comments/, 'fixture:example.json').as('getComment')
+
+ // we have code that gets a comment when
+ // the button is clicked in scripts.js
+ .get('.fixture-btn').click()
+
+ .wait('@getComment').its('responseBody')
+ .should('have.property', 'name')
+ .and('include', 'Using fixtures to represent data')
+
+ // or write fx to represent fixture
+ // by default it assumes it's .json
+ cy
+ .route(/comments/, 'fx:example').as('getComment')
+
+ // we have code that gets a comment when
+ // the button is clicked in scripts.js
+ .get('.fixture-btn').click()
+
+ .wait('@getComment').its('responseBody')
+ .should('have.property', 'name')
+ .and('include', 'Using fixtures to represent data')
+ })
+
+ it('cy.readFile() - read a files contents', function(){
+
+ // You can read a file and returns its contents
+ // The filePath is relative to your project's root.
+
+ cy
+ // https://on.cypress.io/api/readfile
+ .readFile('app/commands/actions.html')
+ .then(function (html) {
+ expect(html).to.include('')
+ })
+
+ })
+
+ it('cy.writeFile() - write to a file', function(){
+
+ // You can write to a file with the specified contents
+ // If the path to the file does not exist, the file
+ // and it's path will be created.
+ // If the file already exists, it will be over-written.
+
+ cy
+ // Use a response from a request to automatically
+ // generate a fixture file for use later
+ .request('https://jsonplaceholder.typicode.com/users').then(function(response){
+ // https://on.cypress.io/api/writefile
+ cy.writeFile('cypress/fixtures/users.json', response.body)
+ })
+ .fixture('users').then(function(users){
+ expect(users[0].name).to.exist
+ })
+
+ cy
+ // JavaScript arrays and objects are stringified and formatted into text.
+ .writeFile('cypress/fixtures/profile.json', { id: 8739, name: 'Jane', email: 'jane@example.com'})
+ .fixture('profile').then(function(profile){
+ expect(profile.name).to.eq('Jane')
+ })
+
+ })
+
+ })
+
+ context('Local Storage', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/commands/local-storage')
+ })
+ // **** Local Storage ****
+ //
+ // Although local storage is automatically cleared
+ // to maintain a clean state in between tests
+ // sometimes we need to clear the local storage manually
+
+ it('cy.clearLocalStorage() - clear all data in local storage', function(){
+
+ // **** Clear all data in Local Storage ****
+ //
+ // https://on.cypress.io/api/clearlocalstorage
+ cy
+ .get(".ls-btn").click().then(function(){
+ expect(localStorage.getItem('prop1')).to.eq('red')
+ expect(localStorage.getItem('prop2')).to.eq('blue')
+ expect(localStorage.getItem('prop3')).to.eq('magenta')
+ })
+
+ // clearLocalStorage() returns the localStorage object
+ .clearLocalStorage().then(function(ls){
+ expect(ls.getItem('prop1')).to.be.null
+ expect(ls.getItem('prop2')).to.be.null
+ expect(ls.getItem('prop3')).to.be.null
+ })
+
+ // **** Clear key matching string in Local Storage ****
+ //
+ cy
+ .get(".ls-btn").click().then(function(){
+ expect(localStorage.getItem('prop1')).to.eq('red')
+ expect(localStorage.getItem('prop2')).to.eq('blue')
+ expect(localStorage.getItem('prop3')).to.eq('magenta')
+ })
+
+ .clearLocalStorage('prop1').then(function(ls){
+ expect(ls.getItem('prop1')).to.be.null
+ expect(ls.getItem('prop2')).to.eq('blue')
+ expect(ls.getItem('prop3')).to.eq('magenta')
+ })
+
+ // **** Clear key's matching regex in Local Storage ****
+ //
+ cy
+ .get(".ls-btn").click().then(function(){
+ expect(localStorage.getItem('prop1')).to.eq('red')
+ expect(localStorage.getItem('prop2')).to.eq('blue')
+ expect(localStorage.getItem('prop3')).to.eq('magenta')
+ })
+
+ .clearLocalStorage(/prop1|2/).then(function(ls){
+ expect(ls.getItem('prop1')).to.be.null
+ expect(ls.getItem('prop2')).to.be.null
+ expect(ls.getItem('prop3')).to.eq('magenta')
+ })
+ })
+ })
+
+ context('Cookies', function(){
+ beforeEach(function(){
+ Cypress.Cookies.debug(true)
+
+ cy.visit('https://example.cypress.io/commands/cookies')
+
+ // clear cookies again after visiting to remove
+ // any 3rd party cookies picked up such as cloudflare
+ .clearCookies()
+ })
+
+ it('cy.getCookie() - get a browser cookie', function(){
+
+ // **** Get a Cookie ****
+ //
+ // // https://on.cypress.io/api/getcookie
+ cy
+ .get('#getCookie .set-a-cookie').click()
+
+ // getCookie() returns a cookie object
+ .getCookie('token').should('have.property', 'value', '123ABC')
+ })
+
+ it('cy.getCookies() - get browser cookies', function(){
+
+ // **** Get all Cookies ****
+ //
+ // // https://on.cypress.io/api/getcookies
+ cy
+ .getCookies().should('be.empty')
+
+ .get('#getCookies .set-a-cookie').click()
+
+ // getCookies() returns an array of cookies
+ .getCookies().should('have.length', 1).then( function(cookies) {
+
+ // each cookie has these properties
+ expect(cookies[0]).to.have.property('name', 'token')
+ expect(cookies[0]).to.have.property('value', '123ABC')
+ expect(cookies[0]).to.have.property('httpOnly', false)
+ expect(cookies[0]).to.have.property('secure', false)
+ expect(cookies[0]).to.have.property('domain')
+ expect(cookies[0]).to.have.property('path')
+ })
+ })
+
+ it('cy.setCookie() - set a browser cookie', function(){
+
+ // **** Set a Cookie ****
+ //
+ // // https://on.cypress.io/api/setcookie
+ cy
+ .getCookies().should('be.empty')
+
+ .setCookie('foo', 'bar')
+
+ // getCookie() returns a cookie object
+ .getCookie('foo').should('have.property', 'value', 'bar')
+ })
+
+ it('cy.clearCookie() - clear a browser cookie', function(){
+
+ // **** Clear a Cookie ****
+ //
+ // // https://on.cypress.io/api/clearcookie
+ cy
+ .getCookie('token').should('be.null')
+
+ .get('#clearCookie .set-a-cookie').click()
+
+ .getCookie('token').should('have.property', 'value', '123ABC')
+
+ // clearCookies() returns null
+ .clearCookie('token').should('be.null')
+
+ .getCookie('token').should('be.null')
+ })
+
+ it('cy.clearCookies() - clear browser cookies', function(){
+
+ // **** Clear all Cookies ****
+ //
+ // https://on.cypress.io/api/clearcookies
+
+ cy
+ .getCookies().should('be.empty')
+
+ .get('#clearCookies .set-a-cookie').click()
+
+ .getCookies().should('have.length', 1)
+
+ // clearCookies() returns null
+ .clearCookies()
+
+ .getCookies().should('be.empty')
+ })
+
+ })
+
+ context('Utilities', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/utilities')
+ })
+
+ // **** Utilities ****
+ //
+ // Cypress offers some utilities commands
+ // that give you access to methods from other
+ // commonly used libraries
+
+ it('Cypress._.method() - call an underscore method', function(){
+
+ cy
+ // use the _.chain, _.pluck, _.first, and _.value functions
+ // https://on.cypress.io/api/cypress-underscore
+ .request('https://jsonplaceholder.typicode.com/users').then(function(response){
+ var _ = Cypress._
+ var ids = _.chain(response.body).pluck('id').first(3).value()
+
+ expect(ids).to.deep.eq([1, 2, 3])
+ })
+ })
+
+ it('Cypress.$(selector) - call a jQuery method', function(){
+
+ // https://on.cypress.io/api/cypress-jquery
+ var $li = Cypress.$('.utility-jquery li:first')
+
+ cy
+ .wrap($li)
+ .should('not.have.class', 'active')
+ .click()
+ .should('have.class', 'active')
+ })
+
+
+ it('Cypress.moment() - format or parse dates using a moment method', function(){
+
+ // use moment's format function
+ // https://on.cypress.io/api/cypress-moment
+ var time = Cypress.moment().utc('2014-04-25T19:38:53.196Z').format('h:mm A')
+
+ cy
+ .get('.utility-moment').contains('3:38 PM')
+ .should('have.class', 'badge')
+ })
+
+ it('Cypress.Blob.method() - blob utilties and base64 string conversion', function(){
+
+ // https://on.cypress.io/api/cypress-blob
+ // https://github.com/nolanlawson/blob-util#imgSrcToDataURL
+ // get the dataUrl string for the javascript-logo
+ return Cypress.Blob.imgSrcToDataURL('https://example.cypress.io/assets/img/javascript-logo.png', undefined, 'anonymous')
+ .then(function(dataUrl){
+ // create an element and set its src to the dataUrl
+ var img = Cypress.$(' ', {src: dataUrl})
+
+ // need to explicitly return cy here since we are initially returning
+ // the Cypress.Blog.imgSrcToDataURL promise to our test
+ return cy
+ .get('.utility-blob').then(function($div){
+ // append the image
+ $div.append(img)
+ })
+ .get('.utility-blob img').click().should('have.attr', 'src', dataUrl)
+ })
+ })
+
+ it('new Cypress.Promise(function) - instantiate a bluebird promise', function(){
+
+ // https://on.cypress.io/api/cypress-promise
+ var waited = false
+
+ function waitOneSecond(){
+ // return a promise that resolves after 1 second
+ return new Cypress.Promise(function(resolve, reject){
+ setTimeout(function(){
+ // set waited to true
+ waited = true
+
+ // resolve with 'foo' string
+ resolve('foo')
+ }, 1000)
+ })
+ }
+
+ cy
+ .then(function(){
+ // return a promise to cy.then() that
+ // is awaited until it resolves
+ return waitOneSecond().then(function(str){
+ expect(str).to.eq('foo')
+ expect(waited).to.be.true
+ })
+ })
+ })
+
+ })
+
+
+ context('Cypress.config()', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/cypress-api/config')
+ })
+
+ // **** Config ****
+ //
+
+ it('Cypress.config() - get and set configuration options', function(){
+
+ // https://on.cypress.io/api/config
+ var myConfig = Cypress.config()
+
+ expect(myConfig).to.have.property('animationDistanceThreshold', 5)
+ expect(myConfig).to.have.property('baseUrl', null)
+ expect(myConfig).to.have.property('defaultCommandTimeout', 4000)
+ expect(myConfig).to.have.property('requestTimeout', 5000)
+ expect(myConfig).to.have.property('responseTimeout', 30000)
+ expect(myConfig).to.have.property('viewportHeight', 660)
+ expect(myConfig).to.have.property('viewportWidth', 1000)
+ expect(myConfig).to.have.property('pageLoadTimeout', 60000)
+ expect(myConfig).to.have.property('waitForAnimations', true)
+
+ // *** get a single configuration option **
+ expect(Cypress.config('pageLoadTimeout')).to.eq(60000)
+
+ // *** set a single configuration option **
+ //
+ // this will change the config for the rest of your tests!
+ //
+ Cypress.config('pageLoadTimeout', 20000)
+
+ expect(Cypress.config('pageLoadTimeout')).to.eq(20000)
+
+ Cypress.config('pageLoadTimeout', 60000)
+ })
+ })
+
+ context('Cypress.env()', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/cypress-api/env')
+ })
+
+ // **** Env ****
+ //
+ // We can set environment variables for highly dynamic values
+ //
+ // https://on.cypress.io/guides/environment-variables
+
+ it('Cypress.env() - get the environment variables', function(){
+
+ // https://on.cypress.io/api/env
+ // set multiple environment variables
+ Cypress.env({
+ host: 'veronica.dev.local',
+ api_server: 'http://localhost:8888/api/v1/'
+ })
+
+ // get environment variable
+ expect(Cypress.env('host')).to.eq('veronica.dev.local')
+
+ // set environment variable
+ Cypress.env('api_server', 'http://localhost:8888/api/v2/')
+ expect(Cypress.env('api_server')).to.eq('http://localhost:8888/api/v2/')
+
+ // get all environment variable
+ expect(Cypress.env()).to.have.property('host', 'veronica.dev.local')
+ expect(Cypress.env()).to.have.property('api_server', 'http://localhost:8888/api/v2/')
+ })
+ })
+
+ context('Cypress.Cookies', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/cypress-api/cookies')
+ })
+
+ // **** Cookies ****
+ //
+ // Manage your app's cookies while testing
+ //
+ // https://on.cypress.io/api/cookies
+
+ it('Cypress.Cookies.debug() - enable or disable debugging', function(){
+
+ Cypress.Cookies.debug(true)
+
+ // Cypress will now log in the console when
+ // cookies are set or cleared
+ cy.setCookie('fakeCookie', '123ABC')
+ cy.clearCookie('fakeCookie')
+ cy.setCookie('fakeCookie', '123ABC')
+ cy.clearCookie('fakeCookie')
+ cy.setCookie('fakeCookie', '123ABC')
+ })
+
+ it('Cypress.Cookies.preserveOnce() - preserve cookies by key', function(){
+
+ // normally cookies are reset after each test
+ cy.getCookie('fakeCookie').should('not.be.ok')
+
+ // preserving a cookie will not clear it when
+ // the next test starts
+ cy.setCookie('lastCookie', '789XYZ')
+ Cypress.Cookies.preserveOnce('lastCookie')
+ })
+
+ it('Cypress.Cookies.defaults() - set defaults for all cookies', function(){
+
+ // now any cookie with the name 'session_id' will
+ // not be cleared before each new test runs
+ Cypress.Cookies.defaults({
+ whitelist: 'session_id'
+ })
+ })
+ })
+
+ context('Cypress.Dom', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/cypress-api/dom')
+ })
+
+ // **** Dom ****
+ //
+ // Cypress.Dom holds methods and logic related to DOM.
+ //
+ // https://on.cypress.io/api/dom
+
+ it('Cypress.Dom.isHidden() - determine if a DOM element is hidden', function(){
+
+ var hiddenP = Cypress.$('.dom-p p.hidden').get(0)
+ var visibleP = Cypress.$('.dom-p p.visible').get(0)
+
+ // our first paragraph has css class 'hidden'
+ expect(Cypress.Dom.isHidden(hiddenP)).to.be.true
+ expect(Cypress.Dom.isHidden(visibleP)).to.be.false
+ })
+ })
+
+ context('Cypress.Server', function(){
+ beforeEach(function(){
+ cy.visit('https://example.cypress.io/cypress-api/server')
+ })
+
+ // **** Server ****
+ //
+ // Permanently override server options for
+ // all instances of cy.server()
+ //
+ // https://on.cypress.io/api/api-server
+
+ it('Cypress.Server.defaults() - change default config of server', function(){
+ Cypress.Server.defaults({
+ delay: 0,
+ force404: false,
+ whitelist: function(xhr){
+ // handle custom logic for whitelisting
+ }
+ })
+ })
+ })
+})
diff --git a/client/cypress/examples/screenshots/Kitchen Sink -- Files -- cyreadFile - read a files contents.png b/client/cypress/examples/screenshots/Kitchen Sink -- Files -- cyreadFile - read a files contents.png
new file mode 100644
index 00000000..5dbde671
Binary files /dev/null and b/client/cypress/examples/screenshots/Kitchen Sink -- Files -- cyreadFile - read a files contents.png differ
diff --git a/client/cypress/examples/screenshots/Kitchen Sink -- Navigation -- cygo - go back or forward in the browsers history.png b/client/cypress/examples/screenshots/Kitchen Sink -- Navigation -- cygo - go back or forward in the browsers history.png
new file mode 100644
index 00000000..8188a6a9
Binary files /dev/null and b/client/cypress/examples/screenshots/Kitchen Sink -- Navigation -- cygo - go back or forward in the browsers history.png differ
diff --git a/client/cypress/examples/screenshots/my-image.png b/client/cypress/examples/screenshots/my-image.png
new file mode 100644
index 00000000..90913458
Binary files /dev/null and b/client/cypress/examples/screenshots/my-image.png differ
diff --git a/client/cypress/examples/support/commands.js b/client/cypress/examples/support/commands.js
new file mode 100644
index 00000000..cae33ce8
--- /dev/null
+++ b/client/cypress/examples/support/commands.js
@@ -0,0 +1,39 @@
+// ***********************************************
+// This example commands.js shows you how to
+// create the custom command: 'login'.
+//
+// The commands.js file is a great place to
+// modify existing commands and create custom
+// commands for use throughout your tests.
+//
+// You can read more about custom commands here:
+// https://on.cypress.io/api/commands
+// ***********************************************
+//
+// Cypress.addParentCommand("login", function(email, password){
+// var email = email || "joe@example.com"
+// var password = password || "foobar"
+//
+// var log = Cypress.Log.command({
+// name: "login",
+// message: [email, password],
+// consoleProps: function(){
+// return {
+// email: email,
+// password: password
+// }
+// }
+// })
+//
+// cy
+// .visit("/login", {log: false})
+// .contains("Log In", {log: false})
+// .get("#email", {log: false}).type(email, {log: false})
+// .get("#password", {log: false}).type(password, {log: false})
+// .get("button", {log: false}).click({log: false}) //this should submit the form
+// .get("h1", {log: false}).contains("Dashboard", {log: false}) //we should be on the dashboard now
+// .url({log: false}).should("match", /dashboard/, {log: false})
+// .then(function(){
+// log.snapshot().end()
+// })
+// })
\ No newline at end of file
diff --git a/client/cypress/examples/support/defaults.js b/client/cypress/examples/support/defaults.js
new file mode 100644
index 00000000..24d28fd2
--- /dev/null
+++ b/client/cypress/examples/support/defaults.js
@@ -0,0 +1,17 @@
+// ***********************************************
+// This example defaults.js shows you how to
+// customize the internal behavior of Cypress.
+//
+// The defaults.js file is a great place to
+// override defaults used throughout all tests.
+//
+// ***********************************************
+//
+// Cypress.Server.defaults({
+// delay: 500,
+// whitelist: function(xhr){}
+// })
+
+// Cypress.Cookies.defaults({
+// whitelist: ["session_id", "remember_token"]
+// })
\ No newline at end of file
diff --git a/client/cypress/examples/support/index.js b/client/cypress/examples/support/index.js
new file mode 100644
index 00000000..30c3e0a1
--- /dev/null
+++ b/client/cypress/examples/support/index.js
@@ -0,0 +1,23 @@
+// ***********************************************************
+// This example support/index.js is processed and
+// loaded automatically before your other 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/guides/configuration#section-global
+// ***********************************************************
+
+// Import commands.js and defaults.js
+// using ES2015 syntax:
+import "./commands"
+import "./defaults"
+
+// Alternatively you can use CommonJS syntax:
+// require("./commands")
+// require("./defaults")
diff --git a/client/cypress/integration/smoke_spec.js b/client/cypress/integration/smoke_spec.js
new file mode 100644
index 00000000..f743cd21
--- /dev/null
+++ b/client/cypress/integration/smoke_spec.js
@@ -0,0 +1,5 @@
+describe('tests run', () => {
+ it('should run', () => {
+ expect(true).to.be.true
+ })
+})
diff --git a/client/cypress/support/commands.js b/client/cypress/support/commands.js
new file mode 100644
index 00000000..4e9b3053
--- /dev/null
+++ b/client/cypress/support/commands.js
@@ -0,0 +1,40 @@
+/* eslint max-len:0 */
+// ***********************************************
+// This example commands.js shows you how to
+// create the custom command: 'login'.
+//
+// The commands.js file is a great place to
+// modify existing commands and create custom
+// commands for use throughout your tests.
+//
+// You can read more about custom commands here:
+// https://on.cypress.io/api/commands
+// ***********************************************
+//
+// Cypress.addParentCommand("login", function(email, password){
+// var email = email || "joe@example.com"
+// var password = password || "foobar"
+//
+// var log = Cypress.Log.command({
+// name: "login",
+// message: [email, password],
+// consoleProps: function(){
+// return {
+// email: email,
+// password: password
+// }
+// }
+// })
+//
+// cy
+// .visit("/login", {log: false})
+// .contains("Log In", {log: false})
+// .get("#email", {log: false}).type(email, {log: false})
+// .get("#password", {log: false}).type(password, {log: false})
+// .get("button", {log: false}).click({log: false}) //this should submit the form
+// .get("h1", {log: false}).contains("Dashboard", {log: false}) //we should be on the dashboard now
+// .url({log: false}).should("match", /dashboard/, {log: false})
+// .then(function(){
+// log.snapshot().end()
+// })
+// })
diff --git a/client/cypress/support/defaults.js b/client/cypress/support/defaults.js
new file mode 100644
index 00000000..7132e88c
--- /dev/null
+++ b/client/cypress/support/defaults.js
@@ -0,0 +1,16 @@
+// ***********************************************
+// This example defaults.js shows you how to
+// customize the internal behavior of Cypress.
+//
+// The defaults.js file is a great place to
+// override defaults used throughout all tests.
+//
+// ***********************************************
+//
+// Cypress.Server.defaults({
+// delay: 500,
+// whitelist: function(xhr){}
+// })
+// Cypress.Cookies.defaults({
+// whitelist: ["session_id", "remember_token"]
+// })
diff --git a/client/cypress/support/index.js b/client/cypress/support/index.js
new file mode 100644
index 00000000..bc372a37
--- /dev/null
+++ b/client/cypress/support/index.js
@@ -0,0 +1,22 @@
+// ***********************************************************
+// This example support/index.js is processed and
+// loaded automatically before your other 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/guides/configuration#section-global
+// ***********************************************************
+
+// Import commands.js and defaults.js
+// using ES2015 syntax:
+import './commands'
+import './defaults'
+// Alternatively you can use CommonJS syntax:
+// require("./commands")
+// require("./defaults")
diff --git a/client/package.json b/client/package.json
index ecafc613..5090aa17 100644
--- a/client/package.json
+++ b/client/package.json
@@ -6,6 +6,7 @@
"babel-jest": "^18.0.0",
"babel-preset-react-app": "^2.1.0",
"cross-env": "^3.1.4",
+ "cypress-cli": "^0.13.1",
"jest": "^18.1.0",
"react-scripts": "0.6.1",
"rimraf": "^2.5.4"
diff --git a/client/yarn.lock b/client/yarn.lock
index 0e502a89..8b5781b8 100644
--- a/client/yarn.lock
+++ b/client/yarn.lock
@@ -68,6 +68,12 @@ amdefine@>=0.0.4:
version "1.0.1"
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+ansi-align@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-1.1.0.tgz#2f0c1658829739add5ebb15e6b0c6e3423f016ba"
+ dependencies:
+ string-width "^1.0.1"
+
ansi-escapes@^1.1.0, ansi-escapes@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
@@ -305,14 +311,6 @@ babel-generator@^6.14.0, babel-generator@^6.18.0, babel-generator@^6.22.0:
lodash "^4.2.0"
source-map "^0.5.0"
-babel-helper-bindify-decorators@^6.22.0:
- version "6.22.0"
- resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.22.0.tgz#d7f5bc261275941ac62acfc4e20dacfb8a3fe952"
- dependencies:
- babel-runtime "^6.22.0"
- babel-traverse "^6.22.0"
- babel-types "^6.22.0"
-
babel-helper-builder-binary-assignment-operator-visitor@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.22.0.tgz#29df56be144d81bdeac08262bfa41d2c5e91cdcd"
@@ -321,7 +319,7 @@ babel-helper-builder-binary-assignment-operator-visitor@^6.22.0:
babel-runtime "^6.22.0"
babel-types "^6.22.0"
-babel-helper-builder-react-jsx@^6.22.0, babel-helper-builder-react-jsx@^6.23.0:
+babel-helper-builder-react-jsx@^6.22.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.23.0.tgz#d53fc8c996e0bc56d0de0fc4cc55a7138395ea4b"
dependencies:
@@ -356,16 +354,7 @@ babel-helper-explode-assignable-expression@^6.22.0:
babel-traverse "^6.22.0"
babel-types "^6.22.0"
-babel-helper-explode-class@^6.22.0:
- version "6.22.0"
- resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.22.0.tgz#646304924aa6388a516843ba7f1855ef8dfeb69b"
- dependencies:
- babel-helper-bindify-decorators "^6.22.0"
- babel-runtime "^6.22.0"
- babel-traverse "^6.22.0"
- babel-types "^6.22.0"
-
-babel-helper-function-name@^6.22.0, babel-helper-function-name@^6.23.0, babel-helper-function-name@^6.8.0:
+babel-helper-function-name@^6.22.0, babel-helper-function-name@^6.8.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.23.0.tgz#25742d67175c8903dbe4b6cb9d9e1fcb8dcf23a6"
dependencies:
@@ -504,22 +493,10 @@ babel-plugin-syntax-async-functions@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95"
-babel-plugin-syntax-async-generators@^6.5.0:
- version "6.13.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a"
-
babel-plugin-syntax-class-properties@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de"
-babel-plugin-syntax-decorators@^6.13.0:
- version "6.13.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b"
-
-babel-plugin-syntax-dynamic-import@^6.18.0:
- version "6.18.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da"
-
babel-plugin-syntax-exponentiation-operator@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de"
@@ -540,14 +517,6 @@ babel-plugin-syntax-trailing-function-commas@^6.13.0, babel-plugin-syntax-traili
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3"
-babel-plugin-transform-async-generator-functions@^6.22.0:
- version "6.22.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.22.0.tgz#a720a98153a7596f204099cd5409f4b3c05bab46"
- dependencies:
- babel-helper-remap-async-to-generator "^6.22.0"
- babel-plugin-syntax-async-generators "^6.5.0"
- babel-runtime "^6.22.0"
-
babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.8.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.22.0.tgz#194b6938ec195ad36efc4c33a971acf00d8cd35e"
@@ -573,25 +542,6 @@ babel-plugin-transform-class-properties@6.22.0:
babel-runtime "^6.22.0"
babel-template "^6.22.0"
-babel-plugin-transform-class-properties@^6.22.0:
- version "6.23.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.23.0.tgz#187b747ee404399013563c993db038f34754ac3b"
- dependencies:
- babel-helper-function-name "^6.23.0"
- babel-plugin-syntax-class-properties "^6.8.0"
- babel-runtime "^6.22.0"
- babel-template "^6.23.0"
-
-babel-plugin-transform-decorators@^6.22.0:
- version "6.22.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.22.0.tgz#c03635b27a23b23b7224f49232c237a73988d27c"
- dependencies:
- babel-helper-explode-class "^6.22.0"
- babel-plugin-syntax-decorators "^6.13.0"
- babel-runtime "^6.22.0"
- babel-template "^6.22.0"
- babel-types "^6.22.0"
-
babel-plugin-transform-es2015-arrow-functions@^6.22.0, babel-plugin-transform-es2015-arrow-functions@^6.3.13:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221"
@@ -789,13 +739,6 @@ babel-plugin-transform-object-rest-spread@6.8.0:
babel-plugin-syntax-object-rest-spread "^6.8.0"
babel-runtime "^6.0.0"
-babel-plugin-transform-object-rest-spread@^6.22.0:
- version "6.23.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.23.0.tgz#875d6bc9be761c58a2ae3feee5dc4895d8c7f921"
- dependencies:
- babel-plugin-syntax-object-rest-spread "^6.8.0"
- babel-runtime "^6.22.0"
-
babel-plugin-transform-react-constant-elements@6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-constant-elements/-/babel-plugin-transform-react-constant-elements-6.22.0.tgz#4af456f80d283e8be00f00f12852354defa08ee1"
@@ -808,7 +751,7 @@ babel-plugin-transform-react-constant-elements@6.9.1:
dependencies:
babel-runtime "^6.9.1"
-babel-plugin-transform-react-display-name@^6.22.0, babel-plugin-transform-react-display-name@^6.23.0, babel-plugin-transform-react-display-name@^6.3.13:
+babel-plugin-transform-react-display-name@^6.22.0, babel-plugin-transform-react-display-name@^6.3.13:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.23.0.tgz#4398910c358441dc4cef18787264d0412ed36b37"
dependencies:
@@ -842,7 +785,7 @@ babel-plugin-transform-react-jsx-source@6.9.0:
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.9.0"
-babel-plugin-transform-react-jsx@6.22.0:
+babel-plugin-transform-react-jsx@6.22.0, babel-plugin-transform-react-jsx@^6.22.0, babel-plugin-transform-react-jsx@^6.3.13:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.22.0.tgz#48556b7dd4c3fe97d1c943bcd54fc3f2561c1817"
dependencies:
@@ -850,14 +793,6 @@ babel-plugin-transform-react-jsx@6.22.0:
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.22.0"
-babel-plugin-transform-react-jsx@^6.22.0, babel-plugin-transform-react-jsx@^6.23.0, babel-plugin-transform-react-jsx@^6.3.13:
- version "6.23.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.23.0.tgz#23e892f7f2e759678eb5e4446a8f8e94e81b3470"
- dependencies:
- babel-helper-builder-react-jsx "^6.23.0"
- babel-plugin-syntax-jsx "^6.8.0"
- babel-runtime "^6.22.0"
-
babel-plugin-transform-regenerator@6.14.0:
version "6.14.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.14.0.tgz#119119b20c8b4283f6c77f0170d404c3c654bec8"
@@ -972,12 +907,6 @@ babel-preset-es2017@^6.14.0, babel-preset-es2017@^6.22.0:
babel-plugin-syntax-trailing-function-commas "^6.22.0"
babel-plugin-transform-async-to-generator "^6.22.0"
-babel-preset-flow@^6.23.0:
- version "6.23.0"
- resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d"
- dependencies:
- babel-plugin-transform-flow-strip-types "^6.22.0"
-
babel-preset-jest@^15.0.0:
version "15.0.0"
resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-15.0.0.tgz#f23988f1f918673ff9b470fdfd60fcc19bc618f5"
@@ -998,7 +927,7 @@ babel-preset-latest@6.14.0:
babel-preset-es2016 "^6.11.3"
babel-preset-es2017 "^6.14.0"
-babel-preset-latest@6.22.0, babel-preset-latest@^6.22.0:
+babel-preset-latest@6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-preset-latest/-/babel-preset-latest-6.22.0.tgz#47b800531350a3dc69126e8c375a40655cd1eeff"
dependencies:
@@ -1063,36 +992,6 @@ babel-preset-react@6.22.0:
babel-plugin-transform-react-jsx-self "^6.22.0"
babel-plugin-transform-react-jsx-source "^6.22.0"
-babel-preset-react@^6.23.0:
- version "6.23.0"
- resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.23.0.tgz#eb7cee4de98a3f94502c28565332da9819455195"
- dependencies:
- babel-plugin-syntax-jsx "^6.3.13"
- babel-plugin-transform-react-display-name "^6.23.0"
- babel-plugin-transform-react-jsx "^6.23.0"
- babel-plugin-transform-react-jsx-self "^6.22.0"
- babel-plugin-transform-react-jsx-source "^6.22.0"
- babel-preset-flow "^6.23.0"
-
-babel-preset-stage-2@^6.22.0:
- version "6.22.0"
- resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.22.0.tgz#ccd565f19c245cade394b21216df704a73b27c07"
- dependencies:
- babel-plugin-syntax-dynamic-import "^6.18.0"
- babel-plugin-transform-class-properties "^6.22.0"
- babel-plugin-transform-decorators "^6.22.0"
- babel-preset-stage-3 "^6.22.0"
-
-babel-preset-stage-3@^6.22.0:
- version "6.22.0"
- resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.22.0.tgz#a4e92bbace7456fafdf651d7a7657ee0bbca9c2e"
- dependencies:
- babel-plugin-syntax-trailing-function-commas "^6.22.0"
- babel-plugin-transform-async-generator-functions "^6.22.0"
- babel-plugin-transform-async-to-generator "^6.22.0"
- babel-plugin-transform-exponentiation-operator "^6.22.0"
- babel-plugin-transform-object-rest-spread "^6.22.0"
-
babel-register@^6.14.0, babel-register@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.22.0.tgz#a61dd83975f9ca4a9e7d6eff3059494cd5ea4c63"
@@ -1105,21 +1004,21 @@ babel-register@^6.14.0, babel-register@^6.22.0:
mkdirp "^0.5.1"
source-map-support "^0.4.2"
-babel-runtime@6.11.6, babel-runtime@^6.9.1:
+babel-runtime@6.11.6:
version "6.11.6"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.11.6.tgz#6db707fef2d49c49bfa3cb64efdb436b518b8222"
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.9.5"
-babel-runtime@6.22.0, babel-runtime@^6.0.0, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.9.0:
+babel-runtime@6.22.0, babel-runtime@^6.0.0, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.9.0, babel-runtime@^6.9.1:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.22.0.tgz#1cf8b4ac67c77a4ddb0db2ae1f74de52ac4ca611"
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.10.0"
-babel-template@^6.14.0:
+babel-template@^6.14.0, babel-template@^6.16.0, babel-template@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.22.0.tgz#403d110905a4626b317a2a1fcb8f3b73204b2edb"
dependencies:
@@ -1129,7 +1028,7 @@ babel-template@^6.14.0:
babylon "^6.11.0"
lodash "^4.2.0"
-babel-template@^6.16.0, babel-template@^6.22.0, babel-template@^6.23.0:
+babel-template@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638"
dependencies:
@@ -1221,6 +1120,10 @@ block-stream@*:
dependencies:
inherits "~2.0.0"
+bluebird@3.3.4:
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.3.4.tgz#f780fe43e1a7a6510f67abd7d0d79533a40ddde6"
+
bluebird@^3.4.1:
version "3.4.7"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3"
@@ -1235,6 +1138,20 @@ boom@2.x.x:
dependencies:
hoek "2.x.x"
+boxen@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/boxen/-/boxen-0.6.0.tgz#8364d4248ac34ff0ef1b2f2bf49a6c60ce0d81b6"
+ dependencies:
+ ansi-align "^1.1.0"
+ camelcase "^2.1.0"
+ chalk "^1.1.1"
+ cli-boxes "^1.0.0"
+ filled-array "^1.0.0"
+ object-assign "^4.0.1"
+ repeating "^2.0.0"
+ string-width "^1.0.1"
+ widest-line "^1.0.0"
+
brace-expansion@^1.0.0:
version "1.1.6"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
@@ -1281,6 +1198,10 @@ bser@1.0.2:
dependencies:
node-int64 "^0.4.0"
+buffer-crc32@~0.2.3:
+ version "0.2.13"
+ resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
+
buffer-shims@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51"
@@ -1326,6 +1247,10 @@ camelcase@^1.0.2:
version "1.2.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+camelcase@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
+
camelcase@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
@@ -1343,6 +1268,10 @@ caniuse-db@^1.0.30000346, caniuse-db@^1.0.30000525, caniuse-db@^1.0.30000527, ca
version "1.0.30000622"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000622.tgz#9d9690b577384990a58e33ebb903a14da735e5fd"
+capture-stack-trace@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d"
+
cardinal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9"
@@ -1434,6 +1363,10 @@ clean-css@3.4.x:
commander "2.8.x"
source-map "0.4.x"
+cli-boxes@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
+
cli-cursor@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
@@ -1491,6 +1424,10 @@ code-point-at@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+coffee-script@^1.9.3:
+ version "1.12.3"
+ resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.3.tgz#de5f4b1b934a4e9f915c57acd7ad323f68f715db"
+
color-convert@^1.3.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
@@ -1543,7 +1480,7 @@ commander@2.8.x, commander@~2.8.1:
dependencies:
graceful-readlink ">= 1.0.0"
-commander@2.9.x, commander@^2.9.0:
+commander@2.9.x, commander@^2.8.1, commander@^2.9.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
dependencies:
@@ -1578,13 +1515,27 @@ concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
-concat-stream@^1.4.6:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7"
+concat-stream@1.5.0, concat-stream@^1.4.6:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611"
dependencies:
- inherits "^2.0.3"
- readable-stream "^2.2.2"
- typedarray "^0.0.6"
+ inherits "~2.0.1"
+ readable-stream "~2.0.0"
+ typedarray "~0.0.5"
+
+configstore@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1"
+ dependencies:
+ dot-prop "^3.0.0"
+ graceful-fs "^4.1.2"
+ mkdirp "^0.5.0"
+ object-assign "^4.0.1"
+ os-tmpdir "^1.0.0"
+ osenv "^0.1.0"
+ uuid "^2.0.1"
+ write-file-atomic "^1.1.2"
+ xdg-basedir "^2.0.0"
connect-history-api-fallback@1.3.0, connect-history-api-fallback@^1.3.0:
version "1.3.0"
@@ -1655,6 +1606,12 @@ core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+create-error-class@^3.0.1:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
+ dependencies:
+ capture-stack-trace "^1.0.0"
+
cross-env@^3.1.4:
version "3.1.4"
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-3.1.4.tgz#56e8bca96f17908a6eb1bc2012ca126f92842130"
@@ -1789,6 +1746,27 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
dependencies:
cssom "0.3.x"
+cypress-cli@^0.13.1:
+ version "0.13.1"
+ resolved "https://registry.yarnpkg.com/cypress-cli/-/cypress-cli-0.13.1.tgz#239371ae7bec161eb12ae2b4c999fd685d38e752"
+ dependencies:
+ bluebird "3.3.4"
+ chalk "^1.1.0"
+ coffee-script "^1.9.3"
+ commander "^2.8.1"
+ extract-zip "1.5.0"
+ fs-extra "^0.22.1"
+ home-or-tmp "^2.0.0"
+ human-interval "^0.1.5"
+ lodash "^3.10.0"
+ progress "^1.1.8"
+ request "^2.60.0"
+ request-progress "^0.3.1"
+ through2 "^2.0.0"
+ update-notifier "^1.0.3"
+ xvfb cypress-io/node-xvfb
+ yauzl "^2.4.1"
+
d@^0.1.1, d@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309"
@@ -1809,6 +1787,10 @@ date-now@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
+debug@0.7.4:
+ version "0.7.4"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39"
+
debug@^2.1.0, debug@^2.1.1, debug@^2.2.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b"
@@ -1952,10 +1934,22 @@ dot-case@^2.1.0:
dependencies:
no-case "^2.2.0"
+dot-prop@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177"
+ dependencies:
+ is-obj "^1.0.0"
+
dotenv@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-2.0.0.tgz#bd759c357aaa70365e01c96b7b0bec08a6e0d949"
+duplexer2@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
+ dependencies:
+ readable-stream "^2.0.2"
+
duplexer@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
@@ -2328,6 +2322,15 @@ extract-text-webpack-plugin@1.0.1:
loader-utils "^0.2.3"
webpack-sources "^0.1.0"
+extract-zip@1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.5.0.tgz#92ccf6d81ef70a9fa4c1747114ccef6d8688a6c4"
+ dependencies:
+ concat-stream "1.5.0"
+ debug "0.7.4"
+ mkdirp "0.5.0"
+ yauzl "2.4.1"
+
extsprintf@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
@@ -2370,6 +2373,12 @@ fbjs@^0.8.1, fbjs@^0.8.4:
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"
+fd-slicer@~1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65"
+ dependencies:
+ pend "~1.2.0"
+
figures@^1.3.5:
version "1.7.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
@@ -2415,6 +2424,10 @@ fill-range@^2.1.0:
repeat-element "^1.1.2"
repeat-string "^1.5.2"
+filled-array@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/filled-array/-/filled-array-1.1.0.tgz#c3c4f6c663b923459a9aa29912d2d031f1507f84"
+
finalhandler@0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.1.tgz#2c400d8d4530935bc232549c5fa385ec07de6fcd"
@@ -2505,6 +2518,14 @@ fs-extra@0.30.0:
path-is-absolute "^1.0.0"
rimraf "^2.2.8"
+fs-extra@^0.22.1:
+ version "0.22.1"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.22.1.tgz#5fd6f8049dc976ca19eb2355d658173cabcce056"
+ dependencies:
+ graceful-fs "^4.1.2"
+ jsonfile "^2.1.0"
+ rimraf "^2.2.8"
+
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@@ -2619,7 +2640,27 @@ globby@^5.0.0:
pify "^2.0.0"
pinkie-promise "^2.0.0"
-graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
+got@^5.0.0:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/got/-/got-5.7.1.tgz#5f81635a61e4a6589f180569ea4e381680a51f35"
+ dependencies:
+ create-error-class "^3.0.1"
+ duplexer2 "^0.1.4"
+ is-redirect "^1.0.0"
+ is-retry-allowed "^1.0.0"
+ is-stream "^1.0.0"
+ lowercase-keys "^1.0.0"
+ node-status-codes "^1.0.0"
+ object-assign "^4.0.1"
+ parse-json "^2.1.0"
+ pinkie-promise "^2.0.0"
+ read-all-stream "^3.0.0"
+ readable-stream "^2.0.5"
+ timed-out "^3.0.0"
+ unzip-response "^1.0.2"
+ url-parse-lax "^1.0.0"
+
+graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
@@ -2823,6 +2864,10 @@ https-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.0.tgz#b3ffdfe734b2a3d4a9efd58e8654c91fce86eafd"
+human-interval@^0.1.5:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/human-interval/-/human-interval-0.1.6.tgz#0057973454764c3abcbeb2aed612fc9644e68488"
+
iconv-lite@0.4.13:
version "0.4.13"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
@@ -2862,7 +2907,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
-inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1:
+inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
@@ -2995,12 +3040,20 @@ is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4:
jsonpointer "^4.0.0"
xtend "^4.0.0"
+is-npm@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
+
is-number@^2.0.2, is-number@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
dependencies:
kind-of "^3.0.2"
+is-obj@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
+
is-path-cwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
@@ -3033,13 +3086,21 @@ is-property@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
+is-redirect@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
+
is-resolvable@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62"
dependencies:
tryit "^1.0.1"
-is-stream@^1.0.1:
+is-retry-allowed@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34"
+
+is-stream@^1.0.0, is-stream@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
@@ -3670,10 +3731,20 @@ klaw@^1.0.0:
optionalDependencies:
graceful-fs "^4.1.9"
+latest-version@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-2.0.0.tgz#56f8d6139620847b8017f8f1f4d78e211324168b"
+ dependencies:
+ package-json "^2.0.0"
+
lazy-cache@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+lazy-req@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/lazy-req/-/lazy-req-1.1.0.tgz#bdaebead30f8d824039ce0ce149d4daa07ba1fac"
+
lcid@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
@@ -3836,6 +3907,10 @@ lodash.words@^3.0.0:
dependencies:
lodash._root "^3.0.0"
+lodash@^3.10.0:
+ version "3.10.1"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
+
lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.14.2, lodash@^4.15.0, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
@@ -3860,6 +3935,10 @@ lower-case@^1.1.0, lower-case@^1.1.1, lower-case@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.3.tgz#c92393d976793eee5ba4edb583cf8eae35bd9bfb"
+lowercase-keys@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306"
+
lru-cache@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e"
@@ -3985,6 +4064,12 @@ minimist@^1.1.1, minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+mkdirp@0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12"
+ dependencies:
+ minimist "0.0.8"
+
mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
@@ -4107,6 +4192,10 @@ node-pre-gyp@^0.6.29:
tar "~2.2.1"
tar-pack "~3.3.0"
+node-status-codes@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/node-status-codes/-/node-status-codes-1.0.0.tgz#5ae5541d024645d32a58fcddc9ceecea7ae3ac2f"
+
nopt@3.x, nopt@~3.0.6:
version "3.0.6"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
@@ -4260,10 +4349,26 @@ os-locale@^1.4.0:
dependencies:
lcid "^1.0.0"
-os-tmpdir@^1.0.1:
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+osenv@^0.1.0:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
+ dependencies:
+ os-homedir "^1.0.0"
+ os-tmpdir "^1.0.0"
+
+package-json@^2.0.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/package-json/-/package-json-2.4.0.tgz#0d15bd67d1cbbddbb2ca222ff2edb86bcb31a8bb"
+ dependencies:
+ got "^5.0.0"
+ registry-auth-token "^3.0.1"
+ registry-url "^3.0.3"
+ semver "^5.1.0"
+
pako@~0.2.0:
version "0.2.9"
resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
@@ -4283,7 +4388,7 @@ parse-glob@^3.0.4:
is-extglob "^1.0.0"
is-glob "^2.0.0"
-parse-json@^2.2.0:
+parse-json@^2.1.0, parse-json@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
dependencies:
@@ -4352,6 +4457,10 @@ pbkdf2-compat@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz#b6e0c8fa99494d94e0511575802a59a5c142f288"
+pend@~1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
+
pify@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
@@ -4631,7 +4740,7 @@ prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
-prepend-http@^1.0.0:
+prepend-http@^1.0.0, prepend-http@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
@@ -4749,7 +4858,7 @@ range-parser@^1.0.3, range-parser@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
-rc@~1.1.6:
+rc@^1.0.1, rc@^1.1.6, rc@~1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9"
dependencies:
@@ -4855,6 +4964,13 @@ react@^15.3.2:
loose-envify "^1.1.0"
object-assign "^4.1.0"
+read-all-stream@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa"
+ dependencies:
+ pinkie-promise "^2.0.0"
+ readable-stream "^2.0.0"
+
read-pkg-up@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
@@ -4888,7 +5004,7 @@ readable-stream@^1.0.27-1, readable-stream@^1.1.13:
isarray "0.0.1"
string_decoder "~0.10.x"
-"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.2.2:
+readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.5:
version "2.2.2"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e"
dependencies:
@@ -4900,6 +5016,17 @@ readable-stream@^1.0.27-1, readable-stream@^1.1.13:
string_decoder "~0.10.x"
util-deprecate "~1.0.1"
+readable-stream@~2.0.0:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.1"
+ isarray "~1.0.0"
+ process-nextick-args "~1.0.6"
+ string_decoder "~0.10.x"
+ util-deprecate "~1.0.1"
+
readable-stream@~2.1.4:
version "2.1.5"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0"
@@ -5013,6 +5140,18 @@ regexpu-core@^2.0.0:
regjsgen "^0.2.0"
regjsparser "^0.1.4"
+registry-auth-token@^3.0.1:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.1.0.tgz#997c08256e0c7999837b90e944db39d8a790276b"
+ dependencies:
+ rc "^1.1.6"
+
+registry-url@^3.0.3:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
+ dependencies:
+ rc "^1.0.1"
+
regjsgen@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
@@ -5051,7 +5190,13 @@ repeating@^2.0.0:
dependencies:
is-finite "^1.0.0"
-request@^2.79.0:
+request-progress@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-0.3.1.tgz#0721c105d8a96ac6b2ce8b2c89ae2d5ecfcf6b3a"
+ dependencies:
+ throttleit "~0.0.2"
+
+request@^2.60.0, request@^2.79.0:
version "2.79.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de"
dependencies:
@@ -5159,7 +5304,13 @@ sax@^1.2.1, sax@~1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
-"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0, semver@~5.3.0:
+semver-diff@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
+ dependencies:
+ semver "^5.0.3"
+
+"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
@@ -5253,6 +5404,10 @@ slice-ansi@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
+slide@^1.1.5:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"
+
snake-case@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-2.1.0.tgz#41bdb1b73f30ec66a04d4e2cad1b76387d4d6d9f"
@@ -5544,10 +5699,25 @@ throat@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/throat/-/throat-3.0.0.tgz#e7c64c867cbb3845f10877642f7b60055b8ec0d6"
+throttleit@~0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf"
+
+through2@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
+ dependencies:
+ readable-stream "^2.1.5"
+ xtend "~4.0.1"
+
through@^2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+timed-out@^3.0.0:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-3.1.3.tgz#95860bfcc5c76c277f8f8326fd0f5b2e20eba217"
+
timers-browserify@^1.0.1:
version "1.4.2"
resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d"
@@ -5612,7 +5782,7 @@ type-is@~1.6.14:
media-typer "0.3.0"
mime-types "~2.1.13"
-typedarray@^0.0.6:
+typedarray@~0.0.5:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
@@ -5655,6 +5825,23 @@ unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+unzip-response@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe"
+
+update-notifier@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-1.0.3.tgz#8f92c515482bd6831b7c93013e70f87552c7cf5a"
+ dependencies:
+ boxen "^0.6.0"
+ chalk "^1.0.0"
+ configstore "^2.0.0"
+ is-npm "^1.0.0"
+ latest-version "^2.0.0"
+ lazy-req "^1.1.0"
+ semver-diff "^2.0.0"
+ xdg-basedir "^2.0.0"
+
upper-case-first@^1.1.0, upper-case-first@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-1.1.2.tgz#5d79bedcff14419518fd2edb0a0507c9b6859115"
@@ -5672,6 +5859,12 @@ url-loader@0.5.7:
loader-utils "0.2.x"
mime "1.2.x"
+url-parse-lax@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
+ dependencies:
+ prepend-http "^1.0.1"
+
url-parse@1.0.x:
version "1.0.5"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.0.5.tgz#0854860422afdcfefeb6c965c662d4800169927b"
@@ -5721,7 +5914,7 @@ utils-merge@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8"
-uuid@^2.0.2:
+uuid@^2.0.1, uuid@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
@@ -5902,6 +6095,12 @@ wide-align@^1.1.0:
dependencies:
string-width "^1.0.1"
+widest-line@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-1.0.0.tgz#0c09c85c2a94683d0d7eaf8ee097d564bf0e105c"
+ dependencies:
+ string-width "^1.0.1"
+
window-size@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
@@ -5940,12 +6139,26 @@ wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+write-file-atomic@^1.1.2:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a"
+ dependencies:
+ graceful-fs "^4.1.11"
+ imurmurhash "^0.1.4"
+ slide "^1.1.5"
+
write@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
dependencies:
mkdirp "^0.5.1"
+xdg-basedir@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2"
+ dependencies:
+ os-homedir "^1.0.0"
+
xml-char-classes@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d"
@@ -5954,10 +6167,14 @@ xml-name-validator@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
-"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0:
+"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+xvfb@cypress-io/node-xvfb:
+ version "0.3.0"
+ resolved "https://codeload.github.com/cypress-io/node-xvfb/tar.gz/22e3783c31d81ebe64d8c0df491ea00cdc74726a"
+
y18n@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
@@ -6024,3 +6241,16 @@ yargs@~3.10.0:
cliui "^2.1.0"
decamelize "^1.0.0"
window-size "0.1.0"
+
+yauzl@2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005"
+ dependencies:
+ fd-slicer "~1.0.1"
+
+yauzl@^2.4.1:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.7.0.tgz#e21d847868b496fc29eaec23ee87fdd33e9b2bce"
+ dependencies:
+ buffer-crc32 "~0.2.3"
+ fd-slicer "~1.0.1"
diff --git a/package-scripts.js b/package-scripts.js
index 582e8469..2ef38658 100644
--- a/package-scripts.js
+++ b/package-scripts.js
@@ -20,6 +20,10 @@ const concurrentTests = {
script: 'nps client.test',
color: 'bgYellow.bold.dim',
},
+ 'e2e-tests': {
+ script: 'nps e2e',
+ color: 'bgGreen.bold.dim',
+ },
}
module.exports = {
@@ -54,6 +58,10 @@ module.exports = {
description: 'run the client tests',
},
},
+ e2e: {
+ script: series(['cd client', 'cypress run']),
+ description: 'run the E2E tests',
+ },
test: {
description: 'run the tests in parallel',
script: concurrent(concurrentTests),