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 <span> inside the button, + // but the <button> 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 <select> 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('<!DOCTYPE html>') + }) + + }) + + 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 <img> element and set its src to the dataUrl + var img = Cypress.$('<img />', {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),