From 080106320570c167dd7624619aca34ae115c974d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment?= <cpartiot@gmail.com> Date: Mon, 6 Jan 2020 17:18:32 +0100 Subject: [PATCH] update: add cypress --- .gitlab-ci.yml | 34 +++ cypress.json | 4 + cypress/examples/actions.spec.js | 281 ++++++++++++++++++ cypress/examples/aliasing.spec.js | 42 +++ cypress/examples/assertions.spec.js | 168 +++++++++++ cypress/examples/connectors.spec.js | 97 ++++++ cypress/examples/cookies.spec.js | 78 +++++ cypress/examples/cypress_api.spec.js | 222 ++++++++++++++ cypress/examples/files.spec.js | 114 +++++++ cypress/examples/local_storage.spec.js | 52 ++++ cypress/examples/location.spec.js | 32 ++ cypress/examples/misc.spec.js | 83 ++++++ cypress/examples/navigation.spec.js | 56 ++++ cypress/examples/network_requests.spec.js | 195 ++++++++++++ cypress/examples/querying.spec.js | 114 +++++++ cypress/examples/spies_stubs_clocks.spec.js | 95 ++++++ cypress/examples/traversal.spec.js | 121 ++++++++ cypress/examples/utilities.spec.js | 133 +++++++++ cypress/examples/viewport.spec.js | 59 ++++ cypress/examples/waiting.spec.js | 34 +++ cypress/examples/window.spec.js | 22 ++ cypress/fixtures/example.json | 5 + cypress/fixtures/profile.json | 5 + cypress/fixtures/users.json | 232 +++++++++++++++ cypress/integration/test.spec.js | 22 ++ cypress/plugins/index.js | 17 ++ ...as detected outside of a test (failed).png | Bin 0 -> 39693 bytes cypress/support/commands.js | 25 ++ cypress/support/index.js | 20 ++ cypress/videos/test.spec.js.mp4 | Bin 0 -> 28361 bytes package.json | 32 +- 31 files changed, 2384 insertions(+), 10 deletions(-) create mode 100644 .gitlab-ci.yml create mode 100644 cypress.json create mode 100644 cypress/examples/actions.spec.js create mode 100644 cypress/examples/aliasing.spec.js create mode 100644 cypress/examples/assertions.spec.js create mode 100644 cypress/examples/connectors.spec.js create mode 100644 cypress/examples/cookies.spec.js create mode 100644 cypress/examples/cypress_api.spec.js create mode 100644 cypress/examples/files.spec.js create mode 100644 cypress/examples/local_storage.spec.js create mode 100644 cypress/examples/location.spec.js create mode 100644 cypress/examples/misc.spec.js create mode 100644 cypress/examples/navigation.spec.js create mode 100644 cypress/examples/network_requests.spec.js create mode 100644 cypress/examples/querying.spec.js create mode 100644 cypress/examples/spies_stubs_clocks.spec.js create mode 100644 cypress/examples/traversal.spec.js create mode 100644 cypress/examples/utilities.spec.js create mode 100644 cypress/examples/viewport.spec.js create mode 100644 cypress/examples/waiting.spec.js create mode 100644 cypress/examples/window.spec.js create mode 100644 cypress/fixtures/example.json create mode 100644 cypress/fixtures/profile.json create mode 100644 cypress/fixtures/users.json create mode 100644 cypress/integration/test.spec.js create mode 100644 cypress/plugins/index.js create mode 100644 cypress/screenshots/test.spec.js/An uncaught error was detected outside of a test (failed).png create mode 100644 cypress/support/commands.js create mode 100644 cypress/support/index.js create mode 100644 cypress/videos/test.spec.js.mp4 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..f6b96fc8 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,34 @@ +--- +image: node + +variables: + npm_config_cache: "$CI_PROJECT_DIR/.npm" + CYPRESS_CACHE_FOLDER: "$CI_PROJECT_DIR/cache/Cypress" + +cache: + key: ${CI_COMMIT_REF_SLUG} + paths: + - .npm + - cache/Cypress + +stages: + - test + - release + +test: + image: cypress/base:10 + stage: test + before_script: + - npm ci + - npm run watch & + - npm run serve & + - npx wait-on http://127.0.0.1:9000 + script: + - npm test + except: + - tags + artifacts: + paths: + - cypress/videos + - cypress/screenshots + expire_in: 1 day diff --git a/cypress.json b/cypress.json new file mode 100644 index 00000000..3c58cbd1 --- /dev/null +++ b/cypress.json @@ -0,0 +1,4 @@ +{ + "baseUrl": "http://0.0.0.0:9000", + "defaultCommandTimeout": 8000 +} \ No newline at end of file diff --git a/cypress/examples/actions.spec.js b/cypress/examples/actions.spec.js new file mode 100644 index 00000000..8923d99d --- /dev/null +++ b/cypress/examples/actions.spec.js @@ -0,0 +1,281 @@ +/// <reference types="Cypress" /> + +context('Actions', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/actions') + }) + + // https://on.cypress.io/interacting-with-elements + + it('.type() - type into a DOM element', () => { + // https://on.cypress.io/type + cy.get('.action-email') + .type('fake@email.com').should('have.value', 'fake@email.com') + + // .type() with special character sequences + .type('{leftarrow}{rightarrow}{uparrow}{downarrow}') + .type('{del}{selectall}{backspace}') + + // .type() with key modifiers + .type('{alt}{option}') //these are equivalent + .type('{ctrl}{control}') //these are equivalent + .type('{meta}{command}{cmd}') //these are equivalent + .type('{shift}') + + // Delay each keypress by 0.1 sec + .type('slow.typing@email.com', { delay: 100 }) + .should('have.value', 'slow.typing@email.com') + + cy.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('.focus() - focus on a DOM element', () => { + // https://on.cypress.io/focus + cy.get('.action-focus').focus() + .should('have.class', 'focus') + .prev().should('have.attr', 'style', 'color: orange;') + }) + + it('.blur() - blur off a DOM element', () => { + // https://on.cypress.io/blur + cy.get('.action-blur').type('About to blur').blur() + .should('have.class', 'error') + .prev().should('have.attr', 'style', 'color: red;') + }) + + it('.clear() - clears an input or textarea element', () => { + // https://on.cypress.io/clear + cy.get('.action-clear').type('Clear this text') + .should('have.value', 'Clear this text') + .clear() + .should('have.value', '') + }) + + it('.submit() - submit a form', () => { + // https://on.cypress.io/submit + cy.get('.action-form') + .find('[type="text"]').type('HALFOFF') + cy.get('.action-form').submit() + .next().should('contain', 'Your form has been submitted!') + }) + + it('.click() - click on a DOM element', () => { + // https://on.cypress.io/click + cy.get('.action-btn').click() + + // You can click on 9 specific positions of an element: + // ----------------------------------- + // | topLeft top topRight | + // | | + // | | + // | | + // | left center right | + // | | + // | | + // | | + // | bottomLeft bottom bottomRight | + // ----------------------------------- + + // clicking in the center of the element is the default + cy.get('#action-canvas').click() + + cy.get('#action-canvas').click('topLeft') + cy.get('#action-canvas').click('top') + cy.get('#action-canvas').click('topRight') + cy.get('#action-canvas').click('left') + cy.get('#action-canvas').click('right') + cy.get('#action-canvas').click('bottomLeft') + cy.get('#action-canvas').click('bottom') + cy.get('#action-canvas').click('bottomRight') + + // .click() accepts an x and y coordinate + // that controls where the click occurs :) + + cy.get('#action-canvas') + .click(80, 75) // click 80px on x coord and 75px on y coord + .click(170, 75) + .click(80, 165) + .click(100, 185) + .click(125, 190) + .click(150, 185) + .click(170, 165) + + // click multiple elements by passing multiple: true + cy.get('.action-labels>.label').click({ multiple: true }) + + // Ignore error checking prior to clicking + cy.get('.action-opacity>.btn').click({ force: true }) + }) + + it('.dblclick() - double click on a DOM element', () => { + // https://on.cypress.io/dblclick + + // Our app has a listener on 'dblclick' event in our 'scripts.js' + // that hides the div and shows an input on double click + cy.get('.action-div').dblclick().should('not.be.visible') + cy.get('.action-input-hidden').should('be.visible') + }) + + it('.rightclick() - right click on a DOM element', () => { + // https://on.cypress.io/rightclick + + // Our app has a listener on 'contextmenu' event in our 'scripts.js' + // that hides the div and shows an input on right click + cy.get('.rightclick-action-div').rightclick().should('not.be.visible') + cy.get('.rightclick-action-input-hidden').should('be.visible') + }) + + it('.check() - check a checkbox or radio element', () => { + // https://on.cypress.io/check + + // By default, .check() will check all + // matching checkbox or radio elements in succession, one after another + cy.get('.action-checkboxes [type="checkbox"]').not('[disabled]') + .check().should('be.checked') + + cy.get('.action-radios [type="radio"]').not('[disabled]') + .check().should('be.checked') + + // .check() accepts a value argument + cy.get('.action-radios [type="radio"]') + .check('radio1').should('be.checked') + + // .check() accepts an array of values + cy.get('.action-multiple-checkboxes [type="checkbox"]') + .check(['checkbox1', 'checkbox2']).should('be.checked') + + // Ignore error checking prior to checking + cy.get('.action-checkboxes [disabled]') + .check({ force: true }).should('be.checked') + + cy.get('.action-radios [type="radio"]') + .check('radio3', { force: true }).should('be.checked') + }) + + it('.uncheck() - uncheck a checkbox element', () => { + // https://on.cypress.io/uncheck + + // By default, .uncheck() will uncheck all matching + // checkbox elements in succession, one after another + cy.get('.action-check [type="checkbox"]') + .not('[disabled]') + .uncheck().should('not.be.checked') + + // .uncheck() accepts a value argument + cy.get('.action-check [type="checkbox"]') + .check('checkbox1') + .uncheck('checkbox1').should('not.be.checked') + + // .uncheck() accepts an array of values + cy.get('.action-check [type="checkbox"]') + .check(['checkbox1', 'checkbox3']) + .uncheck(['checkbox1', 'checkbox3']).should('not.be.checked') + + // Ignore error checking prior to unchecking + cy.get('.action-check [disabled]') + .uncheck({ force: true }).should('not.be.checked') + }) + + it('.select() - select an option in a <select> element', () => { + // https://on.cypress.io/select + + // Select option(s) with matching text content + cy.get('.action-select').select('apples') + + cy.get('.action-select-multiple') + .select(['apples', 'oranges', 'bananas']) + + // Select option(s) with matching value + cy.get('.action-select').select('fr-bananas') + + cy.get('.action-select-multiple') + .select(['fr-apples', 'fr-oranges', 'fr-bananas']) + }) + + it('.scrollIntoView() - scroll an element into view', () => { + // https://on.cypress.io/scrollintoview + + // normally all of these buttons are hidden, + // because they're not within + // the viewable area of their parent + // (we need to scroll to see them) + cy.get('#scroll-horizontal button') + .should('not.be.visible') + + // scroll the button into view, as if the user had scrolled + cy.get('#scroll-horizontal button').scrollIntoView() + .should('be.visible') + + cy.get('#scroll-vertical button') + .should('not.be.visible') + + // Cypress handles the scroll direction needed + cy.get('#scroll-vertical button').scrollIntoView() + .should('be.visible') + + cy.get('#scroll-both button') + .should('not.be.visible') + + // Cypress knows to scroll to the right and down + cy.get('#scroll-both button').scrollIntoView() + .should('be.visible') + }) + + it('.trigger() - trigger an event on a DOM element', () => { + // https://on.cypress.io/trigger + + // To interact with a range input (slider) + // we need to set its value & trigger the + // event to signal it changed + + // Here, we invoke jQuery's val() method to set + // the value and trigger the 'change' event + cy.get('.trigger-input-range') + .invoke('val', 25) + .trigger('change') + .get('input[type=range]').siblings('p') + .should('have.text', '25') + }) + + it('cy.scrollTo() - scroll the window or element to a position', () => { + + // https://on.cypress.io/scrollTo + + // You can scroll to 9 specific positions of an element: + // ----------------------------------- + // | topLeft top topRight | + // | | + // | | + // | | + // | left center right | + // | | + // | | + // | | + // | bottomLeft bottom bottomRight | + // ----------------------------------- + + // if you chain .scrollTo() off of cy, we will + // scroll the entire window + cy.scrollTo('bottom') + + cy.get('#scrollable-horizontal').scrollTo('right') + + // or you can scroll to a specific coordinate: + // (x axis, y axis) in pixels + cy.get('#scrollable-vertical').scrollTo(250, 250) + + // or you can scroll to a specific percentage + // of the (width, height) of the element + cy.get('#scrollable-both').scrollTo('75%', '25%') + + // control the easing of the scroll (default is 'swing') + cy.get('#scrollable-vertical').scrollTo('center', { easing: 'linear' }) + + // control the duration of the scroll (in ms) + cy.get('#scrollable-both').scrollTo('center', { duration: 2000 }) + }) +}) diff --git a/cypress/examples/aliasing.spec.js b/cypress/examples/aliasing.spec.js new file mode 100644 index 00000000..95bac735 --- /dev/null +++ b/cypress/examples/aliasing.spec.js @@ -0,0 +1,42 @@ +/// <reference types="Cypress" /> + +context('Aliasing', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/aliasing') + }) + + it('.as() - alias a DOM element for later use', () => { + // https://on.cypress.io/as + + // Alias a DOM element for use later + // We don't have to traverse to the element + // later in our code, we reference it with @ + + cy.get('.as-table').find('tbody>tr') + .first().find('td').first() + .find('button').as('firstBtn') + + // when we reference the alias, we place an + // @ in front of its name + cy.get('@firstBtn').click() + + cy.get('@firstBtn') + .should('have.class', 'btn-success') + .and('contain', 'Changed') + }) + + it('.as() - alias a route for later use', () => { + + // Alias the route to wait for its response + cy.server() + cy.route('GET', 'comments/*').as('getComment') + + // we have code that gets a comment when + // the button is clicked in scripts.js + cy.get('.network-btn').click() + + // https://on.cypress.io/wait + cy.wait('@getComment').its('status').should('eq', 200) + + }) +}) diff --git a/cypress/examples/assertions.spec.js b/cypress/examples/assertions.spec.js new file mode 100644 index 00000000..791383b6 --- /dev/null +++ b/cypress/examples/assertions.spec.js @@ -0,0 +1,168 @@ +/// <reference types="Cypress" /> + +context('Assertions', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/assertions') + }) + + describe('Implicit Assertions', () => { + it('.should() - make an assertion about the current subject', () => { + // https://on.cypress.io/should + cy.get('.assertion-table') + .find('tbody tr:last') + .should('have.class', 'success') + .find('td') + .first() + // checking the text of the <td> element in various ways + .should('have.text', 'Column content') + .should('contain', 'Column content') + .should('have.html', 'Column content') + // chai-jquery uses "is()" to check if element matches selector + .should('match', 'td') + // to match text content against a regular expression + // first need to invoke jQuery method text() + // and then match using regular expression + .invoke('text') + .should('match', /column content/i) + + // a better way to check element's text content against a regular expression + // is to use "cy.contains" + // https://on.cypress.io/contains + cy.get('.assertion-table') + .find('tbody tr:last') + // finds first <td> element with text content matching regular expression + .contains('td', /column content/i) + .should('be.visible') + + // for more information about asserting element's text + // see https://on.cypress.io/using-cypress-faq#How-do-I-get-an-element’s-text-contents + }) + + it('.and() - chain multiple assertions together', () => { + // https://on.cypress.io/and + cy.get('.assertions-link') + .should('have.class', 'active') + .and('have.attr', 'href') + .and('include', 'cypress.io') + }) + }) + + describe('Explicit Assertions', () => { + // https://on.cypress.io/assertions + it('expect - make an assertion about a specified subject', () => { + // We can use Chai's BDD style assertions + expect(true).to.be.true + const o = { foo: 'bar' } + + expect(o).to.equal(o) + expect(o).to.deep.equal({ foo: 'bar' }) + // matching text using regular expression + expect('FooBar').to.match(/bar$/i) + }) + + it('pass your own callback function to should()', () => { + // Pass a function to should that can have any number + // of explicit assertions within it. + // The ".should(cb)" function will be retried + // automatically until it passes all your explicit assertions or times out. + cy.get('.assertions-p') + .find('p') + .should(($p) => { + // https://on.cypress.io/$ + // return an array of texts from all of the p's + // @ts-ignore TS6133 unused variable + const texts = $p.map((i, el) => Cypress.$(el).text()) + + // jquery map returns jquery object + // and .get() convert this to simple array + const paragraphs = texts.get() + + // array should have length of 3 + expect(paragraphs, 'has 3 paragraphs').to.have.length(3) + + // use second argument to expect(...) to provide clear + // message with each assertion + expect(paragraphs, 'has expected text in each paragraph').to.deep.eq([ + 'Some text from first p', + 'More text from second p', + 'And even more text from third p', + ]) + }) + }) + + it('finds element by class name regex', () => { + cy.get('.docs-header') + .find('div') + // .should(cb) callback function will be retried + .should(($div) => { + expect($div).to.have.length(1) + + const className = $div[0].className + + expect(className).to.match(/heading-/) + }) + // .then(cb) callback is not retried, + // it either passes or fails + .then(($div) => { + expect($div, 'text content').to.have.text('Introduction') + }) + }) + + it('can throw any error', () => { + cy.get('.docs-header') + .find('div') + .should(($div) => { + if ($div.length !== 1) { + // you can throw your own errors + throw new Error('Did not find 1 element') + } + + const className = $div[0].className + + if (!className.match(/heading-/)) { + throw new Error(`Could not find class "heading-" in ${className}`) + } + }) + }) + + it('matches unknown text between two elements', () => { + /** + * Text from the first element. + * @type {string} + */ + let text + + /** + * Normalizes passed text, + * useful before comparing text with spaces and different capitalization. + * @param {string} s Text to normalize + */ + const normalizeText = (s) => s.replace(/\s/g, '').toLowerCase() + + cy.get('.two-elements') + .find('.first') + .then(($first) => { + // save text from the first element + text = normalizeText($first.text()) + }) + + cy.get('.two-elements') + .find('.second') + .should(($div) => { + // we can massage text before comparing + const secondText = normalizeText($div.text()) + + expect(secondText, 'second text').to.equal(text) + }) + }) + + it('assert - assert shape of an object', () => { + const person = { + name: 'Joe', + age: 20, + } + + assert.isObject(person, 'value is object') + }) + }) +}) diff --git a/cypress/examples/connectors.spec.js b/cypress/examples/connectors.spec.js new file mode 100644 index 00000000..d871d774 --- /dev/null +++ b/cypress/examples/connectors.spec.js @@ -0,0 +1,97 @@ +/// <reference types="Cypress" /> + +context('Connectors', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/connectors') + }) + + it('.each() - iterate over an array of elements', () => { + // https://on.cypress.io/each + cy.get('.connectors-each-ul>li') + .each(($el, index, $list) => { + console.log($el, index, $list) + }) + }) + + it('.its() - get properties on the current subject', () => { + // https://on.cypress.io/its + cy.get('.connectors-its-ul>li') + // calls the 'length' property yielding that value + .its('length') + .should('be.gt', 2) + }) + + it('.invoke() - invoke a function on the current subject', () => { + // our div is hidden in our script.js + // $('.connectors-div').hide() + + // https://on.cypress.io/invoke + cy.get('.connectors-div').should('be.hidden') + // call the jquery method 'show' on the 'div.container' + .invoke('show') + .should('be.visible') + }) + + it('.spread() - spread an array as individual args to callback function', () => { + // https://on.cypress.io/spread + const arr = ['foo', 'bar', 'baz'] + + cy.wrap(arr).spread((foo, bar, baz) => { + expect(foo).to.eq('foo') + expect(bar).to.eq('bar') + expect(baz).to.eq('baz') + }) + }) + + describe('.then()', () => { + it('invokes a callback function with the current subject', () => { + // https://on.cypress.io/then + cy.get('.connectors-list > li') + .then(($lis) => { + expect($lis, '3 items').to.have.length(3) + expect($lis.eq(0), 'first item').to.contain('Walk the dog') + expect($lis.eq(1), 'second item').to.contain('Feed the cat') + expect($lis.eq(2), 'third item').to.contain('Write JavaScript') + }) + }) + + it('yields the returned value to the next command', () => { + cy.wrap(1) + .then((num) => { + expect(num).to.equal(1) + + return 2 + }) + .then((num) => { + expect(num).to.equal(2) + }) + }) + + it('yields the original subject without return', () => { + cy.wrap(1) + .then((num) => { + expect(num).to.equal(1) + // note that nothing is returned from this callback + }) + .then((num) => { + // this callback receives the original unchanged value 1 + expect(num).to.equal(1) + }) + + it('yields the value yielded by the last Cypress command inside', () => { + cy.wrap(1) + .then((num) => { + expect(num).to.equal(1) + // note how we run a Cypress command + // the result yielded by this Cypress command + // will be passed to the second ".then" + cy.wrap(2) + }) + .then((num) => { + // this callback receives the value yielded by "cy.wrap(2)" + expect(num).to.equal(2) + }) + }) + }) + }) +}) diff --git a/cypress/examples/cookies.spec.js b/cypress/examples/cookies.spec.js new file mode 100644 index 00000000..bb540e95 --- /dev/null +++ b/cypress/examples/cookies.spec.js @@ -0,0 +1,78 @@ +/// <reference types="Cypress" /> + +context('Cookies', () => { + beforeEach(() => { + 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 + cy.clearCookies() + }) + + it('cy.getCookie() - get a browser cookie', () => { + // https://on.cypress.io/getcookie + cy.get('#getCookie .set-a-cookie').click() + + // cy.getCookie() yields a cookie object + cy.getCookie('token').should('have.property', 'value', '123ABC') + }) + + it('cy.getCookies() - get browser cookies', () => { + // https://on.cypress.io/getcookies + cy.getCookies().should('be.empty') + + cy.get('#getCookies .set-a-cookie').click() + + // cy.getCookies() yields an array of cookies + cy.getCookies().should('have.length', 1).should((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', () => { + // https://on.cypress.io/setcookie + cy.getCookies().should('be.empty') + + cy.setCookie('foo', 'bar') + + // cy.getCookie() yields a cookie object + cy.getCookie('foo').should('have.property', 'value', 'bar') + }) + + it('cy.clearCookie() - clear a browser cookie', () => { + // https://on.cypress.io/clearcookie + cy.getCookie('token').should('be.null') + + cy.get('#clearCookie .set-a-cookie').click() + + cy.getCookie('token').should('have.property', 'value', '123ABC') + + // cy.clearCookies() yields null + cy.clearCookie('token').should('be.null') + + cy.getCookie('token').should('be.null') + }) + + it('cy.clearCookies() - clear browser cookies', () => { + // https://on.cypress.io/clearcookies + cy.getCookies().should('be.empty') + + cy.get('#clearCookies .set-a-cookie').click() + + cy.getCookies().should('have.length', 1) + + // cy.clearCookies() yields null + cy.clearCookies() + + cy.getCookies().should('be.empty') + }) +}) diff --git a/cypress/examples/cypress_api.spec.js b/cypress/examples/cypress_api.spec.js new file mode 100644 index 00000000..0e46520c --- /dev/null +++ b/cypress/examples/cypress_api.spec.js @@ -0,0 +1,222 @@ +/// <reference types="Cypress" /> + +context('Cypress.Commands', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/cypress-api') + }) + + // https://on.cypress.io/custom-commands + + it('.add() - create a custom command', () => { + Cypress.Commands.add('console', { + prevSubject: true, + }, (subject, method) => { + // the previous subject is automatically received + // and the commands arguments are shifted + + // allow us to change the console method used + method = method || 'log' + + // log the subject to the console + // @ts-ignore TS7017 + console[method]('The subject is', subject) + + // whatever we return becomes the new subject + // we don't want to change the subject so + // we return whatever was passed in + return subject + }) + + // @ts-ignore TS2339 + cy.get('button').console('info').then(($button) => { + // subject is still $button + }) + }) +}) + + +context('Cypress.Cookies', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/cypress-api') + }) + + // https://on.cypress.io/cookies + it('.debug() - enable or disable debugging', () => { + 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('.preserveOnce() - preserve cookies by key', () => { + // 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('.defaults() - set defaults for all cookies', () => { + // 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.Server', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/cypress-api') + }) + + // Permanently override server options for + // all instances of cy.server() + + // https://on.cypress.io/cypress-server + it('.defaults() - change default config of server', () => { + Cypress.Server.defaults({ + delay: 0, + force404: false, + }) + }) +}) + +context('Cypress.arch', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/cypress-api') + }) + + it('Get CPU architecture name of underlying OS', () => { + // https://on.cypress.io/arch + expect(Cypress.arch).to.exist + }) +}) + +context('Cypress.config()', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/cypress-api') + }) + + it('Get and set configuration options', () => { + // https://on.cypress.io/config + let 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) + + expect(Cypress.config('pageLoadTimeout')).to.eq(60000) + + // 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.dom', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/cypress-api') + }) + + // https://on.cypress.io/dom + it('.isHidden() - determine if a DOM element is hidden', () => { + let hiddenP = Cypress.$('.dom-p p.hidden').get(0) + let 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.env()', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/cypress-api') + }) + + // We can set environment variables for highly dynamic values + + // https://on.cypress.io/environment-variables + it('Get environment variables', () => { + // https://on.cypress.io/env + // set multiple environment variables + Cypress.env({ + host: 'veronica.dev.local', + api_server: 'http://localhost:8888/v1/', + }) + + // get environment variable + expect(Cypress.env('host')).to.eq('veronica.dev.local') + + // set environment variable + Cypress.env('api_server', 'http://localhost:8888/v2/') + expect(Cypress.env('api_server')).to.eq('http://localhost:8888/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/v2/') + }) +}) + +context('Cypress.log', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/cypress-api') + }) + + it('Control what is printed to the Command Log', () => { + // https://on.cypress.io/cypress-log + }) +}) + + +context('Cypress.platform', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/cypress-api') + }) + + it('Get underlying OS name', () => { + // https://on.cypress.io/platform + expect(Cypress.platform).to.be.exist + }) +}) + +context('Cypress.version', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/cypress-api') + }) + + it('Get current version of Cypress being run', () => { + // https://on.cypress.io/version + expect(Cypress.version).to.be.exist + }) +}) + +context('Cypress.spec', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/cypress-api') + }) + + it('Get current spec information', () => { + // https://on.cypress.io/spec + // wrap the object so we can inspect it easily by clicking in the command log + cy.wrap(Cypress.spec).should('have.keys', ['name', 'relative', 'absolute']) + }) +}) diff --git a/cypress/examples/files.spec.js b/cypress/examples/files.spec.js new file mode 100644 index 00000000..c1a9ab2f --- /dev/null +++ b/cypress/examples/files.spec.js @@ -0,0 +1,114 @@ +/// <reference types="Cypress" /> + +/// JSON fixture file can be loaded directly using +// the built-in JavaScript bundler +// @ts-ignore +const requiredExample = require('../../fixtures/example') + +context('Files', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/files') + }) + + beforeEach(() => { + // load example.json fixture file and store + // in the test context object + cy.fixture('example.json').as('example') + }) + + it('cy.fixture() - load a fixture', () => { + // https://on.cypress.io/fixture + + // Instead of writing a response inline you can + // use a fixture file's content. + + cy.server() + cy.fixture('example.json').as('comment') + // when application makes an Ajax request matching "GET comments/*" + // Cypress will intercept it and reply with object + // from the "comment" alias + cy.route('GET', 'comments/*', '@comment').as('getComment') + + // we have code that gets a comment when + // the button is clicked in scripts.js + cy.get('.fixture-btn').click() + + cy.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('GET', 'comments/*', 'fixture:example.json').as('getComment') + + // we have code that gets a comment when + // the button is clicked in scripts.js + cy.get('.fixture-btn').click() + + cy.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('GET', 'comments/*', 'fx:example').as('getComment') + + // we have code that gets a comment when + // the button is clicked in scripts.js + cy.get('.fixture-btn').click() + + cy.wait('@getComment').its('responseBody') + .should('have.property', 'name') + .and('include', 'Using fixtures to represent data') + }) + + it('cy.fixture() or require - load a fixture', function () { + // we are inside the "function () { ... }" + // callback and can use test context object "this" + // "this.example" was loaded in "beforeEach" function callback + expect(this.example, 'fixture in the test context') + .to.deep.equal(requiredExample) + + // or use "cy.wrap" and "should('deep.equal', ...)" assertion + // @ts-ignore + cy.wrap(this.example, 'fixture vs require') + .should('deep.equal', requiredExample) + }) + + it('cy.readFile() - read a files contents', () => { + // https://on.cypress.io/readfile + + // You can read a file and yield its contents + // The filePath is relative to your project's root. + cy.readFile('cypress.json').then((json) => { + expect(json).to.be.an('object') + }) + }) + + it('cy.writeFile() - write to a file', () => { + // https://on.cypress.io/writefile + + // You can write to a file + + // Use a response from a request to automatically + // generate a fixture file for use later + cy.request('https://jsonplaceholder.cypress.io/users') + .then((response) => { + cy.writeFile('cypress/fixtures/users.json', response.body) + }) + cy.fixture('users').should((users) => { + expect(users[0].name).to.exist + }) + + // JavaScript arrays and objects are stringified + // and formatted into text. + cy.writeFile('cypress/fixtures/profile.json', { + id: 8739, + name: 'Jane', + email: 'jane@example.com', + }) + + cy.fixture('profile').should((profile) => { + expect(profile.name).to.eq('Jane') + }) + }) +}) diff --git a/cypress/examples/local_storage.spec.js b/cypress/examples/local_storage.spec.js new file mode 100644 index 00000000..076b096f --- /dev/null +++ b/cypress/examples/local_storage.spec.js @@ -0,0 +1,52 @@ +/// <reference types="Cypress" /> + +context('Local Storage', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/local-storage') + }) + // Although local storage is automatically cleared + // in between tests to maintain a clean state + // sometimes we need to clear the local storage manually + + it('cy.clearLocalStorage() - clear all data in local storage', () => { + // https://on.cypress.io/clearlocalstorage + cy.get('.ls-btn').click().should(() => { + expect(localStorage.getItem('prop1')).to.eq('red') + expect(localStorage.getItem('prop2')).to.eq('blue') + expect(localStorage.getItem('prop3')).to.eq('magenta') + }) + + // clearLocalStorage() yields the localStorage object + cy.clearLocalStorage().should((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().should(() => { + expect(localStorage.getItem('prop1')).to.eq('red') + expect(localStorage.getItem('prop2')).to.eq('blue') + expect(localStorage.getItem('prop3')).to.eq('magenta') + }) + + cy.clearLocalStorage('prop1').should((ls) => { + expect(ls.getItem('prop1')).to.be.null + expect(ls.getItem('prop2')).to.eq('blue') + expect(ls.getItem('prop3')).to.eq('magenta') + }) + + // Clear keys matching regex in Local Storage + cy.get('.ls-btn').click().should(() => { + expect(localStorage.getItem('prop1')).to.eq('red') + expect(localStorage.getItem('prop2')).to.eq('blue') + expect(localStorage.getItem('prop3')).to.eq('magenta') + }) + + cy.clearLocalStorage(/prop1|2/).should((ls) => { + expect(ls.getItem('prop1')).to.be.null + expect(ls.getItem('prop2')).to.be.null + expect(ls.getItem('prop3')).to.eq('magenta') + }) + }) +}) diff --git a/cypress/examples/location.spec.js b/cypress/examples/location.spec.js new file mode 100644 index 00000000..68e755c1 --- /dev/null +++ b/cypress/examples/location.spec.js @@ -0,0 +1,32 @@ +/// <reference types="Cypress" /> + +context('Location', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/location') + }) + + it('cy.hash() - get the current URL hash', () => { + // https://on.cypress.io/hash + cy.hash().should('be.empty') + }) + + it('cy.location() - get window.location', () => { + // https://on.cypress.io/location + cy.location().should((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', () => { + // https://on.cypress.io/url + cy.url().should('eq', 'https://example.cypress.io/commands/location') + }) +}) diff --git a/cypress/examples/misc.spec.js b/cypress/examples/misc.spec.js new file mode 100644 index 00000000..97edd8be --- /dev/null +++ b/cypress/examples/misc.spec.js @@ -0,0 +1,83 @@ +/// <reference types="Cypress" /> + +context('Misc', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/misc') + }) + + it('.end() - end the command chain', () => { + // https://on.cypress.io/end + + // cy.end is useful when you want to end a chain of commands + // and force Cypress to re-query from the root element + cy.get('.misc-table').within(() => { + // ends the current chain and yields null + cy.contains('Cheryl').click().end() + + // queries the entire table again + cy.contains('Charles').click() + }) + }) + + it('cy.exec() - execute a system command', () => { + // https://on.cypress.io/exec + + // execute a system command. + // so you can take actions necessary for + // your test outside the scope of Cypress. + cy.exec('echo Jane Lane') + .its('stdout').should('contain', 'Jane Lane') + + // we can use Cypress.platform string to + // select appropriate command + // https://on.cypress/io/platform + cy.log(`Platform ${Cypress.platform} architecture ${Cypress.arch}`) + + if (Cypress.platform === 'win32') { + cy.exec('print cypress.json') + .its('stderr').should('be.empty') + } else { + cy.exec('cat cypress.json') + .its('stderr').should('be.empty') + + cy.exec('pwd') + .its('code').should('eq', 0) + } + }) + + it('cy.focused() - get the DOM element that has focus', () => { + // https://on.cypress.io/focused + cy.get('.misc-form').find('#name').click() + cy.focused().should('have.id', 'name') + + cy.get('.misc-form').find('#description').click() + cy.focused().should('have.id', 'description') + }) + + context('Cypress.Screenshot', function () { + it('cy.screenshot() - take a screenshot', () => { + // https://on.cypress.io/screenshot + cy.screenshot('my-image') + }) + + it('Cypress.Screenshot.defaults() - change default config of screenshots', function () { + Cypress.Screenshot.defaults({ + blackout: ['.foo'], + capture: 'viewport', + clip: { x: 0, y: 0, width: 200, height: 200 }, + scale: false, + disableTimersAndAnimations: true, + screenshotOnRunFailure: true, + beforeScreenshot () { }, + afterScreenshot () { }, + }) + }) + }) + + it('cy.wrap() - wrap an object', () => { + // https://on.cypress.io/wrap + cy.wrap({ foo: 'bar' }) + .should('have.property', 'foo') + .and('include', 'bar') + }) +}) diff --git a/cypress/examples/navigation.spec.js b/cypress/examples/navigation.spec.js new file mode 100644 index 00000000..bbd9d479 --- /dev/null +++ b/cypress/examples/navigation.spec.js @@ -0,0 +1,56 @@ +/// <reference types="Cypress" /> + +context('Navigation', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io') + cy.get('.navbar-nav').contains('Commands').click() + cy.get('.dropdown-menu').contains('Navigation').click() + }) + + it('cy.go() - go back or forward in the browser\'s history', () => { + // https://on.cypress.io/go + + cy.location('pathname').should('include', 'navigation') + + cy.go('back') + cy.location('pathname').should('not.include', 'navigation') + + cy.go('forward') + cy.location('pathname').should('include', 'navigation') + + // clicking back + cy.go(-1) + cy.location('pathname').should('not.include', 'navigation') + + // clicking forward + cy.go(1) + cy.location('pathname').should('include', 'navigation') + }) + + it('cy.reload() - reload the page', () => { + // https://on.cypress.io/reload + cy.reload() + + // reload the page without using the cache + cy.reload(true) + }) + + it('cy.visit() - visit a remote url', () => { + // https://on.cypress.io/visit + + // Visit any sub-domain of your current domain + + // Pass options to the visit + cy.visit('https://example.cypress.io/commands/navigation', { + timeout: 50000, // increase total time for the visit to resolve + onBeforeLoad (contentWindow) { + // contentWindow is the remote page's window object + expect(typeof contentWindow === 'object').to.be.true + }, + onLoad (contentWindow) { + // contentWindow is the remote page's window object + expect(typeof contentWindow === 'object').to.be.true + }, + }) + }) +}) diff --git a/cypress/examples/network_requests.spec.js b/cypress/examples/network_requests.spec.js new file mode 100644 index 00000000..ca4b404b --- /dev/null +++ b/cypress/examples/network_requests.spec.js @@ -0,0 +1,195 @@ +/// <reference types="Cypress" /> + +context('Network Requests', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/network-requests') + }) + + // Manage AJAX / XHR requests in your app + + it('cy.server() - control behavior of network requests and responses', () => { + // https://on.cypress.io/server + + cy.server().should((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 + + // pass false to disable existing route stubs + expect(server.enable).to.be.true + // forces requests that don't match your routes to 404 + expect(server.force404).to.be.false + // whitelists requests from ever being logged or stubbed + expect(server.whitelist).to.be.a('function') + }) + + 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', () => { + // https://on.cypress.io/request + cy.request('https://jsonplaceholder.cypress.io/comments') + .should((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.request() - verify response using BDD syntax', () => { + cy.request('https://jsonplaceholder.cypress.io/comments') + .then((response) => { + // https://on.cypress.io/assertions + expect(response).property('status').to.equal(200) + expect(response).property('body').to.have.length(500) + expect(response).to.include.keys('headers', 'duration') + }) + }) + + it('cy.request() with query parameters', () => { + // will execute request + // https://jsonplaceholder.cypress.io/comments?postId=1&id=3 + cy.request({ + url: 'https://jsonplaceholder.cypress.io/comments', + qs: { + postId: 1, + id: 3, + }, + }) + .its('body') + .should('be.an', 'array') + .and('have.length', 1) + .its('0') // yields first element of the array + .should('contain', { + postId: 1, + id: 3, + }) + }) + + it('cy.request() - pass result to the second request', () => { + // first, let's find out the userId of the first user we have + cy.request('https://jsonplaceholder.cypress.io/users?_limit=1') + .its('body') // yields the response object + .its('0') // yields the first element of the returned list + // the above two commands its('body').its('0') + // can be written as its('body.0') + // if you do not care about TypeScript checks + .then((user) => { + expect(user).property('id').to.be.a('number') + // make a new post on behalf of the user + cy.request('POST', 'https://jsonplaceholder.cypress.io/posts', { + userId: user.id, + title: 'Cypress Test Runner', + body: 'Fast, easy and reliable testing for anything that runs in a browser.', + }) + }) + // note that the value here is the returned value of the 2nd request + // which is the new post object + .then((response) => { + expect(response).property('status').to.equal(201) // new entity created + expect(response).property('body').to.contain({ + id: 101, // there are already 100 posts, so new entity gets id 101 + title: 'Cypress Test Runner', + }) + // we don't know the user id here - since it was in above closure + // so in this test just confirm that the property is there + expect(response.body).property('userId').to.be.a('number') + }) + }) + + it('cy.request() - save response in the shared test context', () => { + // https://on.cypress.io/variables-and-aliases + cy.request('https://jsonplaceholder.cypress.io/users?_limit=1') + .its('body').its('0') // yields the first element of the returned list + .as('user') // saves the object in the test context + .then(function () { + // NOTE 👀 + // By the time this callback runs the "as('user')" command + // has saved the user object in the test context. + // To access the test context we need to use + // the "function () { ... }" callback form, + // otherwise "this" points at a wrong or undefined object! + cy.request('POST', 'https://jsonplaceholder.cypress.io/posts', { + userId: this.user.id, + title: 'Cypress Test Runner', + body: 'Fast, easy and reliable testing for anything that runs in a browser.', + }) + .its('body').as('post') // save the new post from the response + }) + .then(function () { + // When this callback runs, both "cy.request" API commands have finished + // and the test context has "user" and "post" objects set. + // Let's verify them. + expect(this.post, 'post has the right user id').property('userId').to.equal(this.user.id) + }) + }) + + it('cy.route() - route responses to matching requests', () => { + // https://on.cypress.io/route + + let message = 'whoa, this comment does not exist' + + cy.server() + + // Listen to GET to comments/1 + cy.route('GET', 'comments/*').as('getComment') + + // we have code that gets a comment when + // the button is clicked in scripts.js + cy.get('.network-btn').click() + + // https://on.cypress.io/wait + cy.wait('@getComment').its('status').should('eq', 200) + + // Listen to POST to comments + cy.route('POST', '/comments').as('postComment') + + // we have code that posts a comment when + // the button is clicked in scripts.js + cy.get('.network-post').click() + cy.wait('@postComment').should((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()') + }) + + // Stub a response to PUT comments/ **** + cy.route({ + method: 'PUT', + url: 'comments/*', + status: 404, + response: { error: message }, + delay: 500, + }).as('putComment') + + // we have code that puts a comment when + // the button is clicked in scripts.js + cy.get('.network-put').click() + + cy.wait('@putComment') + + // our 404 statusCode logic in scripts.js executed + cy.get('.network-put-comment').should('contain', message) + }) +}) diff --git a/cypress/examples/querying.spec.js b/cypress/examples/querying.spec.js new file mode 100644 index 00000000..e3f7c9b6 --- /dev/null +++ b/cypress/examples/querying.spec.js @@ -0,0 +1,114 @@ +/// <reference types="Cypress" /> + +context('Querying', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/querying') + }) + + // The most commonly used query is 'cy.get()', you can + // think of this like the '$' in jQuery + + it('cy.get() - query DOM elements', () => { + // https://on.cypress.io/get + + cy.get('#query-btn').should('contain', 'Button') + + cy.get('.query-btn').should('contain', 'Button') + + cy.get('#querying .well>button:first').should('contain', 'Button') + // ↲ + // Use CSS selectors just like jQuery + + cy.get('[data-test-id="test-example"]').should('have.class', 'example') + + // 'cy.get()' yields jQuery object, you can get its attribute + // by invoking `.attr()` method + cy.get('[data-test-id="test-example"]') + .invoke('attr', 'data-test-id') + .should('equal', 'test-example') + + // or you can get element's CSS property + cy.get('[data-test-id="test-example"]') + .invoke('css', 'position') + .should('equal', 'static') + + // or use assertions directly during 'cy.get()' + // https://on.cypress.io/assertions + cy.get('[data-test-id="test-example"]') + .should('have.attr', 'data-test-id', 'test-example') + .and('have.css', 'position', 'static') + }) + + it('cy.contains() - query DOM elements with matching content', () => { + // https://on.cypress.io/contains + cy.get('.query-list') + .contains('bananas') + .should('have.class', 'third') + + // we can pass a regexp to `.contains()` + cy.get('.query-list') + .contains(/^b\w+/) + .should('have.class', 'third') + + cy.get('.query-list') + .contains('apples') + .should('have.class', 'first') + + // passing a selector to contains will + // yield the selector containing the text + cy.get('#querying') + .contains('ul', 'oranges') + .should('have.class', 'query-list') + + cy.get('.query-button') + .contains('Save Form') + .should('have.class', 'btn') + }) + + it('.within() - query DOM elements within a specific element', () => { + // https://on.cypress.io/within + cy.get('.query-form').within(() => { + cy.get('input:first').should('have.attr', 'placeholder', 'Email') + cy.get('input:last').should('have.attr', 'placeholder', 'Password') + }) + }) + + it('cy.root() - query the root DOM element', () => { + // https://on.cypress.io/root + + // By default, root is the document + cy.root().should('match', 'html') + + cy.get('.query-ul').within(() => { + // In this within, the root is now the ul DOM element + cy.root().should('have.class', 'query-ul') + }) + }) + + it('best practices - selecting elements', () => { + // https://on.cypress.io/best-practices#Selecting-Elements + cy.get('[data-cy=best-practices-selecting-elements]').within(() => { + // Worst - too generic, no context + cy.get('button').click() + + // Bad. Coupled to styling. Highly subject to change. + cy.get('.btn.btn-large').click() + + // Average. Coupled to the `name` attribute which has HTML semantics. + cy.get('[name=submission]').click() + + // Better. But still coupled to styling or JS event listeners. + cy.get('#main').click() + + // Slightly better. Uses an ID but also ensures the element + // has an ARIA role attribute + cy.get('#main[role=button]').click() + + // Much better. But still coupled to text content that may change. + cy.contains('Submit').click() + + // Best. Insulated from all changes. + cy.get('[data-cy=submit]').click() + }) + }) +}) diff --git a/cypress/examples/spies_stubs_clocks.spec.js b/cypress/examples/spies_stubs_clocks.spec.js new file mode 100644 index 00000000..ee677e6a --- /dev/null +++ b/cypress/examples/spies_stubs_clocks.spec.js @@ -0,0 +1,95 @@ +/// <reference types="Cypress" /> + +context('Spies, Stubs, and Clock', () => { + it('cy.spy() - wrap a method in a spy', () => { + // https://on.cypress.io/spy + cy.visit('https://example.cypress.io/commands/spies-stubs-clocks') + + const obj = { + foo () {}, + } + + const spy = cy.spy(obj, 'foo').as('anyArgs') + + obj.foo() + + expect(spy).to.be.called + }) + + it('cy.spy() retries until assertions pass', () => { + cy.visit('https://example.cypress.io/commands/spies-stubs-clocks') + + const obj = { + /** + * Prints the argument passed + * @param x {any} + */ + foo (x) { + console.log('obj.foo called with', x) + }, + } + + cy.spy(obj, 'foo').as('foo') + + setTimeout(() => { + obj.foo('first') + }, 500) + + setTimeout(() => { + obj.foo('second') + }, 2500) + + cy.get('@foo').should('have.been.calledTwice') + }) + + it('cy.stub() - create a stub and/or replace a function with stub', () => { + // https://on.cypress.io/stub + cy.visit('https://example.cypress.io/commands/spies-stubs-clocks') + + const obj = { + /** + * prints both arguments to the console + * @param a {string} + * @param b {string} + */ + foo (a, b) { + console.log('a', a, 'b', b) + }, + } + + const stub = cy.stub(obj, 'foo').as('foo') + + obj.foo('foo', 'bar') + + expect(stub).to.be.called + }) + + it('cy.clock() - control time in the browser', () => { + // https://on.cypress.io/clock + + // create the date in UTC so its always the same + // no matter what local timezone the browser is running in + const now = new Date(Date.UTC(2017, 2, 14)).getTime() + + cy.clock(now) + cy.visit('https://example.cypress.io/commands/spies-stubs-clocks') + cy.get('#clock-div').click() + .should('have.text', '1489449600') + }) + + it('cy.tick() - move time in the browser', () => { + // https://on.cypress.io/tick + + // create the date in UTC so its always the same + // no matter what local timezone the browser is running in + const now = new Date(Date.UTC(2017, 2, 14)).getTime() + + cy.clock(now) + cy.visit('https://example.cypress.io/commands/spies-stubs-clocks') + cy.get('#tick-div').click() + .should('have.text', '1489449600') + cy.tick(10000) // 10 seconds passed + cy.get('#tick-div').click() + .should('have.text', '1489449610') + }) +}) diff --git a/cypress/examples/traversal.spec.js b/cypress/examples/traversal.spec.js new file mode 100644 index 00000000..1082eca6 --- /dev/null +++ b/cypress/examples/traversal.spec.js @@ -0,0 +1,121 @@ +/// <reference types="Cypress" /> + +context('Traversal', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/traversal') + }) + + it('.children() - get child DOM elements', () => { + // https://on.cypress.io/children + cy.get('.traversal-breadcrumb') + .children('.active') + .should('contain', 'Data') + }) + + it('.closest() - get closest ancestor DOM element', () => { + // https://on.cypress.io/closest + cy.get('.traversal-badge') + .closest('ul') + .should('have.class', 'list-group') + }) + + it('.eq() - get a DOM element at a specific index', () => { + // https://on.cypress.io/eq + cy.get('.traversal-list>li') + .eq(1).should('contain', 'siamese') + }) + + it('.filter() - get DOM elements that match the selector', () => { + // https://on.cypress.io/filter + cy.get('.traversal-nav>li') + .filter('.active').should('contain', 'About') + }) + + it('.find() - get descendant DOM elements of the selector', () => { + // https://on.cypress.io/find + cy.get('.traversal-pagination') + .find('li').find('a') + .should('have.length', 7) + }) + + it('.first() - get first DOM element', () => { + // https://on.cypress.io/first + cy.get('.traversal-table td') + .first().should('contain', '1') + }) + + it('.last() - get last DOM element', () => { + // https://on.cypress.io/last + cy.get('.traversal-buttons .btn') + .last().should('contain', 'Submit') + }) + + it('.next() - get next sibling DOM element', () => { + // https://on.cypress.io/next + cy.get('.traversal-ul') + .contains('apples').next().should('contain', 'oranges') + }) + + it('.nextAll() - get all next sibling DOM elements', () => { + // https://on.cypress.io/nextall + cy.get('.traversal-next-all') + .contains('oranges') + .nextAll().should('have.length', 3) + }) + + it('.nextUntil() - get next sibling DOM elements until next el', () => { + // https://on.cypress.io/nextuntil + cy.get('#veggies') + .nextUntil('#nuts').should('have.length', 3) + }) + + it('.not() - remove DOM elements from set of DOM elements', () => { + // https://on.cypress.io/not + cy.get('.traversal-disabled .btn') + .not('[disabled]').should('not.contain', 'Disabled') + }) + + it('.parent() - get parent DOM element from DOM elements', () => { + // https://on.cypress.io/parent + cy.get('.traversal-mark') + .parent().should('contain', 'Morbi leo risus') + }) + + it('.parents() - get parent DOM elements from DOM elements', () => { + // https://on.cypress.io/parents + cy.get('.traversal-cite') + .parents().should('match', 'blockquote') + }) + + it('.parentsUntil() - get parent DOM elements from DOM elements until el', () => { + // https://on.cypress.io/parentsuntil + cy.get('.clothes-nav') + .find('.active') + .parentsUntil('.clothes-nav') + .should('have.length', 2) + }) + + it('.prev() - get previous sibling DOM element', () => { + // https://on.cypress.io/prev + cy.get('.birds').find('.active') + .prev().should('contain', 'Lorikeets') + }) + + it('.prevAll() - get all previous sibling DOM elements', () => { + // https://on.cypress.io/prevAll + cy.get('.fruits-list').find('.third') + .prevAll().should('have.length', 2) + }) + + it('.prevUntil() - get all previous sibling DOM elements until el', () => { + // https://on.cypress.io/prevUntil + cy.get('.foods-list').find('#nuts') + .prevUntil('#veggies').should('have.length', 3) + }) + + it('.siblings() - get all sibling DOM elements', () => { + // https://on.cypress.io/siblings + cy.get('.traversal-pills .active') + .siblings().should('have.length', 2) + }) +}) diff --git a/cypress/examples/utilities.spec.js b/cypress/examples/utilities.spec.js new file mode 100644 index 00000000..9a52cb41 --- /dev/null +++ b/cypress/examples/utilities.spec.js @@ -0,0 +1,133 @@ +/// <reference types="Cypress" /> + +context('Utilities', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/utilities') + }) + + it('Cypress._ - call a lodash method', () => { + // https://on.cypress.io/_ + cy.request('https://jsonplaceholder.cypress.io/users') + .then((response) => { + let ids = Cypress._.chain(response.body).map('id').take(3).value() + + expect(ids).to.deep.eq([1, 2, 3]) + }) + }) + + it('Cypress.$ - call a jQuery method', () => { + // https://on.cypress.io/$ + let $li = Cypress.$('.utility-jquery li:first') + + cy.wrap($li) + .should('not.have.class', 'active') + .click() + .should('have.class', 'active') + }) + + it('Cypress.Blob - blob utilities and base64 string conversion', () => { + // https://on.cypress.io/blob + cy.get('.utility-blob').then(($div) => + // https://github.com/nolanlawson/blob-util#imgSrcToDataURL + // get the dataUrl string for the javascript-logo + Cypress.Blob.imgSrcToDataURL('https://example.cypress.io/assets/img/javascript-logo.png', undefined, 'anonymous') + .then((dataUrl) => { + // create an <img> element and set its src to the dataUrl + let img = Cypress.$('<img />', { src: dataUrl }) + + // need to explicitly return cy here since we are initially returning + // the Cypress.Blob.imgSrcToDataURL promise to our test + // append the image + $div.append(img) + + cy.get('.utility-blob img').click() + .should('have.attr', 'src', dataUrl) + })) + }) + + it('Cypress.minimatch - test out glob patterns against strings', () => { + // https://on.cypress.io/minimatch + let matching = Cypress.minimatch('/users/1/comments', '/users/*/comments', { + matchBase: true, + }) + + expect(matching, 'matching wildcard').to.be.true + + matching = Cypress.minimatch('/users/1/comments/2', '/users/*/comments', { + matchBase: true, + }) + expect(matching, 'comments').to.be.false + + // ** matches against all downstream path segments + matching = Cypress.minimatch('/foo/bar/baz/123/quux?a=b&c=2', '/foo/**', { + matchBase: true, + }) + expect(matching, 'comments').to.be.true + + // whereas * matches only the next path segment + + matching = Cypress.minimatch('/foo/bar/baz/123/quux?a=b&c=2', '/foo/*', { + matchBase: false, + }) + expect(matching, 'comments').to.be.false + }) + + + it('Cypress.moment() - format or parse dates using a moment method', () => { + // https://on.cypress.io/moment + const time = Cypress.moment('2014-04-25T19:38:53.196Z').utc().format('h:mm A') + + expect(time).to.be.a('string') + + cy.get('.utility-moment').contains('3:38 PM') + .should('have.class', 'badge') + + // the time in the element should be between 3pm and 5pm + const start = Cypress.moment('3:00 PM', 'LT') + const end = Cypress.moment('5:00 PM', 'LT') + + cy.get('.utility-moment .badge') + .should(($el) => { + // parse American time like "3:38 PM" + const m = Cypress.moment($el.text().trim(), 'LT') + + // display hours + minutes + AM|PM + const f = 'h:mm A' + + expect(m.isBetween(start, end), + `${m.format(f)} should be between ${start.format(f)} and ${end.format(f)}`).to.be.true + }) + }) + + + it('Cypress.Promise - instantiate a bluebird promise', () => { + // https://on.cypress.io/promise + let waited = false + + /** + * @return Bluebird<string> + */ + function waitOneSecond () { + // return a promise that resolves after 1 second + // @ts-ignore TS2351 (new Cypress.Promise) + return new Cypress.Promise((resolve, reject) => { + setTimeout(() => { + // set waited to true + waited = true + + // resolve with 'foo' string + resolve('foo') + }, 1000) + }) + } + + cy.then(() => + // return a promise to cy.then() that + // is awaited until it resolves + // @ts-ignore TS7006 + waitOneSecond().then((str) => { + expect(str).to.eq('foo') + expect(waited).to.be.true + })) + }) +}) diff --git a/cypress/examples/viewport.spec.js b/cypress/examples/viewport.spec.js new file mode 100644 index 00000000..711fe74e --- /dev/null +++ b/cypress/examples/viewport.spec.js @@ -0,0 +1,59 @@ +/// <reference types="Cypress" /> + +context('Viewport', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/viewport') + }) + + it('cy.viewport() - set the viewport size and dimension', () => { + // https://on.cypress.io/viewport + + cy.get('#navbar').should('be.visible') + cy.viewport(320, 480) + + // the navbar should have collapse since our screen is smaller + cy.get('#navbar').should('not.be.visible') + cy.get('.navbar-toggle').should('be.visible').click() + cy.get('.nav').find('a').should('be.visible') + + // lets see what our app looks like on a super large screen + cy.viewport(2999, 2999) + + // 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 is a little too fast to see :) + + cy.viewport('macbook-15') + cy.wait(200) + cy.viewport('macbook-13') + cy.wait(200) + cy.viewport('macbook-11') + cy.wait(200) + cy.viewport('ipad-2') + cy.wait(200) + cy.viewport('ipad-mini') + cy.wait(200) + cy.viewport('iphone-6+') + cy.wait(200) + cy.viewport('iphone-6') + cy.wait(200) + cy.viewport('iphone-5') + cy.wait(200) + cy.viewport('iphone-4') + cy.wait(200) + cy.viewport('iphone-3') + cy.wait(200) + + // cy.viewport() accepts an orientation for all presets + // the default orientation is 'portrait' + cy.viewport('ipad-2', 'portrait') + cy.wait(200) + cy.viewport('iphone-4', 'landscape') + cy.wait(200) + + // The viewport will be reset back to the default dimensions + // in between tests (the default can be set in cypress.json) + }) +}) diff --git a/cypress/examples/waiting.spec.js b/cypress/examples/waiting.spec.js new file mode 100644 index 00000000..e11d9ca9 --- /dev/null +++ b/cypress/examples/waiting.spec.js @@ -0,0 +1,34 @@ +/// <reference types="Cypress" /> + +context('Waiting', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/waiting') + }) + // BE CAREFUL of adding unnecessary wait times. + // https://on.cypress.io/best-practices#Unnecessary-Waiting + + // https://on.cypress.io/wait + it('cy.wait() - wait for a specific amount of time', () => { + cy.get('.wait-input1').type('Wait 1000ms after typing') + cy.wait(1000) + cy.get('.wait-input2').type('Wait 1000ms after typing') + cy.wait(1000) + cy.get('.wait-input3').type('Wait 1000ms after typing') + cy.wait(1000) + }) + + it('cy.wait() - wait for a specific route', () => { + cy.server() + + // Listen to GET to comments/1 + cy.route('GET', 'comments/*').as('getComment') + + // we have code that gets a comment when + // the button is clicked in scripts.js + cy.get('.network-btn').click() + + // wait for GET comments/1 + cy.wait('@getComment').its('status').should('eq', 200) + }) + +}) diff --git a/cypress/examples/window.spec.js b/cypress/examples/window.spec.js new file mode 100644 index 00000000..00bff9f7 --- /dev/null +++ b/cypress/examples/window.spec.js @@ -0,0 +1,22 @@ +/// <reference types="Cypress" /> + +context('Window', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/window') + }) + + it('cy.window() - get the global window object', () => { + // https://on.cypress.io/window + cy.window().should('have.property', 'top') + }) + + it('cy.document() - get the document object', () => { + // https://on.cypress.io/document + cy.document().should('have.property', 'charset').and('eq', 'UTF-8') + }) + + it('cy.title() - get the title', () => { + // https://on.cypress.io/title + cy.title().should('include', 'Kitchen Sink') + }) +}) diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json new file mode 100644 index 00000000..da18d935 --- /dev/null +++ b/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} \ No newline at end of file diff --git a/cypress/fixtures/profile.json b/cypress/fixtures/profile.json new file mode 100644 index 00000000..b6c355ca --- /dev/null +++ b/cypress/fixtures/profile.json @@ -0,0 +1,5 @@ +{ + "id": 8739, + "name": "Jane", + "email": "jane@example.com" +} \ No newline at end of file diff --git a/cypress/fixtures/users.json b/cypress/fixtures/users.json new file mode 100644 index 00000000..79b699aa --- /dev/null +++ b/cypress/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/cypress/integration/test.spec.js b/cypress/integration/test.spec.js new file mode 100644 index 00000000..9cc9f390 --- /dev/null +++ b/cypress/integration/test.spec.js @@ -0,0 +1,22 @@ +/// <reference types="Cypress" /> + +context('Window', () => { + before(() => { + cy.visit('/') + }) + + it('check meta charset', () => { + // https://on.cypress.io/document + cy.document().should('have.property', 'charset').and('eq', 'UTF-8') + }) + + it('check document title', () => { + // https://on.cypress.io/title + cy.title().should('eq', 'CoopStarter') + }) + + it('check heading', () => { + // https://on.cypress.io/title + cy.get('h2.title_lead').should('include.text', 'Bienvenue') + }) +}) diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js new file mode 100644 index 00000000..fd170fba --- /dev/null +++ b/cypress/plugins/index.js @@ -0,0 +1,17 @@ +// *********************************************************** +// This example plugins/index.js can be used to load plugins +// +// You can change the location of this file or turn off loading +// the plugins file with the 'pluginsFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/plugins-guide +// *********************************************************** + +// This function is called when a project is opened or re-opened (e.g. due to +// the project's config changing) + +module.exports = (on, config) => { + // `on` is used to hook into various events Cypress emits + // `config` is the resolved Cypress config +} diff --git a/cypress/screenshots/test.spec.js/An uncaught error was detected outside of a test (failed).png b/cypress/screenshots/test.spec.js/An uncaught error was detected outside of a test (failed).png new file mode 100644 index 0000000000000000000000000000000000000000..8cda6d8f4fc5efded6e14f3f9e953a065e122346 GIT binary patch literal 39693 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 literal 0 HcmV?d00001 diff --git a/cypress/support/commands.js b/cypress/support/commands.js new file mode 100644 index 00000000..ca4d256f --- /dev/null +++ b/cypress/support/commands.js @@ -0,0 +1,25 @@ +// *********************************************** +// This example commands.js shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add("login", (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/cypress/support/index.js b/cypress/support/index.js new file mode 100644 index 00000000..d68db96d --- /dev/null +++ b/cypress/support/index.js @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') diff --git a/cypress/videos/test.spec.js.mp4 b/cypress/videos/test.spec.js.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..c62deef5109b25c8df35dc3b2598ecac95d45437 GIT binary patch literal 28361 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 I&c^nC0RDOY2><{9 literal 0 HcmV?d00001 diff --git a/package.json b/package.json index a838486e..72ad7e65 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "version": "1.0.0", "license": "MIT", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", + "test": "cypress run", + "cypress": "cypress open", "scss": "node-sass -w ./src/styles/index.scss -o ./www/styles/", "pug": "node ./compile-pug.js -w", "copy-js": "cp ./src/scripts/*.js ./www/scripts/", @@ -11,21 +12,24 @@ "copy-images": "cp -R ./src/images ./www", "watch-js": "onchange 'src/scripts/*.js' -- run-s copy-js", "watch": "run-p scss pug watch-js copy-fonts copy-images", - "serve": "node server.js" + "serve": "node server.js", + "start": "node server.js" }, "devDependencies": { - "http-server": "^0.11.1", - "copy-and-watch": "^0.1.2", - "npm-run-all": "^4.1.5", - "@babel/core": "^7.1.0", "@babel/cli": "^7.1.0", - "node-sass": "^4.9.3", + "@babel/core": "^7.1.0", "browser-sync": "^2.24.7", - "express": "^4.16.3", "chokidar": "^3.2.3", + "copy-and-watch": "^0.1.2", + "cypress": "^3.8.1", + "express": "^4.16.3", + "http-server": "^0.11.1", "js-yaml": "^3.13.1", + "node-sass": "^4.13.0", + "npm-run-all": "^4.1.5", "object-assign-deep": "^0.4.0", - "pug": "^2.0.4" + "pug": "^2.0.4", + "wait-on": "^3.3.0" }, "dependencies": { "@webcomponents/html-imports": "^1.2.0", @@ -35,5 +39,13 @@ "normalize.css": "^8.0.0", "onchange": "^6.1.0", "simple-line-icons": "^2.4.1" - } + }, + "description": "This repository is the frontend application of the CoopStarter project.", + "main": "compile-pug.js", + "repository": { + "type": "git", + "url": "git@git.happy-dev.fr:startinblox/applications/coop-starter/coopstarter-front.git" + }, + "keywords": [], + "author": "" } -- GitLab