├── .gitignore ├── cypress.config.js ├── cypress ├── e2e │ ├── TC01.cy.js │ ├── TC02_fixtures.cy.js │ ├── TC03_writeReadFile.cy.js │ ├── TC04_each.cy.js │ ├── TC05_conditionalTesting.cy.js │ ├── TC06_fileUpload.cy.js │ ├── TC07_fileDownload.cy.js │ ├── TC08_apiTesting.cy.js │ ├── TC09_apiChaining.cy.js │ ├── TC_10_apiMocking.cy.js │ ├── TC_11_jsAlertConfirmPrompt.cy.js │ ├── TC_12_usingskip.cy.js │ ├── TC_13_usingOnly.cy.js │ ├── TC_14_shadowDOM.cy.js │ ├── TC_15_numberOfRetries.cy.js │ ├── TC_16_iFrames.cy.js │ ├── TC_17_pageObject1.cy.js │ ├── TC_18_cypressStudio.cy.js │ ├── TC_19_intercept.cy.js │ ├── TC_20_hoverOverElement.cy.js │ ├── TC_21_databaseTesting.cy.js │ ├── TC_22_parentParentsChildren.cy.js │ ├── TC_23_dragAndDrop.cy.js │ ├── TC_24_newBrowserTabWindow.cy.js │ ├── TC_25_filterFindWithin.cy.js │ ├── TC_26_jqueryCommands.cy.js │ ├── TC_27_cypressRecursion.cy.js │ ├── TC_28_basicAuth.cy.js │ ├── TC_29_cypressRecorder.cy.js │ ├── cucumber-test │ │ ├── login.feature │ │ └── login │ │ │ └── login.js │ ├── examples │ │ ├── actions.spec.js │ │ ├── aliasing.spec.js │ │ ├── assertions.spec.js │ │ ├── connectors.spec.js │ │ ├── cookies.spec.js │ │ ├── cypress_api.spec.js │ │ ├── files.spec.js │ │ ├── local_storage.spec.js │ │ ├── location.spec.js │ │ ├── misc.spec.js │ │ ├── navigation.spec.js │ │ ├── network_requests.spec.js │ │ ├── querying.spec.js │ │ ├── spies_stubs_clocks.spec.js │ │ ├── traversal.spec.js │ │ ├── utilities.spec.js │ │ ├── viewport.spec.js │ │ ├── waiting.spec.js │ │ └── window.spec.js │ ├── pages │ │ ├── dashboardPage.js │ │ └── loginPage.js │ ├── sequenced-tests.cy.js │ └── utils │ │ ├── dashboard.js │ │ └── login.js ├── fixtures │ ├── Download │ │ └── test.txt │ ├── articlefeed.json │ ├── example.json │ ├── images │ │ ├── evening.png │ │ ├── morning.jpg │ │ └── night.jpg │ ├── profile.json │ ├── tags.json │ ├── test1.txt │ ├── test2.json │ ├── testdata.json │ └── users.json ├── plugins │ └── index.js └── support │ ├── commands.js │ ├── e2e.js │ └── filterTests.js ├── jsconfig.json ├── package-lock.json ├── package.json ├── readme.md └── testdata └── test1.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | cypress/videos 4 | cypress/screenshots 5 | TestReport/ 6 | mochawesome-report/ 7 | cypress-combined-report.json 8 | cypress/integration/dummy.js 9 | cypress/fixtures/url.json 10 | cypress/fixtures/data.txt 11 | abcd.html 12 | dummy.cy.js -------------------------------------------------------------------------------- /cypress.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('cypress') 2 | 3 | module.exports = defineConfig({ 4 | watchForFileChanges: false, 5 | chromeWebSecurity: false, 6 | retries: 1, 7 | reporter: '../node_modules/mochawesome/src/mochawesome.js', 8 | reporterOptions: { 9 | overwrite: false, 10 | html: false, 11 | json: true, 12 | }, 13 | projectId: 'd5zibb', 14 | env: { 15 | db: { 16 | host: 'db4free.net', 17 | user: 'username', 18 | password: 'password', 19 | database: 'db_name', 20 | }, 21 | }, 22 | e2e: { 23 | // We've imported your old cypress plugins here. 24 | // You may want to clean this up later by importing these. 25 | setupNodeEvents(on, config) { 26 | require("@deploysentinel/cypress-recorder")(on, config) 27 | return require('./cypress/plugins/index.js')(on, config) 28 | }, 29 | specPattern: 30 | ["**/*.feature", "cypress/e2e/**/*.cy.{js,jsx,ts,tsx}"], 31 | baseUrl: 'https://opensource-demo.orangehrmlive.com/', 32 | }, 33 | }) 34 | -------------------------------------------------------------------------------- /cypress/e2e/TC01.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters([], () => { 4 | describe('Search for Google Wiki page from Wikipedia website (Smoke)', () => { 5 | before(() => { 6 | cy.visit('https://wikipedia.org') 7 | }) 8 | 9 | it('Validate Page Title', () => { 10 | cy.title().should('eq', 'Wikipedia') 11 | }) 12 | 13 | it('Search for Google Wiki Page', () => { 14 | cy.get('#searchInput').type('google') 15 | cy.get('button[type="submit"]').click() 16 | }) 17 | 18 | it('Validate Google Wiki Page has opened', () => { 19 | cy.get('h1#firstHeading').contains('Google') 20 | cy.title().should('eq', 'Google - Wikipedia') 21 | }) 22 | }) 23 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC02_fixtures.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters([], () => { 4 | describe('Login to OrangeHRM website (E2E)', function () { 5 | before(function () { 6 | cy.visit('https://opensource-demo.orangehrmlive.com/') 7 | cy.fixture('testdata').then(function (testdata) { 8 | this.testdata = testdata 9 | }) 10 | }) 11 | 12 | it('Validate successful Login', function () { 13 | cy.get('#txtUsername').type(this.testdata.username) 14 | cy.get('#txtPassword').type(this.testdata.password) 15 | cy.get('#btnLogin').click() 16 | cy.get('#welcome').contains(this.testdata.welcomeText) 17 | }) 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /cypress/e2e/TC03_writeReadFile.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters([], () => { 4 | describe('Example for writeFile and readFile (Smoke,E2E)', function () { 5 | 6 | it('Write to a text file test1.txt using writeFile', function () { 7 | cy.writeFile('cypress/fixtures/test1.txt', 'Testersdock.com\n') 8 | }) 9 | 10 | it('Append content to the end of the text file test1.txt using the flag a+', function () { 11 | cy.writeFile('cypress/fixtures/test1.txt', 'Info Hub for Testers', { flag: 'a+' }) 12 | }) 13 | 14 | it('Write to a JSON file test2.json using writeFile', function () { 15 | cy.writeFile('cypress/fixtures/test2.json', { firstname: 'Alapan', lastname: 'Das' }) 16 | }) 17 | 18 | it('Validate the content of both text and JSON file using readFile', function () { 19 | cy.readFile('cypress/fixtures/test1.txt').should('contain', 'Testersdock') 20 | cy.readFile('cypress/fixtures/test1.txt').should('eq', 'Testersdock.com\nInfo Hub for Testers') 21 | cy.readFile('cypress/fixtures/test2.json').its('firstname').should('eq', 'Alapan') 22 | }) 23 | 24 | }) 25 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC04_each.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters([], () => { 4 | describe('Example to demonstrate the use each in Cypress', function () { 5 | before(function () { 6 | cy.visit('https://opensource-demo.orangehrmlive.com/') 7 | }) 8 | 9 | beforeEach(function () { 10 | cy.fixture('testdata').then(function (testdata) { 11 | this.testdata = testdata 12 | }) 13 | }) 14 | 15 | it('Validate successful Login', function () { 16 | cy.get('#txtUsername').type(this.testdata.username) 17 | cy.get('#txtPassword').type(this.testdata.password) 18 | cy.get('#btnLogin').click() 19 | cy.get('#welcome').contains(this.testdata.welcomeText) 20 | }) 21 | 22 | it('Validate all the Quick Launch Texts', function () { 23 | cy.get('.quickLaunge').each(($el, index) => { 24 | expect($el).to.contain(this.testdata.quickLaunch[index]) 25 | }) 26 | }) 27 | 28 | /*Please check the pie chart percentage values before execution. 29 | I realized it very late that the pie chart values changes after few days. 30 | Update the empDistPieChart from the testdata.json file with the latest values.*/ 31 | 32 | it('Validate the Employee Distribution by Subunit Piechart Values and sum of percentage values', function () { 33 | var total = 0 34 | cy.get('.pieLabel').each(($el, index) => { 35 | expect($el).to.contain(this.testdata.empDistPieChart[index]) 36 | total = total + parseInt($el.text()) 37 | }).then(() => { 38 | expect(total).to.equal(99) 39 | }) 40 | }) 41 | }) 42 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC05_conditionalTesting.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters(['regression'], () => { 4 | describe('Example to demo conditional testing in cypress', () => { 5 | beforeEach(() => { 6 | cy.visit('https://wikipedia.org') 7 | }) 8 | 9 | it('Check that if you find WikiVoyage on the page, then click on it and validate (Go to If)', () => { 10 | cy.title().should('eq', 'Wikipedia') 11 | cy.get('body').then((body) => { 12 | if (body.find('[data-jsl10n="wikivoyage.name"]').length > 0) { 13 | cy.get('[data-jsl10n="wikivoyage.name"]').click() 14 | } 15 | else { 16 | cy.get('[data-jsl10n="wiktionary.name"]').click() 17 | } 18 | }) 19 | cy.title().should('eq', 'Wikivoyage') 20 | }) 21 | 22 | it('Check that if you dont find WikiVoyage in the page, then click on Wiktionary and validate (Go to Else)', () => { 23 | cy.title().should('eq', 'Wikipedia') 24 | cy.get('body').then((body) => { 25 | if (body.find('wrongLocator').length > 0) { 26 | cy.get('[data-jsl10n="wikivoyage.name"]').click() 27 | } 28 | else { 29 | cy.get('[data-jsl10n="wiktionary.name"]').click() 30 | } 31 | }) 32 | cy.title().should('eq', 'Wiktionary') 33 | }) 34 | }) 35 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC06_fileUpload.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters([], () => { 4 | describe('Example to demonstrate file upload in cypress', function () { 5 | 6 | it('File Upload using cypress-file-upload npm package', () => { 7 | cy.visit('https://the-internet.herokuapp.com/upload') 8 | const filepath = 'images/evening.png' 9 | cy.get('input[type="file"]').attachFile(filepath) 10 | cy.get('#file-submit').click() 11 | cy.get('#uploaded-files').contains('evening.png') 12 | }) 13 | 14 | it('File Upload using selectFile with select mode', () => { 15 | cy.visit('https://the-internet.herokuapp.com/upload') 16 | cy.get('#file-upload').selectFile('cypress/fixtures/images/evening.png') 17 | cy.get('#file-submit').click() 18 | cy.get('#uploaded-files').contains('evening.png') 19 | }) 20 | 21 | it('File Upload using selectFile with drag and drop mode', () => { 22 | cy.visit('https://postimages.org/') 23 | cy.get('#uploadFile').selectFile('cypress/fixtures/images/evening.png', { action: 'drag-drop' }) 24 | cy.get('.controls > h2', { timeout: 7000 }).should('have.text', 'Upload completed!') 25 | cy.get('.imagetitle').should('have.text', 'evening') 26 | }) 27 | 28 | it.only('Multiple file upload using selectFile', () => { 29 | cy.visit('https://postimages.org/') 30 | cy.get('#uploadFile').selectFile([ 31 | 'cypress/fixtures/images/morning.jpg', 32 | 'cypress/fixtures/images/evening.png', 33 | 'cypress/fixtures/images/night.jpg', 34 | ], { action: 'drag-drop' }) 35 | cy.get('.controls > h2', { timeout: 9000 }).should('have.text', 'Upload completed!') 36 | cy.get('.imagetitle').eq(0).should('have.text', 'evening') 37 | cy.get('.imagetitle').eq(1).should('have.text', 'morning') 38 | cy.get('.imagetitle').eq(2).should('have.text', 'night') 39 | }) 40 | }) 41 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC07_fileDownload.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters([], () => { 4 | describe('Example to demonstrate file download in cypress', function () { 5 | 6 | it('File Download using cypress-downloadfile npm package', () => { 7 | cy.downloadFile('https://www.learningcontainer.com/wp-content/uploads/2020/04/sample-text-file.txt', 8 | 'cypress/fixtures/Download', 'test.txt') 9 | cy.readFile('cypress/fixtures/Download/test.txt').should('contain', 'Lorem ipsum dolor sit amet') 10 | }) 11 | }) 12 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC08_apiTesting.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters(['regression','smoke'], () => { 4 | describe('Example to demonstrate API Testing in cypress', function () { 5 | 6 | it('Hit an API End point and validate its response status code and body', () => { 7 | cy.request({ 8 | method: 'GET', 9 | url: 'https://randomuser.me/api/', 10 | qs: 'results=1' 11 | }).then((response) => { 12 | expect(response.status).to.eq(200) 13 | expect(response.body).to.have.property('info') 14 | expect(response.body.info).to.have.property('version', '1.3') 15 | }) 16 | }) 17 | }) 18 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC09_apiChaining.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters([], () => { 4 | describe('Example to demonstrate API Chaining in Cypress', function () { 5 | 6 | it('Chain two API requests and validate the response', () => { 7 | //Part 1 8 | cy.request({ 9 | method: 'GET', 10 | url: 'https://www.metaweather.com/api/location/search/?query=sn', 11 | }).then((response) => { 12 | const location = response.body[0].title 13 | return location 14 | }) 15 | //Part 2 16 | .then((location) => { 17 | cy.request({ 18 | method: 'GET', 19 | url: 'https://www.metaweather.com/api/location/search/?query=' + location 20 | }).then((response) => { 21 | expect(response.status).to.eq(200) 22 | expect(response.body[0]).to.have.property('title', location) 23 | }) 24 | }) 25 | }) 26 | }) 27 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_10_apiMocking.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters([], () => { 4 | describe('Example to demonstrate API Mocking in Cypress', () => { 5 | 6 | beforeEach(() => { 7 | cy.server() 8 | cy.route('GET', '**/tags', 'fixture:tags.json') 9 | cy.route('GET', '**/articles*', 'fixture:articlefeed.json') 10 | cy.visit('https://angular.realworld.io/') 11 | }) 12 | 13 | it('Mock the Tags from the API Response and then validate on UI', () => { 14 | cy.get('.tag-list') 15 | .should('contain', 'cypress') 16 | .and('contain', 'selenium') 17 | 18 | }) 19 | 20 | it('Mock the Article feed from the API Response and then validate on UI', () => { 21 | cy.get('app-favorite-button.pull-xs-right').contains('10') 22 | cy.get('.author').contains('testersdock') 23 | cy.get('.preview-link > p').contains('This is a test description') 24 | }) 25 | }) 26 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_11_jsAlertConfirmPrompt.cy.js: -------------------------------------------------------------------------------- 1 | describe('Example to demonstrate handling of JavaScript Alerts, Confirm, Prompt in Cypress', () => { 2 | 3 | beforeEach(() => { 4 | cy.visit('http://the-internet.herokuapp.com/javascript_alerts') 5 | }) 6 | 7 | it('Handling JS Alert - Validate Alert Text and Click OK', () => { 8 | cy.contains('Click for JS Alert').click() 9 | cy.on('window:alert', (str) => { 10 | expect(str).to.equal('I am a JS Alert') 11 | }) 12 | cy.on('window:confirm', () => true); 13 | cy.get('#result').should('have.text', 'You successfully clicked an alert') 14 | }) 15 | 16 | it('Handling JS Confirm - Validate Confirm Text and Click OK', () => { 17 | cy.contains('Click for JS Confirm').click() 18 | cy.on('window:confirm', (str) => { 19 | expect(str).to.equal(`I am a JS Confirm`) 20 | }) 21 | cy.on('window:confirm', () => true); 22 | cy.get('#result').should('have.text', 'You clicked: Ok') 23 | }) 24 | 25 | it('Handling JS Confirm - Click Cancel', () => { 26 | cy.contains('Click for JS Confirm').click() 27 | cy.on('window:confirm', () => false); 28 | cy.get('#result').should('have.text', 'You clicked: Cancel') 29 | }) 30 | 31 | it('Handling JS Prompt - Input text in prompt, Click OK and Validate Input Text', () => { 32 | cy.window().then(($win) => { 33 | cy.stub($win, 'prompt').returns('This is a test text') 34 | cy.contains('Click for JS Prompt').click() 35 | }) 36 | cy.get('#result').should('have.text', 'You entered: This is a test text') 37 | }) 38 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_12_usingskip.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters([], () => { 4 | describe('Example to Demostrate the use of skip in cypress', () => { 5 | before(() => { 6 | cy.visit('https://wikipedia.org') 7 | }) 8 | 9 | it.skip('Validate Page Title', () => { 10 | cy.title().should('eq', 'Wikipedia') 11 | }) 12 | 13 | it('Search for Google Wiki Page', () => { 14 | cy.get('#searchInput').type('google') 15 | cy.get('button[type="submit"]').click() 16 | }) 17 | 18 | it.skip('Validate Google Wiki Page has opened', () => { 19 | cy.get('h1#firstHeading').contains('Google') 20 | cy.title().should('eq', 'Google - Wikipedia') 21 | }) 22 | }) 23 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_13_usingOnly.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters([], () => { 4 | describe('Example to Demostrate the use of only in cypress', () => { 5 | before(() => { 6 | cy.visit('https://wikipedia.org') 7 | }) 8 | 9 | it.only('Validate Page Title', () => { 10 | cy.title().should('eq', 'Wikipedia') 11 | }) 12 | 13 | it('Search for Google Wiki Page', () => { 14 | cy.get('#searchInput').type('google') 15 | cy.get('button[type="submit"]').click() 16 | }) 17 | 18 | it('Validate Google Wiki Page has opened', () => { 19 | cy.get('h1#firstHeading').contains('Google') 20 | cy.title().should('eq', 'Google - Wikipedia') 21 | }) 22 | }) 23 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_14_shadowDOM.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters([], () => { 4 | describe('Example to demonstrate the handling of Shadow Dom in Cypress', () => { 5 | beforeEach(() => { 6 | cy.visit('https://books-pwakit.appspot.com/') 7 | }) 8 | 9 | it('Input a text in the input box and after search validate the URL', () => { 10 | cy.get('book-app') //1 11 | .shadow() //2 12 | .find('app-header') //3 13 | .find('.toolbar-bottom') //4 14 | .find('book-input-decorator') //5 15 | .find('#input') //6 16 | .type('Science') 17 | .click() 18 | .url('contains', 'explore?q=Science') 19 | }) 20 | 21 | it('Input a text in the input box and after search validate the URL with includeShadowDom flag set to true', () => { 22 | cy.get('book-app') 23 | .find('#input') 24 | .type('Science', { force: true }) 25 | .click() 26 | .url('include', 'explore?q=Science') 27 | }) 28 | 29 | it('Input a text in the input box and after search validate the URL with includeShadowDom option', () => { 30 | cy.get('book-app') 31 | .find('#input', { includeShadowDom: true }) 32 | .type('Science', { force: true }) 33 | .click() 34 | .url('include', 'explore?q=Science') 35 | }) 36 | }) 37 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_15_numberOfRetries.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters([], () => { 4 | describe('Test to demonstrate Test Retries in Cypress', () => { 5 | before(() => { 6 | cy.visit('https://wikipedia.org') 7 | }) 8 | 9 | it('Validate Page Title', () => { 10 | //Intentionally making it fail to check retries 11 | cy.title().should('eq', 'Wikipedia1111') 12 | }) 13 | }) 14 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_16_iFrames.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters([], () => { 4 | describe('Test to demonstrate testing of iframes in Cypress', () => { 5 | before(() => { 6 | cy.visit('http://the-internet.herokuapp.com/iframe') 7 | }) 8 | 9 | it('Input text in the text editor which is inside an iframe', () => { 10 | cy.getIframe('#mce_0_ifr').clear().type('This is a test description.') 11 | }) 12 | }) 13 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_17_pageObject1.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters([], () => { 4 | describe('Validate Login and Logout on OrangeHRM website', function () { 5 | 6 | beforeEach(function () { 7 | cy.fixture('testdata').then(function (testdata) { 8 | this.testdata = testdata 9 | }) 10 | }) 11 | 12 | it('Validate successful Login', function () { 13 | cy.login(this.testdata) 14 | }) 15 | 16 | it('Validate successful Logout', function () { 17 | cy.logout() 18 | }) 19 | 20 | }) 21 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_18_cypressStudio.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters([], () => { 4 | describe('Example to Demonstrate Cypress Studio', () => { 5 | 6 | it('Extend Test via Cypress Studio', () => { 7 | cy.visit('https://opensource-demo.orangehrmlive.com/index.php/dashboard') 8 | /* ==== Generated with Cypress Studio ==== */ 9 | cy.get('#divUsername > .form-hint').click(); 10 | cy.get('#txtUsername').type('Admin'); 11 | cy.get('#txtPassword').type('admin123'); 12 | cy.get('#btnLogin').click(); 13 | cy.get('#welcome').click(); 14 | cy.get('#welcome-menu > :nth-child(1) > :nth-child(2) > a').click(); 15 | /* ==== End Cypress Studio ==== */ 16 | }) 17 | }) 18 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_19_intercept.cy.js: -------------------------------------------------------------------------------- 1 | import TestFilters from '../support/filterTests.js' 2 | 3 | TestFilters(['smoke'], () => { 4 | describe('Example to demonstrate API Mocking in Cypress using cy.intercept', () => { 5 | 6 | beforeEach(() => { 7 | cy.intercept('GET', '**/tags', { fixture: 'tags.json' }) 8 | cy.intercept('GET', '**/articles*', { fixture: 'articlefeed.json' }) 9 | cy.visit('https://angular.realworld.io/') 10 | }) 11 | 12 | it('Mock the Tags from the API Response and then validate on UI', () => { 13 | cy.get('.tag-list', { timeout: 10000 }) 14 | .should('contain', 'cypress') 15 | .and('contain', 'selenium') 16 | }) 17 | 18 | it('Mock the Article feed from the API Response and then validate on UI', () => { 19 | cy.get('app-favorite-button.pull-xs-right').contains('10') 20 | cy.get('.author').contains('testersdock') 21 | cy.get('.preview-link > p').contains('This is a test description') 22 | }) 23 | }) 24 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_20_hoverOverElement.cy.js: -------------------------------------------------------------------------------- 1 | describe('Example to Demostrate how to hover over element in cypress', () => { 2 | 3 | it('Hover and Validate Text using trigger(\'mouseover\')', function () { 4 | cy.visit('https://www.amazon.com/') 5 | cy.get('[data-csa-c-content-id="nav_ya_signin"]').trigger('mouseover') 6 | cy.contains('Create a List').click() 7 | cy.url().should('include','wishlist/intro') 8 | }) 9 | 10 | it('Hover and Validate Text using invoke(\'show\')', function () { 11 | cy.visit('http://automationpractice.com/index.php') 12 | cy.contains('Add to cart', {matchCase: false}).first().click() 13 | cy.get('.cross', {timeout: 5000}).click() 14 | cy.get('#searchbox').scrollTo('center',{ensureScrollable: false}) 15 | cy.get('.cart_block').invoke('show') 16 | cy.contains('Check out', {matchCase: false}).click() 17 | cy.get('.navigation_page').should('have.text', 'Your shopping cart') 18 | }) 19 | 20 | it('Hover and Validate Text using realHover()', function () { 21 | cy.visit('https://the-internet.herokuapp.com/hovers') 22 | cy.get('div:nth-child(3) > img').realHover('mouse') 23 | cy.get('div:nth-child(3) > div > h5').should('be.visible') 24 | cy.get('div:nth-child(4) > img').realHover('mouse') 25 | cy.get('div:nth-child(4) > div > h5').should('be.visible') 26 | cy.get('div:nth-child(5) > img').realHover('mouse') 27 | cy.get('div:nth-child(5) > div > h5').should('be.visible') 28 | }) 29 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_21_databaseTesting.cy.js: -------------------------------------------------------------------------------- 1 | describe('Example to Demonstrate SQL Database Testing in Cypress', () => { 2 | 3 | it('Create a Table', function () { 4 | cy.task('queryDb', "CREATE TABLE Persons (PersonID int, FirstName varchar(255), Address varchar(255), City varchar(255))") 5 | }) 6 | 7 | it('Input Entries into the table', function () { 8 | cy.task('queryDb', `INSERT INTO Persons (PersonID, FirstName, Address, City) VALUES 9 | (001, "John", "House No. 01", "Helsinki"), 10 | (002, "Pam", "House No. 02", "Espoo"), 11 | (003, "Dwight", "House No. 03", "Lapland"), 12 | (004, "Michael", "House No. 04", "Vantaa");`).then((result) => { 13 | expect(result.affectedRows).to.equal(4) 14 | }) 15 | }) 16 | 17 | it('Update an Entry into the table and verify', function () { 18 | cy.task('queryDb', `UPDATE Persons SET FirstName = "Kevin" WHERE City="Vantaa"`).then((result) => { 19 | expect(result.changedRows).to.equal(1) 20 | }) 21 | cy.task('queryDb', `SELECT FirstName FROM Persons WHERE City="Vantaa"`).then((result) => { 22 | expect(result[0].FirstName).to.equal('Kevin') 23 | }) 24 | }) 25 | 26 | it('Verify that there is only one row where the city is Espoo', function () { 27 | cy.task('queryDb', `SELECT COUNT(*) as "rowCount" FROM Persons WHERE City="Espoo"`).then((result) => { 28 | 29 | expect(result[0].rowCount).to.equal(1) 30 | }) 31 | }) 32 | 33 | it('Delete a Table and Verify', function () { 34 | cy.task('queryDb', `DROP TABLE Persons`).then((result) => { 35 | expect(result.message).to.equal("") 36 | }) 37 | }) 38 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_22_parentParentsChildren.cy.js: -------------------------------------------------------------------------------- 1 | describe('Example to demonstrate parent, parents and children commands in cypress', () => { 2 | 3 | before(() => { 4 | cy.visit('https://testautomationpractice.blogspot.com/') 5 | }) 6 | 7 | it('Using parents and children', function () { 8 | cy.get('employee#2') 9 | .parents('empinfo') 10 | .children('#3') 11 | .should('contain', 'Marry') 12 | }) 13 | 14 | it('Using parent and children', function () { 15 | cy.get('employee#2') 16 | .parent() 17 | .children('#1') 18 | .should('contain', 'david@myemail.com') 19 | }) 20 | 21 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_23_dragAndDrop.cy.js: -------------------------------------------------------------------------------- 1 | describe('Example to demonstrate Drag and Drop in cypress', () => { 2 | 3 | beforeEach(() => { 4 | 5 | //Defining browser resolution 6 | cy.viewport(1920, 1080) 7 | }) 8 | 9 | it('Using the cyess-drag-drop plugin on a HTML site', function () { 10 | 11 | cy.visit('https://the-internet.herokuapp.com/drag_and_drop') 12 | 13 | //Before Drag and Drop column-a has 'A' and 'column-b' has 'B' 14 | cy.get('#column-a') 15 | .should('have.text', 'A') 16 | cy.get('#column-b') 17 | .should('have.text', 'B') 18 | 19 | //Drag and drop using cyess-drag-drop plugin 20 | cy.get('#column-a').drag('#column-b') 21 | 22 | //After Drag and Drop column-a has 'B' and 'column-b' has 'A' 23 | cy.get('#column-a') 24 | .should('have.text', 'B') 25 | cy.get('#column-b') 26 | .should('have.text', 'A') 27 | }) 28 | 29 | it('Using custom commands on a Angular Material site', function () { 30 | 31 | cy.visit('https://material.angular.io/cdk/drag-drop/overview#cdk-drag-drop-connected-sorting') 32 | 33 | //Click on 'Accept Cookies' button 34 | cy.get('.buttons > .mat-primary').should('be.visible').click() 35 | 36 | //Check the drop list is visible 37 | cy.get('#cdk-drop-list-1 > div:nth-child(1)', { timeout: 7000 }) 38 | .should('be.visible') 39 | 40 | //Before Drag and Drop the first item is 'Get up' 41 | cy.get('#cdk-drop-list-2 > :nth-child(1)') 42 | .should('have.text', 'Get up') 43 | 44 | //Drag and Drop using custom command 45 | cy.draganddrop('#cdk-drop-list-1 > div:nth-child(1)', '#cdk-drop-list-2') 46 | 47 | //After Drag and Drop the first item is 'Get to work' 48 | cy.get('#cdk-drop-list-2 > :nth-child(1)') 49 | .should('have.text', 'Get to work') 50 | }) 51 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_24_newBrowserTabWindow.cy.js: -------------------------------------------------------------------------------- 1 | describe('Example to demonstrate the handling of new browser windows in cypress', () => { 2 | 3 | it('Handling new Browser Tab', function () { 4 | cy.visit('https://the-internet.herokuapp.com/windows') 5 | cy.get('.example > a').invoke('removeAttr', 'target').click() 6 | cy.url() 7 | .should('include', '/windows/new') 8 | cy.get('h3') 9 | .should('have.text', 'New Window') 10 | }) 11 | 12 | it('Handling new Browser Window', function () { 13 | cy.visit('https://alapanme.github.io/testing-cypress.html') 14 | cy.window().then((win) => { 15 | cy.stub(win, 'open', url => { 16 | win.location.href = 'https://the-internet.herokuapp.com/'; 17 | }).as("popup") 18 | }) 19 | cy.get('button').click() 20 | cy.get('@popup') 21 | .should("be.called") 22 | cy.get('h1') 23 | .should('have.text', 'Welcome to the-internet') 24 | }) 25 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_25_filterFindWithin.cy.js: -------------------------------------------------------------------------------- 1 | describe('Example to demonstrate filter, find and within commands in cypress', () => { 2 | 3 | it('Using filter with selector', { tags: 'regression' }, function () { 4 | cy.visit('/') 5 | cy.loginOrangeCRM('Admin', 'admin123') 6 | cy.get('.legendColorBox', { timeout: 7000 }).should('be.visible') 7 | cy.get('td').filter('.legendLabel').eq(1).should('have.text', 'Administration') 8 | }) 9 | 10 | it('Using filter with innerText', function () { 11 | cy.visit('/') 12 | cy.loginOrangeCRM('Admin', 'admin123') 13 | cy.get('.legendColorBox', { timeout: 7000 }).should('be.visible') 14 | cy.get('td').filter(':contains("Client Services")').should('have.text', 'Client Services') 15 | }) 16 | 17 | it('Using find', function () { 18 | cy.visit('https://testautomationpractice.blogspot.com/') 19 | cy.get('empinfo').find('#1 > name').should('have.text', 'David') 20 | }) 21 | 22 | it('Using within', function () { 23 | cy.visit('/index.php/performance/addPerformanceTrackerLog/trackId/3') 24 | cy.loginOrangeCRM('Admin', 'admin123') 25 | Cypress.on('uncaught:exception', (err, runnable) => { 26 | return false 27 | }) 28 | cy.get('tr.odd').should('be.visible').within(() => { 29 | cy.get('.left').eq(0).should('have.text', 'Fiona Grace') 30 | cy.get('.left').eq(1).should('have.text', 'Project X') 31 | cy.get('.left').eq(2).should('have.text', 'Worked long hours to achieve t...') 32 | cy.get('.left').eq(3).should('have.text', 'Positive') 33 | cy.get('.left').eq(4).should('have.text', '2020-10-09') 34 | }) 35 | }) 36 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_26_jqueryCommands.cy.js: -------------------------------------------------------------------------------- 1 | describe('Example to demonstrate commonly used JQuery commands in cypress', () => { 2 | 3 | it('Check if a button is disabled or enabled', { tags: 'smoke' }, function () { 4 | cy.visit('https://getbootstrap.com/docs/4.0/components/buttons/#disabled-state') 5 | cy.get('button.btn.btn-lg.btn-primary').eq(2).then(($btn) => { 6 | if ($btn.is(':disabled')) { cy.log('Button is disabled') } 7 | else { cy.log('Button is enabled') } 8 | }) 9 | cy.get('button.btn.btn-lg.btn-primary').eq(1).then(($btn) => { 10 | if ($btn.is(':enabled')) { cy.log('Button is enabled') } 11 | else { cy.log('Button is disabled') } 12 | }) 13 | }) 14 | 15 | it('Remove the disabled attribute and validate that button is enabled now', function () { 16 | cy.get('button.btn.btn-lg.btn-primary').eq(2).then(($btn) => { 17 | cy.wrap($btn.removeAttr('disabled')).should('be.enabled') 18 | }) 19 | }) 20 | 21 | it('Assert inner text', function () { 22 | cy.visit('https://testautomationpractice.blogspot.com/') 23 | cy.get('h2.title').eq(0).then(($ele) => { 24 | expect($ele.text()).to.equal('New Windows') 25 | }) 26 | }) 27 | 28 | it('Assert value', function () { 29 | cy.get('input#field1').eq(0).then(($ele) => { 30 | expect($ele.val()).to.equal('Hello World!') 31 | }) 32 | }) 33 | 34 | it('Assert the value of an attribute', function () { 35 | cy.get('#HTML7').then(($ele) => { 36 | expect($ele.attr('data-version')).to.equal('1') 37 | }) 38 | }) 39 | 40 | it('Assert CSS property', function () { 41 | cy.visit('https://the-internet.herokuapp.com/tables') 42 | cy.get('table#table1').then(($ele) => { 43 | expect($ele.css('margin-bottom')).to.equal('20px') 44 | }) 45 | }) 46 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_27_cypressRecursion.cy.js: -------------------------------------------------------------------------------- 1 | import { recurse } from 'cypress-recurse' 2 | 3 | describe('Example to demonstrate recursion in Cypress', { tags: 'smoke' }, () => { 4 | it('Validate the number 3 using recursion', function () { 5 | cy.visit('https://alapanme.github.io/random-number.html') 6 | recurse( 7 | () => { 8 | cy.reload() 9 | return cy.get('#myNumber').invoke('text').then(parseInt) 10 | }, 11 | (x) => x === 3, 12 | { 13 | log: false, 14 | timeout: 7000, // try up to 7 seconds 15 | limit: 20, // try up to 20 times 16 | delay: 50 // delay before next iteration, ms 17 | } 18 | ).should('equal', 3) 19 | }) 20 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_28_basicAuth.cy.js: -------------------------------------------------------------------------------- 1 | describe('Example to demonstrate handling of Basic Auth in Cypress', () => { 2 | 3 | it('Successfully login by appending username and password in URL', function () { 4 | cy.visit('https://admin:admin@the-internet.herokuapp.com/basic_auth') 5 | cy.get('p').should('include.text', 'Congratulations! You must have the proper credentials.') 6 | }) 7 | 8 | it('Successfully login using headers', function () { 9 | cy.visit("https://the-internet.herokuapp.com/basic_auth", { 10 | headers: { 11 | authorization: 'Basic YWRtaW46YWRtaW4=' 12 | }, 13 | failOnStatusCode: false 14 | }) 15 | cy.get('p').should('include.text', 'Congratulations! You must have the proper credentials.') 16 | }) 17 | }) -------------------------------------------------------------------------------- /cypress/e2e/TC_29_cypressRecorder.cy.js: -------------------------------------------------------------------------------- 1 | describe('Example to Demonstrate Cypress Recorder by Deploy Sentinel', () => { 2 | 3 | it('Written with DeploySentinel Recorder', () => { 4 | // Load "https://opensource-demo.orangehrmlive.com/index.php/dashboard" 5 | cy.visit('https://opensource-demo.orangehrmlive.com/index.php/dashboard'); 6 | 7 | // Resize window to 1000 x 660 8 | cy.viewport(1000, 660); 9 | 10 | // Click on #txtUsername 11 | cy.get('#txtUsername').click(); 12 | 13 | // Fill "Admin" on #txtUsername 14 | cy.get('#txtUsername').type("Admin"); 15 | 16 | // Click on #txtPassword 17 | cy.get('#txtPassword').click(); 18 | 19 | // Fill "admin123" on #txtPassword 20 | cy.get('#txtPassword').type("admin123"); 21 | 22 | // Click on #btnLogin 23 | cy.get('#btnLogin').click(); 24 | 25 | // Click on "Welcome Paul" 26 | cy.get('#welcome').click(); 27 | 28 | // Click on "Logout" 29 | cy.get('[href="/index.php/auth/logout"]').click(); 30 | }); 31 | }) -------------------------------------------------------------------------------- /cypress/e2e/cucumber-test/login.feature: -------------------------------------------------------------------------------- 1 | Feature: Login 2 | 3 | Scenario Outline: Login to Orange CRM Website 4 | 5 | Given User is at the login page 6 | When User enters username as '' and password as '' 7 | And User clicks on login button 8 | Then User is able to successfully login to the Website 9 | Examples: 10 | | username | password | 11 | | Admin | admin123 | 12 | -------------------------------------------------------------------------------- /cypress/e2e/cucumber-test/login/login.js: -------------------------------------------------------------------------------- 1 | import { Given, When, Then, And } from "@badeball/cypress-cucumber-preprocessor" 2 | 3 | Given('User is at the login page', () => { 4 | cy.visit('https://opensource-demo.orangehrmlive.com/') 5 | }) 6 | 7 | When('User enters username as {string} and password as {string}', (username, password) => { 8 | cy.get('#txtUsername').type(username) 9 | cy.get('#txtPassword').type(password) 10 | }) 11 | 12 | And('User clicks on login button', () => { 13 | cy.get('#btnLogin').click() 14 | }) 15 | 16 | Then('User is able to successfully login to the Website', () => { 17 | cy.get('#welcome').should('be.visible', {timeout: 10000}) 18 | }) -------------------------------------------------------------------------------- /cypress/e2e/examples/actions.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Actions', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io/commands/actions') 6 | }) 7 | 8 | // https://on.cypress.io/interacting-with-elements 9 | 10 | it('.type() - type into a DOM element', () => { 11 | // https://on.cypress.io/type 12 | cy.get('.action-email') 13 | .type('fake@email.com').should('have.value', 'fake@email.com') 14 | 15 | // .type() with special character sequences 16 | .type('{leftarrow}{rightarrow}{uparrow}{downarrow}') 17 | .type('{del}{selectall}{backspace}') 18 | 19 | // .type() with key modifiers 20 | .type('{alt}{option}') //these are equivalent 21 | .type('{ctrl}{control}') //these are equivalent 22 | .type('{meta}{command}{cmd}') //these are equivalent 23 | .type('{shift}') 24 | 25 | // Delay each keypress by 0.1 sec 26 | .type('slow.typing@email.com', { delay: 100 }) 27 | .should('have.value', 'slow.typing@email.com') 28 | 29 | cy.get('.action-disabled') 30 | // Ignore error checking prior to type 31 | // like whether the input is visible or disabled 32 | .type('disabled error checking', { force: true }) 33 | .should('have.value', 'disabled error checking') 34 | }) 35 | 36 | it('.focus() - focus on a DOM element', () => { 37 | // https://on.cypress.io/focus 38 | cy.get('.action-focus').focus() 39 | .should('have.class', 'focus') 40 | .prev().should('have.attr', 'style', 'color: orange;') 41 | }) 42 | 43 | it('.blur() - blur off a DOM element', () => { 44 | // https://on.cypress.io/blur 45 | cy.get('.action-blur').type('About to blur').blur() 46 | .should('have.class', 'error') 47 | .prev().should('have.attr', 'style', 'color: red;') 48 | }) 49 | 50 | it('.clear() - clears an input or textarea element', () => { 51 | // https://on.cypress.io/clear 52 | cy.get('.action-clear').type('Clear this text') 53 | .should('have.value', 'Clear this text') 54 | .clear() 55 | .should('have.value', '') 56 | }) 57 | 58 | it('.submit() - submit a form', () => { 59 | // https://on.cypress.io/submit 60 | cy.get('.action-form') 61 | .find('[type="text"]').type('HALFOFF') 62 | 63 | cy.get('.action-form').submit() 64 | .next().should('contain', 'Your form has been submitted!') 65 | }) 66 | 67 | it('.click() - click on a DOM element', () => { 68 | // https://on.cypress.io/click 69 | cy.get('.action-btn').click() 70 | 71 | // You can click on 9 specific positions of an element: 72 | // ----------------------------------- 73 | // | topLeft top topRight | 74 | // | | 75 | // | | 76 | // | | 77 | // | left center right | 78 | // | | 79 | // | | 80 | // | | 81 | // | bottomLeft bottom bottomRight | 82 | // ----------------------------------- 83 | 84 | // clicking in the center of the element is the default 85 | cy.get('#action-canvas').click() 86 | 87 | cy.get('#action-canvas').click('topLeft') 88 | cy.get('#action-canvas').click('top') 89 | cy.get('#action-canvas').click('topRight') 90 | cy.get('#action-canvas').click('left') 91 | cy.get('#action-canvas').click('right') 92 | cy.get('#action-canvas').click('bottomLeft') 93 | cy.get('#action-canvas').click('bottom') 94 | cy.get('#action-canvas').click('bottomRight') 95 | 96 | // .click() accepts an x and y coordinate 97 | // that controls where the click occurs :) 98 | 99 | cy.get('#action-canvas') 100 | .click(80, 75) // click 80px on x coord and 75px on y coord 101 | .click(170, 75) 102 | .click(80, 165) 103 | .click(100, 185) 104 | .click(125, 190) 105 | .click(150, 185) 106 | .click(170, 165) 107 | 108 | // click multiple elements by passing multiple: true 109 | cy.get('.action-labels>.label').click({ multiple: true }) 110 | 111 | // Ignore error checking prior to clicking 112 | cy.get('.action-opacity>.btn').click({ force: true }) 113 | }) 114 | 115 | it('.dblclick() - double click on a DOM element', () => { 116 | // https://on.cypress.io/dblclick 117 | 118 | // Our app has a listener on 'dblclick' event in our 'scripts.js' 119 | // that hides the div and shows an input on double click 120 | cy.get('.action-div').dblclick().should('not.be.visible') 121 | cy.get('.action-input-hidden').should('be.visible') 122 | }) 123 | 124 | it('.rightclick() - right click on a DOM element', () => { 125 | // https://on.cypress.io/rightclick 126 | 127 | // Our app has a listener on 'contextmenu' event in our 'scripts.js' 128 | // that hides the div and shows an input on right click 129 | cy.get('.rightclick-action-div').rightclick().should('not.be.visible') 130 | cy.get('.rightclick-action-input-hidden').should('be.visible') 131 | }) 132 | 133 | it('.check() - check a checkbox or radio element', () => { 134 | // https://on.cypress.io/check 135 | 136 | // By default, .check() will check all 137 | // matching checkbox or radio elements in succession, one after another 138 | cy.get('.action-checkboxes [type="checkbox"]').not('[disabled]') 139 | .check().should('be.checked') 140 | 141 | cy.get('.action-radios [type="radio"]').not('[disabled]') 142 | .check().should('be.checked') 143 | 144 | // .check() accepts a value argument 145 | cy.get('.action-radios [type="radio"]') 146 | .check('radio1').should('be.checked') 147 | 148 | // .check() accepts an array of values 149 | cy.get('.action-multiple-checkboxes [type="checkbox"]') 150 | .check(['checkbox1', 'checkbox2']).should('be.checked') 151 | 152 | // Ignore error checking prior to checking 153 | cy.get('.action-checkboxes [disabled]') 154 | .check({ force: true }).should('be.checked') 155 | 156 | cy.get('.action-radios [type="radio"]') 157 | .check('radio3', { force: true }).should('be.checked') 158 | }) 159 | 160 | it('.uncheck() - uncheck a checkbox element', () => { 161 | // https://on.cypress.io/uncheck 162 | 163 | // By default, .uncheck() will uncheck all matching 164 | // checkbox elements in succession, one after another 165 | cy.get('.action-check [type="checkbox"]') 166 | .not('[disabled]') 167 | .uncheck().should('not.be.checked') 168 | 169 | // .uncheck() accepts a value argument 170 | cy.get('.action-check [type="checkbox"]') 171 | .check('checkbox1') 172 | .uncheck('checkbox1').should('not.be.checked') 173 | 174 | // .uncheck() accepts an array of values 175 | cy.get('.action-check [type="checkbox"]') 176 | .check(['checkbox1', 'checkbox3']) 177 | .uncheck(['checkbox1', 'checkbox3']).should('not.be.checked') 178 | 179 | // Ignore error checking prior to unchecking 180 | cy.get('.action-check [disabled]') 181 | .uncheck({ force: true }).should('not.be.checked') 182 | }) 183 | 184 | it('.select() - select an option in a element', () => { 185 | // https://on.cypress.io/select 186 | 187 | // at first, no option should be selected 188 | cy.get('.action-select') 189 | .should('have.value', '--Select a fruit--') 190 | 191 | // Select option(s) with matching text content 192 | cy.get('.action-select').select('apples') 193 | // confirm the apples were selected 194 | // note that each value starts with "fr-" in our HTML 195 | cy.get('.action-select').should('have.value', 'fr-apples') 196 | 197 | cy.get('.action-select-multiple') 198 | .select(['apples', 'oranges', 'bananas']) 199 | // when getting multiple values, invoke "val" method first 200 | .invoke('val') 201 | .should('deep.equal', ['fr-apples', 'fr-oranges', 'fr-bananas']) 202 | 203 | // Select option(s) with matching value 204 | cy.get('.action-select').select('fr-bananas') 205 | // can attach an assertion right away to the element 206 | .should('have.value', 'fr-bananas') 207 | 208 | cy.get('.action-select-multiple') 209 | .select(['fr-apples', 'fr-oranges', 'fr-bananas']) 210 | .invoke('val') 211 | .should('deep.equal', ['fr-apples', 'fr-oranges', 'fr-bananas']) 212 | 213 | // assert the selected values include oranges 214 | cy.get('.action-select-multiple') 215 | .invoke('val').should('include', 'fr-oranges') 216 | }) 217 | 218 | it('.scrollIntoView() - scroll an element into view', () => { 219 | // https://on.cypress.io/scrollintoview 220 | 221 | // normally all of these buttons are hidden, 222 | // because they're not within 223 | // the viewable area of their parent 224 | // (we need to scroll to see them) 225 | cy.get('#scroll-horizontal button') 226 | .should('not.be.visible') 227 | 228 | // scroll the button into view, as if the user had scrolled 229 | cy.get('#scroll-horizontal button').scrollIntoView() 230 | .should('be.visible') 231 | 232 | cy.get('#scroll-vertical button') 233 | .should('not.be.visible') 234 | 235 | // Cypress handles the scroll direction needed 236 | cy.get('#scroll-vertical button').scrollIntoView() 237 | .should('be.visible') 238 | 239 | cy.get('#scroll-both button') 240 | .should('not.be.visible') 241 | 242 | // Cypress knows to scroll to the right and down 243 | cy.get('#scroll-both button').scrollIntoView() 244 | .should('be.visible') 245 | }) 246 | 247 | it('.trigger() - trigger an event on a DOM element', () => { 248 | // https://on.cypress.io/trigger 249 | 250 | // To interact with a range input (slider) 251 | // we need to set its value & trigger the 252 | // event to signal it changed 253 | 254 | // Here, we invoke jQuery's val() method to set 255 | // the value and trigger the 'change' event 256 | cy.get('.trigger-input-range') 257 | .invoke('val', 25) 258 | .trigger('change') 259 | .get('input[type=range]').siblings('p') 260 | .should('have.text', '25') 261 | }) 262 | 263 | it('cy.scrollTo() - scroll the window or element to a position', () => { 264 | // https://on.cypress.io/scrollTo 265 | 266 | // You can scroll to 9 specific positions of an element: 267 | // ----------------------------------- 268 | // | topLeft top topRight | 269 | // | | 270 | // | | 271 | // | | 272 | // | left center right | 273 | // | | 274 | // | | 275 | // | | 276 | // | bottomLeft bottom bottomRight | 277 | // ----------------------------------- 278 | 279 | // if you chain .scrollTo() off of cy, we will 280 | // scroll the entire window 281 | cy.scrollTo('bottom') 282 | 283 | cy.get('#scrollable-horizontal').scrollTo('right') 284 | 285 | // or you can scroll to a specific coordinate: 286 | // (x axis, y axis) in pixels 287 | cy.get('#scrollable-vertical').scrollTo(250, 250) 288 | 289 | // or you can scroll to a specific percentage 290 | // of the (width, height) of the element 291 | cy.get('#scrollable-both').scrollTo('75%', '25%') 292 | 293 | // control the easing of the scroll (default is 'swing') 294 | cy.get('#scrollable-vertical').scrollTo('center', { easing: 'linear' }) 295 | 296 | // control the duration of the scroll (in ms) 297 | cy.get('#scrollable-both').scrollTo('center', { duration: 2000 }) 298 | }) 299 | }) 300 | -------------------------------------------------------------------------------- /cypress/e2e/examples/aliasing.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Aliasing', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io/commands/aliasing') 6 | }) 7 | 8 | it('.as() - alias a DOM element for later use', () => { 9 | // https://on.cypress.io/as 10 | 11 | // Alias a DOM element for use later 12 | // We don't have to traverse to the element 13 | // later in our code, we reference it with @ 14 | 15 | cy.get('.as-table').find('tbody>tr') 16 | .first().find('td').first() 17 | .find('button').as('firstBtn') 18 | 19 | // when we reference the alias, we place an 20 | // @ in front of its name 21 | cy.get('@firstBtn').click() 22 | 23 | cy.get('@firstBtn') 24 | .should('have.class', 'btn-success') 25 | .and('contain', 'Changed') 26 | }) 27 | 28 | it('.as() - alias a route for later use', () => { 29 | // Alias the route to wait for its response 30 | cy.server() 31 | cy.route('GET', 'comments/*').as('getComment') 32 | 33 | // we have code that gets a comment when 34 | // the button is clicked in scripts.js 35 | cy.get('.network-btn').click() 36 | 37 | // https://on.cypress.io/wait 38 | cy.wait('@getComment').its('status').should('eq', 200) 39 | }) 40 | }) 41 | -------------------------------------------------------------------------------- /cypress/e2e/examples/assertions.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Assertions', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io/commands/assertions') 6 | }) 7 | 8 | describe('Implicit Assertions', () => { 9 | it('.should() - make an assertion about the current subject', () => { 10 | // https://on.cypress.io/should 11 | cy.get('.assertion-table') 12 | .find('tbody tr:last') 13 | .should('have.class', 'success') 14 | .find('td') 15 | .first() 16 | // checking the text of the element in various ways 17 | .should('have.text', 'Column content') 18 | .should('contain', 'Column content') 19 | .should('have.html', 'Column content') 20 | // chai-jquery uses "is()" to check if element matches selector 21 | .should('match', 'td') 22 | // to match text content against a regular expression 23 | // first need to invoke jQuery method text() 24 | // and then match using regular expression 25 | .invoke('text') 26 | .should('match', /column content/i) 27 | 28 | // a better way to check element's text content against a regular expression 29 | // is to use "cy.contains" 30 | // https://on.cypress.io/contains 31 | cy.get('.assertion-table') 32 | .find('tbody tr:last') 33 | // finds first element with text content matching regular expression 34 | .contains('td', /column content/i) 35 | .should('be.visible') 36 | 37 | // for more information about asserting element's text 38 | // see https://on.cypress.io/using-cypress-faq#How-do-I-get-an-element’s-text-contents 39 | }) 40 | 41 | it('.and() - chain multiple assertions together', () => { 42 | // https://on.cypress.io/and 43 | cy.get('.assertions-link') 44 | .should('have.class', 'active') 45 | .and('have.attr', 'href') 46 | .and('include', 'cypress.io') 47 | }) 48 | }) 49 | 50 | describe('Explicit Assertions', () => { 51 | // https://on.cypress.io/assertions 52 | it('expect - make an assertion about a specified subject', () => { 53 | // We can use Chai's BDD style assertions 54 | expect(true).to.be.true 55 | const o = { foo: 'bar' } 56 | 57 | expect(o).to.equal(o) 58 | expect(o).to.deep.equal({ foo: 'bar' }) 59 | // matching text using regular expression 60 | expect('FooBar').to.match(/bar$/i) 61 | }) 62 | 63 | it('pass your own callback function to should()', () => { 64 | // Pass a function to should that can have any number 65 | // of explicit assertions within it. 66 | // The ".should(cb)" function will be retried 67 | // automatically until it passes all your explicit assertions or times out. 68 | cy.get('.assertions-p') 69 | .find('p') 70 | .should(($p) => { 71 | // https://on.cypress.io/$ 72 | // return an array of texts from all of the p's 73 | // @ts-ignore TS6133 unused variable 74 | const texts = $p.map((i, el) => Cypress.$(el).text()) 75 | 76 | // jquery map returns jquery object 77 | // and .get() convert this to simple array 78 | const paragraphs = texts.get() 79 | 80 | // array should have length of 3 81 | expect(paragraphs, 'has 3 paragraphs').to.have.length(3) 82 | 83 | // use second argument to expect(...) to provide clear 84 | // message with each assertion 85 | expect(paragraphs, 'has expected text in each paragraph').to.deep.eq([ 86 | 'Some text from first p', 87 | 'More text from second p', 88 | 'And even more text from third p', 89 | ]) 90 | }) 91 | }) 92 | 93 | it('finds element by class name regex', () => { 94 | cy.get('.docs-header') 95 | .find('div') 96 | // .should(cb) callback function will be retried 97 | .should(($div) => { 98 | expect($div).to.have.length(1) 99 | 100 | const className = $div[0].className 101 | 102 | expect(className).to.match(/heading-/) 103 | }) 104 | // .then(cb) callback is not retried, 105 | // it either passes or fails 106 | .then(($div) => { 107 | expect($div, 'text content').to.have.text('Introduction') 108 | }) 109 | }) 110 | 111 | it('can throw any error', () => { 112 | cy.get('.docs-header') 113 | .find('div') 114 | .should(($div) => { 115 | if ($div.length !== 1) { 116 | // you can throw your own errors 117 | throw new Error('Did not find 1 element') 118 | } 119 | 120 | const className = $div[0].className 121 | 122 | if (!className.match(/heading-/)) { 123 | throw new Error(`Could not find class "heading-" in ${className}`) 124 | } 125 | }) 126 | }) 127 | 128 | it('matches unknown text between two elements', () => { 129 | /** 130 | * Text from the first element. 131 | * @type {string} 132 | */ 133 | let text 134 | 135 | /** 136 | * Normalizes passed text, 137 | * useful before comparing text with spaces and different capitalization. 138 | * @param {string} s Text to normalize 139 | */ 140 | const normalizeText = (s) => s.replace(/\s/g, '').toLowerCase() 141 | 142 | cy.get('.two-elements') 143 | .find('.first') 144 | .then(($first) => { 145 | // save text from the first element 146 | text = normalizeText($first.text()) 147 | }) 148 | 149 | cy.get('.two-elements') 150 | .find('.second') 151 | .should(($div) => { 152 | // we can massage text before comparing 153 | const secondText = normalizeText($div.text()) 154 | 155 | expect(secondText, 'second text').to.equal(text) 156 | }) 157 | }) 158 | 159 | it('assert - assert shape of an object', () => { 160 | const person = { 161 | name: 'Joe', 162 | age: 20, 163 | } 164 | 165 | assert.isObject(person, 'value is object') 166 | }) 167 | 168 | it('retries the should callback until assertions pass', () => { 169 | cy.get('#random-number') 170 | .should(($div) => { 171 | const n = parseFloat($div.text()) 172 | 173 | expect(n).to.be.gte(1).and.be.lte(10) 174 | }) 175 | }) 176 | }) 177 | }) 178 | -------------------------------------------------------------------------------- /cypress/e2e/examples/connectors.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Connectors', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io/commands/connectors') 6 | }) 7 | 8 | it('.each() - iterate over an array of elements', () => { 9 | // https://on.cypress.io/each 10 | cy.get('.connectors-each-ul>li') 11 | .each(($el, index, $list) => { 12 | console.log($el, index, $list) 13 | }) 14 | }) 15 | 16 | it('.its() - get properties on the current subject', () => { 17 | // https://on.cypress.io/its 18 | cy.get('.connectors-its-ul>li') 19 | // calls the 'length' property yielding that value 20 | .its('length') 21 | .should('be.gt', 2) 22 | }) 23 | 24 | it('.invoke() - invoke a function on the current subject', () => { 25 | // our div is hidden in our script.js 26 | // $('.connectors-div').hide() 27 | 28 | // https://on.cypress.io/invoke 29 | cy.get('.connectors-div').should('be.hidden') 30 | // call the jquery method 'show' on the 'div.container' 31 | .invoke('show') 32 | .should('be.visible') 33 | }) 34 | 35 | it('.spread() - spread an array as individual args to callback function', () => { 36 | // https://on.cypress.io/spread 37 | const arr = ['foo', 'bar', 'baz'] 38 | 39 | cy.wrap(arr).spread((foo, bar, baz) => { 40 | expect(foo).to.eq('foo') 41 | expect(bar).to.eq('bar') 42 | expect(baz).to.eq('baz') 43 | }) 44 | }) 45 | 46 | describe('.then()', () => { 47 | it('invokes a callback function with the current subject', () => { 48 | // https://on.cypress.io/then 49 | cy.get('.connectors-list > li') 50 | .then(($lis) => { 51 | expect($lis, '3 items').to.have.length(3) 52 | expect($lis.eq(0), 'first item').to.contain('Walk the dog') 53 | expect($lis.eq(1), 'second item').to.contain('Feed the cat') 54 | expect($lis.eq(2), 'third item').to.contain('Write JavaScript') 55 | }) 56 | }) 57 | 58 | it('yields the returned value to the next command', () => { 59 | cy.wrap(1) 60 | .then((num) => { 61 | expect(num).to.equal(1) 62 | 63 | return 2 64 | }) 65 | .then((num) => { 66 | expect(num).to.equal(2) 67 | }) 68 | }) 69 | 70 | it('yields the original subject without return', () => { 71 | cy.wrap(1) 72 | .then((num) => { 73 | expect(num).to.equal(1) 74 | // note that nothing is returned from this callback 75 | }) 76 | .then((num) => { 77 | // this callback receives the original unchanged value 1 78 | expect(num).to.equal(1) 79 | }) 80 | }) 81 | 82 | it('yields the value yielded by the last Cypress command inside', () => { 83 | cy.wrap(1) 84 | .then((num) => { 85 | expect(num).to.equal(1) 86 | // note how we run a Cypress command 87 | // the result yielded by this Cypress command 88 | // will be passed to the second ".then" 89 | cy.wrap(2) 90 | }) 91 | .then((num) => { 92 | // this callback receives the value yielded by "cy.wrap(2)" 93 | expect(num).to.equal(2) 94 | }) 95 | }) 96 | }) 97 | }) 98 | -------------------------------------------------------------------------------- /cypress/e2e/examples/cookies.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Cookies', () => { 4 | beforeEach(() => { 5 | Cypress.Cookies.debug(true) 6 | 7 | cy.visit('https://example.cypress.io/commands/cookies') 8 | 9 | // clear cookies again after visiting to remove 10 | // any 3rd party cookies picked up such as cloudflare 11 | cy.clearCookies() 12 | }) 13 | 14 | it('cy.getCookie() - get a browser cookie', () => { 15 | // https://on.cypress.io/getcookie 16 | cy.get('#getCookie .set-a-cookie').click() 17 | 18 | // cy.getCookie() yields a cookie object 19 | cy.getCookie('token').should('have.property', 'value', '123ABC') 20 | }) 21 | 22 | it('cy.getCookies() - get browser cookies', () => { 23 | // https://on.cypress.io/getcookies 24 | cy.getCookies().should('be.empty') 25 | 26 | cy.get('#getCookies .set-a-cookie').click() 27 | 28 | // cy.getCookies() yields an array of cookies 29 | cy.getCookies().should('have.length', 1).should((cookies) => { 30 | // each cookie has these properties 31 | expect(cookies[0]).to.have.property('name', 'token') 32 | expect(cookies[0]).to.have.property('value', '123ABC') 33 | expect(cookies[0]).to.have.property('httpOnly', false) 34 | expect(cookies[0]).to.have.property('secure', false) 35 | expect(cookies[0]).to.have.property('domain') 36 | expect(cookies[0]).to.have.property('path') 37 | }) 38 | }) 39 | 40 | it('cy.setCookie() - set a browser cookie', () => { 41 | // https://on.cypress.io/setcookie 42 | cy.getCookies().should('be.empty') 43 | 44 | cy.setCookie('foo', 'bar') 45 | 46 | // cy.getCookie() yields a cookie object 47 | cy.getCookie('foo').should('have.property', 'value', 'bar') 48 | }) 49 | 50 | it('cy.clearCookie() - clear a browser cookie', () => { 51 | // https://on.cypress.io/clearcookie 52 | cy.getCookie('token').should('be.null') 53 | 54 | cy.get('#clearCookie .set-a-cookie').click() 55 | 56 | cy.getCookie('token').should('have.property', 'value', '123ABC') 57 | 58 | // cy.clearCookies() yields null 59 | cy.clearCookie('token').should('be.null') 60 | 61 | cy.getCookie('token').should('be.null') 62 | }) 63 | 64 | it('cy.clearCookies() - clear browser cookies', () => { 65 | // https://on.cypress.io/clearcookies 66 | cy.getCookies().should('be.empty') 67 | 68 | cy.get('#clearCookies .set-a-cookie').click() 69 | 70 | cy.getCookies().should('have.length', 1) 71 | 72 | // cy.clearCookies() yields null 73 | cy.clearCookies() 74 | 75 | cy.getCookies().should('be.empty') 76 | }) 77 | }) 78 | -------------------------------------------------------------------------------- /cypress/e2e/examples/cypress_api.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Cypress.Commands', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io/cypress-api') 6 | }) 7 | 8 | // https://on.cypress.io/custom-commands 9 | 10 | it('.add() - create a custom command', () => { 11 | Cypress.Commands.add('console', { 12 | prevSubject: true, 13 | }, (subject, method) => { 14 | // the previous subject is automatically received 15 | // and the commands arguments are shifted 16 | 17 | // allow us to change the console method used 18 | method = method || 'log' 19 | 20 | // log the subject to the console 21 | // @ts-ignore TS7017 22 | console[method]('The subject is', subject) 23 | 24 | // whatever we return becomes the new subject 25 | // we don't want to change the subject so 26 | // we return whatever was passed in 27 | return subject 28 | }) 29 | 30 | // @ts-ignore TS2339 31 | cy.get('button').console('info').then(($button) => { 32 | // subject is still $button 33 | }) 34 | }) 35 | }) 36 | 37 | context('Cypress.Cookies', () => { 38 | beforeEach(() => { 39 | cy.visit('https://example.cypress.io/cypress-api') 40 | }) 41 | 42 | // https://on.cypress.io/cookies 43 | it('.debug() - enable or disable debugging', () => { 44 | Cypress.Cookies.debug(true) 45 | 46 | // Cypress will now log in the console when 47 | // cookies are set or cleared 48 | cy.setCookie('fakeCookie', '123ABC') 49 | cy.clearCookie('fakeCookie') 50 | cy.setCookie('fakeCookie', '123ABC') 51 | cy.clearCookie('fakeCookie') 52 | cy.setCookie('fakeCookie', '123ABC') 53 | }) 54 | 55 | it('.preserveOnce() - preserve cookies by key', () => { 56 | // normally cookies are reset after each test 57 | cy.getCookie('fakeCookie').should('not.be.ok') 58 | 59 | // preserving a cookie will not clear it when 60 | // the next test starts 61 | cy.setCookie('lastCookie', '789XYZ') 62 | Cypress.Cookies.preserveOnce('lastCookie') 63 | }) 64 | 65 | it('.defaults() - set defaults for all cookies', () => { 66 | // now any cookie with the name 'session_id' will 67 | // not be cleared before each new test runs 68 | Cypress.Cookies.defaults({ 69 | whitelist: 'session_id', 70 | }) 71 | }) 72 | }) 73 | 74 | context('Cypress.Server', () => { 75 | beforeEach(() => { 76 | cy.visit('https://example.cypress.io/cypress-api') 77 | }) 78 | 79 | // Permanently override server options for 80 | // all instances of cy.server() 81 | 82 | // https://on.cypress.io/cypress-server 83 | it('.defaults() - change default config of server', () => { 84 | Cypress.Server.defaults({ 85 | delay: 0, 86 | force404: false, 87 | }) 88 | }) 89 | }) 90 | 91 | context('Cypress.arch', () => { 92 | beforeEach(() => { 93 | cy.visit('https://example.cypress.io/cypress-api') 94 | }) 95 | 96 | it('Get CPU architecture name of underlying OS', () => { 97 | // https://on.cypress.io/arch 98 | expect(Cypress.arch).to.exist 99 | }) 100 | }) 101 | 102 | context('Cypress.config()', () => { 103 | beforeEach(() => { 104 | cy.visit('https://example.cypress.io/cypress-api') 105 | }) 106 | 107 | it('Get and set configuration options', () => { 108 | // https://on.cypress.io/config 109 | let myConfig = Cypress.config() 110 | 111 | expect(myConfig).to.have.property('animationDistanceThreshold', 5) 112 | expect(myConfig).to.have.property('baseUrl', null) 113 | expect(myConfig).to.have.property('defaultCommandTimeout', 4000) 114 | expect(myConfig).to.have.property('requestTimeout', 5000) 115 | expect(myConfig).to.have.property('responseTimeout', 30000) 116 | expect(myConfig).to.have.property('viewportHeight', 660) 117 | expect(myConfig).to.have.property('viewportWidth', 1000) 118 | expect(myConfig).to.have.property('pageLoadTimeout', 60000) 119 | expect(myConfig).to.have.property('waitForAnimations', true) 120 | 121 | expect(Cypress.config('pageLoadTimeout')).to.eq(60000) 122 | 123 | // this will change the config for the rest of your tests! 124 | Cypress.config('pageLoadTimeout', 20000) 125 | 126 | expect(Cypress.config('pageLoadTimeout')).to.eq(20000) 127 | 128 | Cypress.config('pageLoadTimeout', 60000) 129 | }) 130 | }) 131 | 132 | context('Cypress.dom', () => { 133 | beforeEach(() => { 134 | cy.visit('https://example.cypress.io/cypress-api') 135 | }) 136 | 137 | // https://on.cypress.io/dom 138 | it('.isHidden() - determine if a DOM element is hidden', () => { 139 | let hiddenP = Cypress.$('.dom-p p.hidden').get(0) 140 | let visibleP = Cypress.$('.dom-p p.visible').get(0) 141 | 142 | // our first paragraph has css class 'hidden' 143 | expect(Cypress.dom.isHidden(hiddenP)).to.be.true 144 | expect(Cypress.dom.isHidden(visibleP)).to.be.false 145 | }) 146 | }) 147 | 148 | context('Cypress.env()', () => { 149 | beforeEach(() => { 150 | cy.visit('https://example.cypress.io/cypress-api') 151 | }) 152 | 153 | // We can set environment variables for highly dynamic values 154 | 155 | // https://on.cypress.io/environment-variables 156 | it('Get environment variables', () => { 157 | // https://on.cypress.io/env 158 | // set multiple environment variables 159 | Cypress.env({ 160 | host: 'veronica.dev.local', 161 | api_server: 'http://localhost:8888/v1/', 162 | }) 163 | 164 | // get environment variable 165 | expect(Cypress.env('host')).to.eq('veronica.dev.local') 166 | 167 | // set environment variable 168 | Cypress.env('api_server', 'http://localhost:8888/v2/') 169 | expect(Cypress.env('api_server')).to.eq('http://localhost:8888/v2/') 170 | 171 | // get all environment variable 172 | expect(Cypress.env()).to.have.property('host', 'veronica.dev.local') 173 | expect(Cypress.env()).to.have.property('api_server', 'http://localhost:8888/v2/') 174 | }) 175 | }) 176 | 177 | context('Cypress.log', () => { 178 | beforeEach(() => { 179 | cy.visit('https://example.cypress.io/cypress-api') 180 | }) 181 | 182 | it('Control what is printed to the Command Log', () => { 183 | // https://on.cypress.io/cypress-log 184 | }) 185 | }) 186 | 187 | context('Cypress.platform', () => { 188 | beforeEach(() => { 189 | cy.visit('https://example.cypress.io/cypress-api') 190 | }) 191 | 192 | it('Get underlying OS name', () => { 193 | // https://on.cypress.io/platform 194 | expect(Cypress.platform).to.be.exist 195 | }) 196 | }) 197 | 198 | context('Cypress.version', () => { 199 | beforeEach(() => { 200 | cy.visit('https://example.cypress.io/cypress-api') 201 | }) 202 | 203 | it('Get current version of Cypress being run', () => { 204 | // https://on.cypress.io/version 205 | expect(Cypress.version).to.be.exist 206 | }) 207 | }) 208 | 209 | context('Cypress.spec', () => { 210 | beforeEach(() => { 211 | cy.visit('https://example.cypress.io/cypress-api') 212 | }) 213 | 214 | it('Get current spec information', () => { 215 | // https://on.cypress.io/spec 216 | // wrap the object so we can inspect it easily by clicking in the command log 217 | cy.wrap(Cypress.spec).should('include.keys', ['name', 'relative', 'absolute']) 218 | }) 219 | }) 220 | -------------------------------------------------------------------------------- /cypress/e2e/examples/files.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// JSON fixture file can be loaded directly using 4 | // the built-in JavaScript bundler 5 | // @ts-ignore 6 | const requiredExample = require('../../fixtures/example') 7 | 8 | context('Files', () => { 9 | beforeEach(() => { 10 | cy.visit('https://example.cypress.io/commands/files') 11 | }) 12 | 13 | beforeEach(() => { 14 | // load example.json fixture file and store 15 | // in the test context object 16 | cy.fixture('example.json').as('example') 17 | }) 18 | 19 | it('cy.fixture() - load a fixture', () => { 20 | // https://on.cypress.io/fixture 21 | 22 | // Instead of writing a response inline you can 23 | // use a fixture file's content. 24 | 25 | cy.server() 26 | cy.fixture('example.json').as('comment') 27 | // when application makes an Ajax request matching "GET comments/*" 28 | // Cypress will intercept it and reply with object 29 | // from the "comment" alias 30 | cy.route('GET', 'comments/*', '@comment').as('getComment') 31 | 32 | // we have code that gets a comment when 33 | // the button is clicked in scripts.js 34 | cy.get('.fixture-btn').click() 35 | 36 | cy.wait('@getComment').its('responseBody') 37 | .should('have.property', 'name') 38 | .and('include', 'Using fixtures to represent data') 39 | 40 | // you can also just write the fixture in the route 41 | cy.route('GET', 'comments/*', 'fixture:example.json').as('getComment') 42 | 43 | // we have code that gets a comment when 44 | // the button is clicked in scripts.js 45 | cy.get('.fixture-btn').click() 46 | 47 | cy.wait('@getComment').its('responseBody') 48 | .should('have.property', 'name') 49 | .and('include', 'Using fixtures to represent data') 50 | 51 | // or write fx to represent fixture 52 | // by default it assumes it's .json 53 | cy.route('GET', 'comments/*', 'fx:example').as('getComment') 54 | 55 | // we have code that gets a comment when 56 | // the button is clicked in scripts.js 57 | cy.get('.fixture-btn').click() 58 | 59 | cy.wait('@getComment').its('responseBody') 60 | .should('have.property', 'name') 61 | .and('include', 'Using fixtures to represent data') 62 | }) 63 | 64 | it('cy.fixture() or require - load a fixture', function () { 65 | // we are inside the "function () { ... }" 66 | // callback and can use test context object "this" 67 | // "this.example" was loaded in "beforeEach" function callback 68 | expect(this.example, 'fixture in the test context') 69 | .to.deep.equal(requiredExample) 70 | 71 | // or use "cy.wrap" and "should('deep.equal', ...)" assertion 72 | // @ts-ignore 73 | cy.wrap(this.example, 'fixture vs require') 74 | .should('deep.equal', requiredExample) 75 | }) 76 | 77 | it('cy.readFile() - read file contents', () => { 78 | // https://on.cypress.io/readfile 79 | 80 | // You can read a file and yield its contents 81 | // The filePath is relative to your project's root. 82 | cy.readFile('cypress.json').then((json) => { 83 | expect(json).to.be.an('object') 84 | }) 85 | }) 86 | 87 | it('cy.writeFile() - write to a file', () => { 88 | // https://on.cypress.io/writefile 89 | 90 | // You can write to a file 91 | 92 | // Use a response from a request to automatically 93 | // generate a fixture file for use later 94 | cy.request('https://jsonplaceholder.cypress.io/users') 95 | .then((response) => { 96 | cy.writeFile('cypress/fixtures/users.json', response.body) 97 | }) 98 | 99 | cy.fixture('users').should((users) => { 100 | expect(users[0].name).to.exist 101 | }) 102 | 103 | // JavaScript arrays and objects are stringified 104 | // and formatted into text. 105 | cy.writeFile('cypress/fixtures/profile.json', { 106 | id: 8739, 107 | name: 'Jane', 108 | email: 'jane@example.com', 109 | }) 110 | 111 | cy.fixture('profile').should((profile) => { 112 | expect(profile.name).to.eq('Jane') 113 | }) 114 | }) 115 | }) 116 | -------------------------------------------------------------------------------- /cypress/e2e/examples/local_storage.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Local Storage', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io/commands/local-storage') 6 | }) 7 | // Although local storage is automatically cleared 8 | // in between tests to maintain a clean state 9 | // sometimes we need to clear the local storage manually 10 | 11 | it('cy.clearLocalStorage() - clear all data in local storage', () => { 12 | // https://on.cypress.io/clearlocalstorage 13 | cy.get('.ls-btn').click().should(() => { 14 | expect(localStorage.getItem('prop1')).to.eq('red') 15 | expect(localStorage.getItem('prop2')).to.eq('blue') 16 | expect(localStorage.getItem('prop3')).to.eq('magenta') 17 | }) 18 | 19 | // clearLocalStorage() yields the localStorage object 20 | cy.clearLocalStorage().should((ls) => { 21 | expect(ls.getItem('prop1')).to.be.null 22 | expect(ls.getItem('prop2')).to.be.null 23 | expect(ls.getItem('prop3')).to.be.null 24 | }) 25 | 26 | // Clear key matching string in Local Storage 27 | cy.get('.ls-btn').click().should(() => { 28 | expect(localStorage.getItem('prop1')).to.eq('red') 29 | expect(localStorage.getItem('prop2')).to.eq('blue') 30 | expect(localStorage.getItem('prop3')).to.eq('magenta') 31 | }) 32 | 33 | cy.clearLocalStorage('prop1').should((ls) => { 34 | expect(ls.getItem('prop1')).to.be.null 35 | expect(ls.getItem('prop2')).to.eq('blue') 36 | expect(ls.getItem('prop3')).to.eq('magenta') 37 | }) 38 | 39 | // Clear keys matching regex in Local Storage 40 | cy.get('.ls-btn').click().should(() => { 41 | expect(localStorage.getItem('prop1')).to.eq('red') 42 | expect(localStorage.getItem('prop2')).to.eq('blue') 43 | expect(localStorage.getItem('prop3')).to.eq('magenta') 44 | }) 45 | 46 | cy.clearLocalStorage(/prop1|2/).should((ls) => { 47 | expect(ls.getItem('prop1')).to.be.null 48 | expect(ls.getItem('prop2')).to.be.null 49 | expect(ls.getItem('prop3')).to.eq('magenta') 50 | }) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /cypress/e2e/examples/location.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Location', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io/commands/location') 6 | }) 7 | 8 | it('cy.hash() - get the current URL hash', () => { 9 | // https://on.cypress.io/hash 10 | cy.hash().should('be.empty') 11 | }) 12 | 13 | it('cy.location() - get window.location', () => { 14 | // https://on.cypress.io/location 15 | cy.location().should((location) => { 16 | expect(location.hash).to.be.empty 17 | expect(location.href).to.eq('https://example.cypress.io/commands/location') 18 | expect(location.host).to.eq('example.cypress.io') 19 | expect(location.hostname).to.eq('example.cypress.io') 20 | expect(location.origin).to.eq('https://example.cypress.io') 21 | expect(location.pathname).to.eq('/commands/location') 22 | expect(location.port).to.eq('') 23 | expect(location.protocol).to.eq('https:') 24 | expect(location.search).to.be.empty 25 | }) 26 | }) 27 | 28 | it('cy.url() - get the current URL', () => { 29 | // https://on.cypress.io/url 30 | cy.url().should('eq', 'https://example.cypress.io/commands/location') 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /cypress/e2e/examples/misc.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Misc', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io/commands/misc') 6 | }) 7 | 8 | it('.end() - end the command chain', () => { 9 | // https://on.cypress.io/end 10 | 11 | // cy.end is useful when you want to end a chain of commands 12 | // and force Cypress to re-query from the root element 13 | cy.get('.misc-table').within(() => { 14 | // ends the current chain and yields null 15 | cy.contains('Cheryl').click().end() 16 | 17 | // queries the entire table again 18 | cy.contains('Charles').click() 19 | }) 20 | }) 21 | 22 | it('cy.exec() - execute a system command', () => { 23 | // execute a system command. 24 | // so you can take actions necessary for 25 | // your test outside the scope of Cypress. 26 | // https://on.cypress.io/exec 27 | 28 | // we can use Cypress.platform string to 29 | // select appropriate command 30 | // https://on.cypress/io/platform 31 | cy.log(`Platform ${Cypress.platform} architecture ${Cypress.arch}`) 32 | 33 | // on CircleCI Windows build machines we have a failure to run bash shell 34 | // https://github.com/cypress-io/cypress/issues/5169 35 | // so skip some of the tests by passing flag "--env circle=true" 36 | const isCircleOnWindows = Cypress.platform === 'win32' && Cypress.env('circle') 37 | 38 | if (isCircleOnWindows) { 39 | cy.log('Skipping test on CircleCI') 40 | 41 | return 42 | } 43 | 44 | // cy.exec problem on Shippable CI 45 | // https://github.com/cypress-io/cypress/issues/6718 46 | const isShippable = Cypress.platform === 'linux' && Cypress.env('shippable') 47 | 48 | if (isShippable) { 49 | cy.log('Skipping test on ShippableCI') 50 | 51 | return 52 | } 53 | 54 | cy.exec('echo Jane Lane') 55 | .its('stdout').should('contain', 'Jane Lane') 56 | 57 | if (Cypress.platform === 'win32') { 58 | cy.exec('print cypress.json') 59 | .its('stderr').should('be.empty') 60 | } else { 61 | cy.exec('cat cypress.json') 62 | .its('stderr').should('be.empty') 63 | 64 | cy.exec('pwd') 65 | .its('code').should('eq', 0) 66 | } 67 | }) 68 | 69 | it('cy.focused() - get the DOM element that has focus', () => { 70 | // https://on.cypress.io/focused 71 | cy.get('.misc-form').find('#name').click() 72 | cy.focused().should('have.id', 'name') 73 | 74 | cy.get('.misc-form').find('#description').click() 75 | cy.focused().should('have.id', 'description') 76 | }) 77 | 78 | context('Cypress.Screenshot', function () { 79 | it('cy.screenshot() - take a screenshot', () => { 80 | // https://on.cypress.io/screenshot 81 | cy.screenshot('my-image') 82 | }) 83 | 84 | it('Cypress.Screenshot.defaults() - change default config of screenshots', function () { 85 | Cypress.Screenshot.defaults({ 86 | blackout: ['.foo'], 87 | capture: 'viewport', 88 | clip: { x: 0, y: 0, width: 200, height: 200 }, 89 | scale: false, 90 | disableTimersAndAnimations: true, 91 | screenshotOnRunFailure: true, 92 | onBeforeScreenshot () { }, 93 | onAfterScreenshot () { }, 94 | }) 95 | }) 96 | }) 97 | 98 | it('cy.wrap() - wrap an object', () => { 99 | // https://on.cypress.io/wrap 100 | cy.wrap({ foo: 'bar' }) 101 | .should('have.property', 'foo') 102 | .and('include', 'bar') 103 | }) 104 | }) 105 | -------------------------------------------------------------------------------- /cypress/e2e/examples/navigation.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Navigation', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io') 6 | cy.get('.navbar-nav').contains('Commands').click() 7 | cy.get('.dropdown-menu').contains('Navigation').click() 8 | }) 9 | 10 | it('cy.go() - go back or forward in the browser\'s history', () => { 11 | // https://on.cypress.io/go 12 | 13 | cy.location('pathname').should('include', 'navigation') 14 | 15 | cy.go('back') 16 | cy.location('pathname').should('not.include', 'navigation') 17 | 18 | cy.go('forward') 19 | cy.location('pathname').should('include', 'navigation') 20 | 21 | // clicking back 22 | cy.go(-1) 23 | cy.location('pathname').should('not.include', 'navigation') 24 | 25 | // clicking forward 26 | cy.go(1) 27 | cy.location('pathname').should('include', 'navigation') 28 | }) 29 | 30 | it('cy.reload() - reload the page', () => { 31 | // https://on.cypress.io/reload 32 | cy.reload() 33 | 34 | // reload the page without using the cache 35 | cy.reload(true) 36 | }) 37 | 38 | it('cy.visit() - visit a remote url', () => { 39 | // https://on.cypress.io/visit 40 | 41 | // Visit any sub-domain of your current domain 42 | 43 | // Pass options to the visit 44 | cy.visit('https://example.cypress.io/commands/navigation', { 45 | timeout: 50000, // increase total time for the visit to resolve 46 | onBeforeLoad (contentWindow) { 47 | // contentWindow is the remote page's window object 48 | expect(typeof contentWindow === 'object').to.be.true 49 | }, 50 | onLoad (contentWindow) { 51 | // contentWindow is the remote page's window object 52 | expect(typeof contentWindow === 'object').to.be.true 53 | }, 54 | }) 55 | }) 56 | }) 57 | -------------------------------------------------------------------------------- /cypress/e2e/examples/network_requests.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Network Requests', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io/commands/network-requests') 6 | }) 7 | 8 | // Manage AJAX / XHR requests in your app 9 | 10 | it('cy.server() - control behavior of network requests and responses', () => { 11 | // https://on.cypress.io/server 12 | 13 | cy.server().should((server) => { 14 | // the default options on server 15 | // you can override any of these options 16 | expect(server.delay).to.eq(0) 17 | expect(server.method).to.eq('GET') 18 | expect(server.status).to.eq(200) 19 | expect(server.headers).to.be.null 20 | expect(server.response).to.be.null 21 | expect(server.onRequest).to.be.undefined 22 | expect(server.onResponse).to.be.undefined 23 | expect(server.onAbort).to.be.undefined 24 | 25 | // These options control the server behavior 26 | // affecting all requests 27 | 28 | // pass false to disable existing route stubs 29 | expect(server.enable).to.be.true 30 | // forces requests that don't match your routes to 404 31 | expect(server.force404).to.be.false 32 | // whitelists requests from ever being logged or stubbed 33 | expect(server.whitelist).to.be.a('function') 34 | }) 35 | 36 | cy.server({ 37 | method: 'POST', 38 | delay: 1000, 39 | status: 422, 40 | response: {}, 41 | }) 42 | 43 | // any route commands will now inherit the above options 44 | // from the server. anything we pass specifically 45 | // to route will override the defaults though. 46 | }) 47 | 48 | it('cy.request() - make an XHR request', () => { 49 | // https://on.cypress.io/request 50 | cy.request('https://jsonplaceholder.cypress.io/comments') 51 | .should((response) => { 52 | expect(response.status).to.eq(200) 53 | // the server sometimes gets an extra comment posted from another machine 54 | // which gets returned as 1 extra object 55 | expect(response.body).to.have.property('length').and.be.oneOf([500, 501]) 56 | expect(response).to.have.property('headers') 57 | expect(response).to.have.property('duration') 58 | }) 59 | }) 60 | 61 | it('cy.request() - verify response using BDD syntax', () => { 62 | cy.request('https://jsonplaceholder.cypress.io/comments') 63 | .then((response) => { 64 | // https://on.cypress.io/assertions 65 | expect(response).property('status').to.equal(200) 66 | expect(response).property('body').to.have.property('length').and.be.oneOf([500, 501]) 67 | expect(response).to.include.keys('headers', 'duration') 68 | }) 69 | }) 70 | 71 | it('cy.request() with query parameters', () => { 72 | // will execute request 73 | // https://jsonplaceholder.cypress.io/comments?postId=1&id=3 74 | cy.request({ 75 | url: 'https://jsonplaceholder.cypress.io/comments', 76 | qs: { 77 | postId: 1, 78 | id: 3, 79 | }, 80 | }) 81 | .its('body') 82 | .should('be.an', 'array') 83 | .and('have.length', 1) 84 | .its('0') // yields first element of the array 85 | .should('contain', { 86 | postId: 1, 87 | id: 3, 88 | }) 89 | }) 90 | 91 | it('cy.request() - pass result to the second request', () => { 92 | // first, let's find out the userId of the first user we have 93 | cy.request('https://jsonplaceholder.cypress.io/users?_limit=1') 94 | .its('body') // yields the response object 95 | .its('0') // yields the first element of the returned list 96 | // the above two commands its('body').its('0') 97 | // can be written as its('body.0') 98 | // if you do not care about TypeScript checks 99 | .then((user) => { 100 | expect(user).property('id').to.be.a('number') 101 | // make a new post on behalf of the user 102 | cy.request('POST', 'https://jsonplaceholder.cypress.io/posts', { 103 | userId: user.id, 104 | title: 'Cypress Test Runner', 105 | body: 'Fast, easy and reliable testing for anything that runs in a browser.', 106 | }) 107 | }) 108 | // note that the value here is the returned value of the 2nd request 109 | // which is the new post object 110 | .then((response) => { 111 | expect(response).property('status').to.equal(201) // new entity created 112 | expect(response).property('body').to.contain({ 113 | title: 'Cypress Test Runner', 114 | }) 115 | 116 | // we don't know the exact post id - only that it will be > 100 117 | // since JSONPlaceholder has built-in 100 posts 118 | expect(response.body).property('id').to.be.a('number') 119 | .and.to.be.gt(100) 120 | 121 | // we don't know the user id here - since it was in above closure 122 | // so in this test just confirm that the property is there 123 | expect(response.body).property('userId').to.be.a('number') 124 | }) 125 | }) 126 | 127 | it('cy.request() - save response in the shared test context', () => { 128 | // https://on.cypress.io/variables-and-aliases 129 | cy.request('https://jsonplaceholder.cypress.io/users?_limit=1') 130 | .its('body').its('0') // yields the first element of the returned list 131 | .as('user') // saves the object in the test context 132 | .then(function () { 133 | // NOTE 👀 134 | // By the time this callback runs the "as('user')" command 135 | // has saved the user object in the test context. 136 | // To access the test context we need to use 137 | // the "function () { ... }" callback form, 138 | // otherwise "this" points at a wrong or undefined object! 139 | cy.request('POST', 'https://jsonplaceholder.cypress.io/posts', { 140 | userId: this.user.id, 141 | title: 'Cypress Test Runner', 142 | body: 'Fast, easy and reliable testing for anything that runs in a browser.', 143 | }) 144 | .its('body').as('post') // save the new post from the response 145 | }) 146 | .then(function () { 147 | // When this callback runs, both "cy.request" API commands have finished 148 | // and the test context has "user" and "post" objects set. 149 | // Let's verify them. 150 | expect(this.post, 'post has the right user id').property('userId').to.equal(this.user.id) 151 | }) 152 | }) 153 | 154 | it('cy.route() - route responses to matching requests', () => { 155 | // https://on.cypress.io/route 156 | 157 | let message = 'whoa, this comment does not exist' 158 | 159 | cy.server() 160 | 161 | // Listen to GET to comments/1 162 | cy.route('GET', 'comments/*').as('getComment') 163 | 164 | // we have code that gets a comment when 165 | // the button is clicked in scripts.js 166 | cy.get('.network-btn').click() 167 | 168 | // https://on.cypress.io/wait 169 | cy.wait('@getComment').its('status').should('eq', 200) 170 | 171 | // Listen to POST to comments 172 | cy.route('POST', '/comments').as('postComment') 173 | 174 | // we have code that posts a comment when 175 | // the button is clicked in scripts.js 176 | cy.get('.network-post').click() 177 | cy.wait('@postComment').should((xhr) => { 178 | expect(xhr.requestBody).to.include('email') 179 | expect(xhr.requestHeaders).to.have.property('Content-Type') 180 | expect(xhr.responseBody).to.have.property('name', 'Using POST in cy.route()') 181 | }) 182 | 183 | // Stub a response to PUT comments/ **** 184 | cy.route({ 185 | method: 'PUT', 186 | url: 'comments/*', 187 | status: 404, 188 | response: { error: message }, 189 | delay: 500, 190 | }).as('putComment') 191 | 192 | // we have code that puts a comment when 193 | // the button is clicked in scripts.js 194 | cy.get('.network-put').click() 195 | 196 | cy.wait('@putComment') 197 | 198 | // our 404 statusCode logic in scripts.js executed 199 | cy.get('.network-put-comment').should('contain', message) 200 | }) 201 | }) 202 | -------------------------------------------------------------------------------- /cypress/e2e/examples/querying.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Querying', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io/commands/querying') 6 | }) 7 | 8 | // The most commonly used query is 'cy.get()', you can 9 | // think of this like the '$' in jQuery 10 | 11 | it('cy.get() - query DOM elements', () => { 12 | // https://on.cypress.io/get 13 | 14 | cy.get('#query-btn').should('contain', 'Button') 15 | 16 | cy.get('.query-btn').should('contain', 'Button') 17 | 18 | cy.get('#querying .well>button:first').should('contain', 'Button') 19 | // ↲ 20 | // Use CSS selectors just like jQuery 21 | 22 | cy.get('[data-test-id="test-example"]').should('have.class', 'example') 23 | 24 | // 'cy.get()' yields jQuery object, you can get its attribute 25 | // by invoking `.attr()` method 26 | cy.get('[data-test-id="test-example"]') 27 | .invoke('attr', 'data-test-id') 28 | .should('equal', 'test-example') 29 | 30 | // or you can get element's CSS property 31 | cy.get('[data-test-id="test-example"]') 32 | .invoke('css', 'position') 33 | .should('equal', 'static') 34 | 35 | // or use assertions directly during 'cy.get()' 36 | // https://on.cypress.io/assertions 37 | cy.get('[data-test-id="test-example"]') 38 | .should('have.attr', 'data-test-id', 'test-example') 39 | .and('have.css', 'position', 'static') 40 | }) 41 | 42 | it('cy.contains() - query DOM elements with matching content', () => { 43 | // https://on.cypress.io/contains 44 | cy.get('.query-list') 45 | .contains('bananas') 46 | .should('have.class', 'third') 47 | 48 | // we can pass a regexp to `.contains()` 49 | cy.get('.query-list') 50 | .contains(/^b\w+/) 51 | .should('have.class', 'third') 52 | 53 | cy.get('.query-list') 54 | .contains('apples') 55 | .should('have.class', 'first') 56 | 57 | // passing a selector to contains will 58 | // yield the selector containing the text 59 | cy.get('#querying') 60 | .contains('ul', 'oranges') 61 | .should('have.class', 'query-list') 62 | 63 | cy.get('.query-button') 64 | .contains('Save Form') 65 | .should('have.class', 'btn') 66 | }) 67 | 68 | it('.within() - query DOM elements within a specific element', () => { 69 | // https://on.cypress.io/within 70 | cy.get('.query-form').within(() => { 71 | cy.get('input:first').should('have.attr', 'placeholder', 'Email') 72 | cy.get('input:last').should('have.attr', 'placeholder', 'Password') 73 | }) 74 | }) 75 | 76 | it('cy.root() - query the root DOM element', () => { 77 | // https://on.cypress.io/root 78 | 79 | // By default, root is the document 80 | cy.root().should('match', 'html') 81 | 82 | cy.get('.query-ul').within(() => { 83 | // In this within, the root is now the ul DOM element 84 | cy.root().should('have.class', 'query-ul') 85 | }) 86 | }) 87 | 88 | it('best practices - selecting elements', () => { 89 | // https://on.cypress.io/best-practices#Selecting-Elements 90 | cy.get('[data-cy=best-practices-selecting-elements]').within(() => { 91 | // Worst - too generic, no context 92 | cy.get('button').click() 93 | 94 | // Bad. Coupled to styling. Highly subject to change. 95 | cy.get('.btn.btn-large').click() 96 | 97 | // Average. Coupled to the `name` attribute which has HTML semantics. 98 | cy.get('[name=submission]').click() 99 | 100 | // Better. But still coupled to styling or JS event listeners. 101 | cy.get('#main').click() 102 | 103 | // Slightly better. Uses an ID but also ensures the element 104 | // has an ARIA role attribute 105 | cy.get('#main[role=button]').click() 106 | 107 | // Much better. But still coupled to text content that may change. 108 | cy.contains('Submit').click() 109 | 110 | // Best. Insulated from all changes. 111 | cy.get('[data-cy=submit]').click() 112 | }) 113 | }) 114 | }) 115 | -------------------------------------------------------------------------------- /cypress/e2e/examples/spies_stubs_clocks.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | // remove no check once Cypress.sinon is typed 3 | // https://github.com/cypress-io/cypress/issues/6720 4 | 5 | context('Spies, Stubs, and Clock', () => { 6 | it('cy.spy() - wrap a method in a spy', () => { 7 | // https://on.cypress.io/spy 8 | cy.visit('https://example.cypress.io/commands/spies-stubs-clocks') 9 | 10 | const obj = { 11 | foo () {}, 12 | } 13 | 14 | const spy = cy.spy(obj, 'foo').as('anyArgs') 15 | 16 | obj.foo() 17 | 18 | expect(spy).to.be.called 19 | }) 20 | 21 | it('cy.spy() retries until assertions pass', () => { 22 | cy.visit('https://example.cypress.io/commands/spies-stubs-clocks') 23 | 24 | const obj = { 25 | /** 26 | * Prints the argument passed 27 | * @param x {any} 28 | */ 29 | foo (x) { 30 | console.log('obj.foo called with', x) 31 | }, 32 | } 33 | 34 | cy.spy(obj, 'foo').as('foo') 35 | 36 | setTimeout(() => { 37 | obj.foo('first') 38 | }, 500) 39 | 40 | setTimeout(() => { 41 | obj.foo('second') 42 | }, 2500) 43 | 44 | cy.get('@foo').should('have.been.calledTwice') 45 | }) 46 | 47 | it('cy.stub() - create a stub and/or replace a function with stub', () => { 48 | // https://on.cypress.io/stub 49 | cy.visit('https://example.cypress.io/commands/spies-stubs-clocks') 50 | 51 | const obj = { 52 | /** 53 | * prints both arguments to the console 54 | * @param a {string} 55 | * @param b {string} 56 | */ 57 | foo (a, b) { 58 | console.log('a', a, 'b', b) 59 | }, 60 | } 61 | 62 | const stub = cy.stub(obj, 'foo').as('foo') 63 | 64 | obj.foo('foo', 'bar') 65 | 66 | expect(stub).to.be.called 67 | }) 68 | 69 | it('cy.clock() - control time in the browser', () => { 70 | // https://on.cypress.io/clock 71 | 72 | // create the date in UTC so its always the same 73 | // no matter what local timezone the browser is running in 74 | const now = new Date(Date.UTC(2017, 2, 14)).getTime() 75 | 76 | cy.clock(now) 77 | cy.visit('https://example.cypress.io/commands/spies-stubs-clocks') 78 | cy.get('#clock-div').click() 79 | .should('have.text', '1489449600') 80 | }) 81 | 82 | it('cy.tick() - move time in the browser', () => { 83 | // https://on.cypress.io/tick 84 | 85 | // create the date in UTC so its always the same 86 | // no matter what local timezone the browser is running in 87 | const now = new Date(Date.UTC(2017, 2, 14)).getTime() 88 | 89 | cy.clock(now) 90 | cy.visit('https://example.cypress.io/commands/spies-stubs-clocks') 91 | cy.get('#tick-div').click() 92 | .should('have.text', '1489449600') 93 | 94 | cy.tick(10000) // 10 seconds passed 95 | cy.get('#tick-div').click() 96 | .should('have.text', '1489449610') 97 | }) 98 | 99 | it('cy.stub() matches depending on arguments', () => { 100 | // see all possible matchers at 101 | // https://sinonjs.org/releases/latest/matchers/ 102 | const greeter = { 103 | /** 104 | * Greets a person 105 | * @param {string} name 106 | */ 107 | greet (name) { 108 | return `Hello, ${name}!` 109 | }, 110 | } 111 | 112 | cy.stub(greeter, 'greet') 113 | .callThrough() // if you want non-matched calls to call the real method 114 | .withArgs(Cypress.sinon.match.string).returns('Hi') 115 | .withArgs(Cypress.sinon.match.number).throws(new Error('Invalid name')) 116 | 117 | expect(greeter.greet('World')).to.equal('Hi') 118 | // @ts-ignore 119 | expect(() => greeter.greet(42)).to.throw('Invalid name') 120 | expect(greeter.greet).to.have.been.calledTwice 121 | 122 | // non-matched calls goes the actual method 123 | // @ts-ignore 124 | expect(greeter.greet()).to.equal('Hello, undefined!') 125 | }) 126 | 127 | it('matches call arguments using Sinon matchers', () => { 128 | // see all possible matchers at 129 | // https://sinonjs.org/releases/latest/matchers/ 130 | const calculator = { 131 | /** 132 | * returns the sum of two arguments 133 | * @param a {number} 134 | * @param b {number} 135 | */ 136 | add (a, b) { 137 | return a + b 138 | }, 139 | } 140 | 141 | const spy = cy.spy(calculator, 'add').as('add') 142 | 143 | expect(calculator.add(2, 3)).to.equal(5) 144 | 145 | // if we want to assert the exact values used during the call 146 | expect(spy).to.be.calledWith(2, 3) 147 | 148 | // let's confirm "add" method was called with two numbers 149 | expect(spy).to.be.calledWith(Cypress.sinon.match.number, Cypress.sinon.match.number) 150 | 151 | // alternatively, provide the value to match 152 | expect(spy).to.be.calledWith(Cypress.sinon.match(2), Cypress.sinon.match(3)) 153 | 154 | // match any value 155 | expect(spy).to.be.calledWith(Cypress.sinon.match.any, 3) 156 | 157 | // match any value from a list 158 | expect(spy).to.be.calledWith(Cypress.sinon.match.in([1, 2, 3]), 3) 159 | 160 | /** 161 | * Returns true if the given number is event 162 | * @param {number} x 163 | */ 164 | const isEven = (x) => x % 2 === 0 165 | 166 | // expect the value to pass a custom predicate function 167 | // the second argument to "sinon.match(predicate, message)" is 168 | // shown if the predicate does not pass and assertion fails 169 | expect(spy).to.be.calledWith(Cypress.sinon.match(isEven, 'isEven'), 3) 170 | 171 | /** 172 | * Returns a function that checks if a given number is larger than the limit 173 | * @param {number} limit 174 | * @returns {(x: number) => boolean} 175 | */ 176 | const isGreaterThan = (limit) => (x) => x > limit 177 | 178 | /** 179 | * Returns a function that checks if a given number is less than the limit 180 | * @param {number} limit 181 | * @returns {(x: number) => boolean} 182 | */ 183 | const isLessThan = (limit) => (x) => x < limit 184 | 185 | // you can combine several matchers using "and", "or" 186 | expect(spy).to.be.calledWith( 187 | Cypress.sinon.match.number, 188 | Cypress.sinon.match(isGreaterThan(2), '> 2').and(Cypress.sinon.match(isLessThan(4), '< 4')), 189 | ) 190 | 191 | expect(spy).to.be.calledWith( 192 | Cypress.sinon.match.number, 193 | Cypress.sinon.match(isGreaterThan(200), '> 200').or(Cypress.sinon.match(3)), 194 | ) 195 | 196 | // matchers can be used from BDD assertions 197 | cy.get('@add').should('have.been.calledWith', 198 | Cypress.sinon.match.number, Cypress.sinon.match(3)) 199 | 200 | // you can alias matchers for shorter test code 201 | const { match: M } = Cypress.sinon 202 | 203 | cy.get('@add').should('have.been.calledWith', M.number, M(3)) 204 | }) 205 | }) 206 | -------------------------------------------------------------------------------- /cypress/e2e/examples/traversal.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Traversal', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io/commands/traversal') 6 | }) 7 | 8 | it('.children() - get child DOM elements', () => { 9 | // https://on.cypress.io/children 10 | cy.get('.traversal-breadcrumb') 11 | .children('.active') 12 | .should('contain', 'Data') 13 | }) 14 | 15 | it('.closest() - get closest ancestor DOM element', () => { 16 | // https://on.cypress.io/closest 17 | cy.get('.traversal-badge') 18 | .closest('ul') 19 | .should('have.class', 'list-group') 20 | }) 21 | 22 | it('.eq() - get a DOM element at a specific index', () => { 23 | // https://on.cypress.io/eq 24 | cy.get('.traversal-list>li') 25 | .eq(1).should('contain', 'siamese') 26 | }) 27 | 28 | it('.filter() - get DOM elements that match the selector', () => { 29 | // https://on.cypress.io/filter 30 | cy.get('.traversal-nav>li') 31 | .filter('.active').should('contain', 'About') 32 | }) 33 | 34 | it('.find() - get descendant DOM elements of the selector', () => { 35 | // https://on.cypress.io/find 36 | cy.get('.traversal-pagination') 37 | .find('li').find('a') 38 | .should('have.length', 7) 39 | }) 40 | 41 | it('.first() - get first DOM element', () => { 42 | // https://on.cypress.io/first 43 | cy.get('.traversal-table td') 44 | .first().should('contain', '1') 45 | }) 46 | 47 | it('.last() - get last DOM element', () => { 48 | // https://on.cypress.io/last 49 | cy.get('.traversal-buttons .btn') 50 | .last().should('contain', 'Submit') 51 | }) 52 | 53 | it('.next() - get next sibling DOM element', () => { 54 | // https://on.cypress.io/next 55 | cy.get('.traversal-ul') 56 | .contains('apples').next().should('contain', 'oranges') 57 | }) 58 | 59 | it('.nextAll() - get all next sibling DOM elements', () => { 60 | // https://on.cypress.io/nextall 61 | cy.get('.traversal-next-all') 62 | .contains('oranges') 63 | .nextAll().should('have.length', 3) 64 | }) 65 | 66 | it('.nextUntil() - get next sibling DOM elements until next el', () => { 67 | // https://on.cypress.io/nextuntil 68 | cy.get('#veggies') 69 | .nextUntil('#nuts').should('have.length', 3) 70 | }) 71 | 72 | it('.not() - remove DOM elements from set of DOM elements', () => { 73 | // https://on.cypress.io/not 74 | cy.get('.traversal-disabled .btn') 75 | .not('[disabled]').should('not.contain', 'Disabled') 76 | }) 77 | 78 | it('.parent() - get parent DOM element from DOM elements', () => { 79 | // https://on.cypress.io/parent 80 | cy.get('.traversal-mark') 81 | .parent().should('contain', 'Morbi leo risus') 82 | }) 83 | 84 | it('.parents() - get parent DOM elements from DOM elements', () => { 85 | // https://on.cypress.io/parents 86 | cy.get('.traversal-cite') 87 | .parents().should('match', 'blockquote') 88 | }) 89 | 90 | it('.parentsUntil() - get parent DOM elements from DOM elements until el', () => { 91 | // https://on.cypress.io/parentsuntil 92 | cy.get('.clothes-nav') 93 | .find('.active') 94 | .parentsUntil('.clothes-nav') 95 | .should('have.length', 2) 96 | }) 97 | 98 | it('.prev() - get previous sibling DOM element', () => { 99 | // https://on.cypress.io/prev 100 | cy.get('.birds').find('.active') 101 | .prev().should('contain', 'Lorikeets') 102 | }) 103 | 104 | it('.prevAll() - get all previous sibling DOM elements', () => { 105 | // https://on.cypress.io/prevAll 106 | cy.get('.fruits-list').find('.third') 107 | .prevAll().should('have.length', 2) 108 | }) 109 | 110 | it('.prevUntil() - get all previous sibling DOM elements until el', () => { 111 | // https://on.cypress.io/prevUntil 112 | cy.get('.foods-list').find('#nuts') 113 | .prevUntil('#veggies').should('have.length', 3) 114 | }) 115 | 116 | it('.siblings() - get all sibling DOM elements', () => { 117 | // https://on.cypress.io/siblings 118 | cy.get('.traversal-pills .active') 119 | .siblings().should('have.length', 2) 120 | }) 121 | }) 122 | -------------------------------------------------------------------------------- /cypress/e2e/examples/utilities.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Utilities', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io/utilities') 6 | }) 7 | 8 | it('Cypress._ - call a lodash method', () => { 9 | // https://on.cypress.io/_ 10 | cy.request('https://jsonplaceholder.cypress.io/users') 11 | .then((response) => { 12 | let ids = Cypress._.chain(response.body).map('id').take(3).value() 13 | 14 | expect(ids).to.deep.eq([1, 2, 3]) 15 | }) 16 | }) 17 | 18 | it('Cypress.$ - call a jQuery method', () => { 19 | // https://on.cypress.io/$ 20 | let $li = Cypress.$('.utility-jquery li:first') 21 | 22 | cy.wrap($li) 23 | .should('not.have.class', 'active') 24 | .click() 25 | .should('have.class', 'active') 26 | }) 27 | 28 | it('Cypress.Blob - blob utilities and base64 string conversion', () => { 29 | // https://on.cypress.io/blob 30 | cy.get('.utility-blob').then(($div) => { 31 | // https://github.com/nolanlawson/blob-util#imgSrcToDataURL 32 | // get the dataUrl string for the javascript-logo 33 | return Cypress.Blob.imgSrcToDataURL('https://example.cypress.io/assets/img/javascript-logo.png', undefined, 'anonymous') 34 | .then((dataUrl) => { 35 | // create an element and set its src to the dataUrl 36 | let img = Cypress.$('', { src: dataUrl }) 37 | 38 | // need to explicitly return cy here since we are initially returning 39 | // the Cypress.Blob.imgSrcToDataURL promise to our test 40 | // append the image 41 | $div.append(img) 42 | 43 | cy.get('.utility-blob img').click() 44 | .should('have.attr', 'src', dataUrl) 45 | }) 46 | }) 47 | }) 48 | 49 | it('Cypress.minimatch - test out glob patterns against strings', () => { 50 | // https://on.cypress.io/minimatch 51 | let matching = Cypress.minimatch('/users/1/comments', '/users/*/comments', { 52 | matchBase: true, 53 | }) 54 | 55 | expect(matching, 'matching wildcard').to.be.true 56 | 57 | matching = Cypress.minimatch('/users/1/comments/2', '/users/*/comments', { 58 | matchBase: true, 59 | }) 60 | 61 | expect(matching, 'comments').to.be.false 62 | 63 | // ** matches against all downstream path segments 64 | matching = Cypress.minimatch('/foo/bar/baz/123/quux?a=b&c=2', '/foo/**', { 65 | matchBase: true, 66 | }) 67 | 68 | expect(matching, 'comments').to.be.true 69 | 70 | // whereas * matches only the next path segment 71 | 72 | matching = Cypress.minimatch('/foo/bar/baz/123/quux?a=b&c=2', '/foo/*', { 73 | matchBase: false, 74 | }) 75 | 76 | expect(matching, 'comments').to.be.false 77 | }) 78 | 79 | it('Cypress.moment() - format or parse dates using a moment method', () => { 80 | // https://on.cypress.io/moment 81 | const time = Cypress.moment('2014-04-25T19:38:53.196Z').utc().format('h:mm A') 82 | 83 | expect(time).to.be.a('string') 84 | 85 | cy.get('.utility-moment').contains('3:38 PM') 86 | .should('have.class', 'badge') 87 | 88 | // the time in the element should be between 3pm and 5pm 89 | const start = Cypress.moment('3:00 PM', 'LT') 90 | const end = Cypress.moment('5:00 PM', 'LT') 91 | 92 | cy.get('.utility-moment .badge') 93 | .should(($el) => { 94 | // parse American time like "3:38 PM" 95 | const m = Cypress.moment($el.text().trim(), 'LT') 96 | 97 | // display hours + minutes + AM|PM 98 | const f = 'h:mm A' 99 | 100 | expect(m.isBetween(start, end), 101 | `${m.format(f)} should be between ${start.format(f)} and ${end.format(f)}`).to.be.true 102 | }) 103 | }) 104 | 105 | it('Cypress.Promise - instantiate a bluebird promise', () => { 106 | // https://on.cypress.io/promise 107 | let waited = false 108 | 109 | /** 110 | * @return Bluebird 111 | */ 112 | function waitOneSecond () { 113 | // return a promise that resolves after 1 second 114 | // @ts-ignore TS2351 (new Cypress.Promise) 115 | return new Cypress.Promise((resolve, reject) => { 116 | setTimeout(() => { 117 | // set waited to true 118 | waited = true 119 | 120 | // resolve with 'foo' string 121 | resolve('foo') 122 | }, 1000) 123 | }) 124 | } 125 | 126 | cy.then(() => { 127 | // return a promise to cy.then() that 128 | // is awaited until it resolves 129 | // @ts-ignore TS7006 130 | return waitOneSecond().then((str) => { 131 | expect(str).to.eq('foo') 132 | expect(waited).to.be.true 133 | }) 134 | }) 135 | }) 136 | }) 137 | -------------------------------------------------------------------------------- /cypress/e2e/examples/viewport.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Viewport', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io/commands/viewport') 6 | }) 7 | 8 | it('cy.viewport() - set the viewport size and dimension', () => { 9 | // https://on.cypress.io/viewport 10 | 11 | cy.get('#navbar').should('be.visible') 12 | cy.viewport(320, 480) 13 | 14 | // the navbar should have collapse since our screen is smaller 15 | cy.get('#navbar').should('not.be.visible') 16 | cy.get('.navbar-toggle').should('be.visible').click() 17 | cy.get('.nav').find('a').should('be.visible') 18 | 19 | // lets see what our app looks like on a super large screen 20 | cy.viewport(2999, 2999) 21 | 22 | // cy.viewport() accepts a set of preset sizes 23 | // to easily set the screen to a device's width and height 24 | 25 | // We added a cy.wait() between each viewport change so you can see 26 | // the change otherwise it is a little too fast to see :) 27 | 28 | cy.viewport('macbook-15') 29 | cy.wait(200) 30 | cy.viewport('macbook-13') 31 | cy.wait(200) 32 | cy.viewport('macbook-11') 33 | cy.wait(200) 34 | cy.viewport('ipad-2') 35 | cy.wait(200) 36 | cy.viewport('ipad-mini') 37 | cy.wait(200) 38 | cy.viewport('iphone-6+') 39 | cy.wait(200) 40 | cy.viewport('iphone-6') 41 | cy.wait(200) 42 | cy.viewport('iphone-5') 43 | cy.wait(200) 44 | cy.viewport('iphone-4') 45 | cy.wait(200) 46 | cy.viewport('iphone-3') 47 | cy.wait(200) 48 | 49 | // cy.viewport() accepts an orientation for all presets 50 | // the default orientation is 'portrait' 51 | cy.viewport('ipad-2', 'portrait') 52 | cy.wait(200) 53 | cy.viewport('iphone-4', 'landscape') 54 | cy.wait(200) 55 | 56 | // The viewport will be reset back to the default dimensions 57 | // in between tests (the default can be set in cypress.json) 58 | }) 59 | }) 60 | -------------------------------------------------------------------------------- /cypress/e2e/examples/waiting.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Waiting', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io/commands/waiting') 6 | }) 7 | // BE CAREFUL of adding unnecessary wait times. 8 | // https://on.cypress.io/best-practices#Unnecessary-Waiting 9 | 10 | // https://on.cypress.io/wait 11 | it('cy.wait() - wait for a specific amount of time', () => { 12 | cy.get('.wait-input1').type('Wait 1000ms after typing') 13 | cy.wait(1000) 14 | cy.get('.wait-input2').type('Wait 1000ms after typing') 15 | cy.wait(1000) 16 | cy.get('.wait-input3').type('Wait 1000ms after typing') 17 | cy.wait(1000) 18 | }) 19 | 20 | it('cy.wait() - wait for a specific route', () => { 21 | cy.server() 22 | 23 | // Listen to GET to comments/1 24 | cy.route('GET', 'comments/*').as('getComment') 25 | 26 | // we have code that gets a comment when 27 | // the button is clicked in scripts.js 28 | cy.get('.network-btn').click() 29 | 30 | // wait for GET comments/1 31 | cy.wait('@getComment').its('status').should('eq', 200) 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /cypress/e2e/examples/window.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context('Window', () => { 4 | beforeEach(() => { 5 | cy.visit('https://example.cypress.io/commands/window') 6 | }) 7 | 8 | it('cy.window() - get the global window object', () => { 9 | // https://on.cypress.io/window 10 | cy.window().should('have.property', 'top') 11 | }) 12 | 13 | it('cy.document() - get the document object', () => { 14 | // https://on.cypress.io/document 15 | cy.document().should('have.property', 'charset').and('eq', 'UTF-8') 16 | }) 17 | 18 | it('cy.title() - get the title', () => { 19 | // https://on.cypress.io/title 20 | cy.title().should('include', 'Kitchen Sink') 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /cypress/e2e/pages/dashboardPage.js: -------------------------------------------------------------------------------- 1 | class dashboardPage { 2 | 3 | welcomeTxt() { 4 | return cy.get('#welcome') 5 | } 6 | 7 | logoutTxt() { 8 | return cy.contains('Logout') 9 | } 10 | } 11 | 12 | export default dashboardPage -------------------------------------------------------------------------------- /cypress/e2e/pages/loginPage.js: -------------------------------------------------------------------------------- 1 | class loginPage { 2 | 3 | usernameInput() { 4 | return cy.get('#txtUsername') 5 | } 6 | 7 | passwordInput() { 8 | return cy.get('#txtPassword') 9 | } 10 | 11 | loginBtn() { 12 | return cy.get('#btnLogin') 13 | } 14 | } 15 | export default loginPage -------------------------------------------------------------------------------- /cypress/e2e/sequenced-tests.cy.js: -------------------------------------------------------------------------------- 1 | //Run tests in the intended order 2 | 3 | import './TC05_conditionalTesting.cy.js' 4 | import './TC01.cy.js' 5 | import './TC03_writeReadFile.cy.js' 6 | import './TC02_fixtures.cy.js' -------------------------------------------------------------------------------- /cypress/e2e/utils/dashboard.js: -------------------------------------------------------------------------------- 1 | import loginPage from '../pages/loginPage.js' 2 | import dashboardPage from '../pages/dashboardPage.js' 3 | const login = new loginPage(); 4 | const dashboard = new dashboardPage(); 5 | 6 | Cypress.Commands.add('logout', () => { 7 | dashboard.welcomeTxt().click() 8 | dashboard.logoutTxt().click() 9 | login.usernameInput().should('be.visible') 10 | }) -------------------------------------------------------------------------------- /cypress/e2e/utils/login.js: -------------------------------------------------------------------------------- 1 | import loginPage from '../pages/loginPage.js' 2 | import dashboardPage from '../pages/dashboardPage.js' 3 | const login = new loginPage(); 4 | const dashboard = new dashboardPage(); 5 | 6 | Cypress.Commands.add('login', (data) => { 7 | cy.visit('/') 8 | login.usernameInput().type(data.username) 9 | login.passwordInput().type(data.password) 10 | login.loginBtn().click() 11 | dashboard.welcomeTxt().contains(data.welcomeText) 12 | }) -------------------------------------------------------------------------------- /cypress/fixtures/Download/test.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 2 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 3 | Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. 4 | Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -------------------------------------------------------------------------------- /cypress/fixtures/articlefeed.json: -------------------------------------------------------------------------------- 1 | { 2 | "articles":[ 3 | { 4 | "title":"Hi", 5 | "slug":"hi-5h5nba", 6 | "body":"testing", 7 | "createdAt":"2020-09-26T03:18:26.635Z", 8 | "updatedAt":"2020-09-26T03:18:26.635Z", 9 | "tagList":[ 10 | 11 | ], 12 | "description":"This is a test description", 13 | "author":{ 14 | "username":"testersdock", 15 | "bio":null, 16 | "image":"https://static.productionready.io/images/smiley-cyrus.jpg", 17 | "following":false 18 | }, 19 | "favorited":false, 20 | "favoritesCount":10 21 | } 22 | ], 23 | "articlesCount":500 24 | } -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } -------------------------------------------------------------------------------- /cypress/fixtures/images/evening.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alapanme/Cypress-Automation/ea36e36d5d900d6d86186e07beb23f67919058ca/cypress/fixtures/images/evening.png -------------------------------------------------------------------------------- /cypress/fixtures/images/morning.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alapanme/Cypress-Automation/ea36e36d5d900d6d86186e07beb23f67919058ca/cypress/fixtures/images/morning.jpg -------------------------------------------------------------------------------- /cypress/fixtures/images/night.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alapanme/Cypress-Automation/ea36e36d5d900d6d86186e07beb23f67919058ca/cypress/fixtures/images/night.jpg -------------------------------------------------------------------------------- /cypress/fixtures/profile.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 8739, 3 | "name": "Jane", 4 | "email": "jane@example.com" 5 | } -------------------------------------------------------------------------------- /cypress/fixtures/tags.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags":[ 3 | "cypress", 4 | "selenium" 5 | ] 6 | } -------------------------------------------------------------------------------- /cypress/fixtures/test1.txt: -------------------------------------------------------------------------------- 1 | Testersdock.com 2 | Info Hub for Testers -------------------------------------------------------------------------------- /cypress/fixtures/test2.json: -------------------------------------------------------------------------------- 1 | { 2 | "firstname": "Alapan", 3 | "lastname": "Das" 4 | } -------------------------------------------------------------------------------- /cypress/fixtures/testdata.json: -------------------------------------------------------------------------------- 1 | { 2 | "username": "Admin", 3 | "password": "admin123", 4 | "welcomeText": "Welcome", 5 | "quickLaunch": ["Assign Leave", "Leave List", "Timesheets", "Apply Leave", "My Leave", "My Timesheet"], 6 | "empDistPieChart": ["40%", "20%", "13%", "13%", "13%"] 7 | } -------------------------------------------------------------------------------- /cypress/fixtures/users.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "name": "Leanne Graham", 5 | "username": "Bret", 6 | "email": "Sincere@april.biz", 7 | "address": { 8 | "street": "Kulas Light", 9 | "suite": "Apt. 556", 10 | "city": "Gwenborough", 11 | "zipcode": "92998-3874", 12 | "geo": { 13 | "lat": "-37.3159", 14 | "lng": "81.1496" 15 | } 16 | }, 17 | "phone": "1-770-736-8031 x56442", 18 | "website": "hildegard.org", 19 | "company": { 20 | "name": "Romaguera-Crona", 21 | "catchPhrase": "Multi-layered client-server neural-net", 22 | "bs": "harness real-time e-markets" 23 | } 24 | }, 25 | { 26 | "id": 2, 27 | "name": "Ervin Howell", 28 | "username": "Antonette", 29 | "email": "Shanna@melissa.tv", 30 | "address": { 31 | "street": "Victor Plains", 32 | "suite": "Suite 879", 33 | "city": "Wisokyburgh", 34 | "zipcode": "90566-7771", 35 | "geo": { 36 | "lat": "-43.9509", 37 | "lng": "-34.4618" 38 | } 39 | }, 40 | "phone": "010-692-6593 x09125", 41 | "website": "anastasia.net", 42 | "company": { 43 | "name": "Deckow-Crist", 44 | "catchPhrase": "Proactive didactic contingency", 45 | "bs": "synergize scalable supply-chains" 46 | } 47 | }, 48 | { 49 | "id": 3, 50 | "name": "Clementine Bauch", 51 | "username": "Samantha", 52 | "email": "Nathan@yesenia.net", 53 | "address": { 54 | "street": "Douglas Extension", 55 | "suite": "Suite 847", 56 | "city": "McKenziehaven", 57 | "zipcode": "59590-4157", 58 | "geo": { 59 | "lat": "-68.6102", 60 | "lng": "-47.0653" 61 | } 62 | }, 63 | "phone": "1-463-123-4447", 64 | "website": "ramiro.info", 65 | "company": { 66 | "name": "Romaguera-Jacobson", 67 | "catchPhrase": "Face to face bifurcated interface", 68 | "bs": "e-enable strategic applications" 69 | } 70 | }, 71 | { 72 | "id": 4, 73 | "name": "Patricia Lebsack", 74 | "username": "Karianne", 75 | "email": "Julianne.OConner@kory.org", 76 | "address": { 77 | "street": "Hoeger Mall", 78 | "suite": "Apt. 692", 79 | "city": "South Elvis", 80 | "zipcode": "53919-4257", 81 | "geo": { 82 | "lat": "29.4572", 83 | "lng": "-164.2990" 84 | } 85 | }, 86 | "phone": "493-170-9623 x156", 87 | "website": "kale.biz", 88 | "company": { 89 | "name": "Robel-Corkery", 90 | "catchPhrase": "Multi-tiered zero tolerance productivity", 91 | "bs": "transition cutting-edge web services" 92 | } 93 | }, 94 | { 95 | "id": 5, 96 | "name": "Chelsey Dietrich", 97 | "username": "Kamren", 98 | "email": "Lucio_Hettinger@annie.ca", 99 | "address": { 100 | "street": "Skiles Walks", 101 | "suite": "Suite 351", 102 | "city": "Roscoeview", 103 | "zipcode": "33263", 104 | "geo": { 105 | "lat": "-31.8129", 106 | "lng": "62.5342" 107 | } 108 | }, 109 | "phone": "(254)954-1289", 110 | "website": "demarco.info", 111 | "company": { 112 | "name": "Keebler LLC", 113 | "catchPhrase": "User-centric fault-tolerant solution", 114 | "bs": "revolutionize end-to-end systems" 115 | } 116 | }, 117 | { 118 | "id": 6, 119 | "name": "Mrs. Dennis Schulist", 120 | "username": "Leopoldo_Corkery", 121 | "email": "Karley_Dach@jasper.info", 122 | "address": { 123 | "street": "Norberto Crossing", 124 | "suite": "Apt. 950", 125 | "city": "South Christy", 126 | "zipcode": "23505-1337", 127 | "geo": { 128 | "lat": "-71.4197", 129 | "lng": "71.7478" 130 | } 131 | }, 132 | "phone": "1-477-935-8478 x6430", 133 | "website": "ola.org", 134 | "company": { 135 | "name": "Considine-Lockman", 136 | "catchPhrase": "Synchronised bottom-line interface", 137 | "bs": "e-enable innovative applications" 138 | } 139 | }, 140 | { 141 | "id": 7, 142 | "name": "Kurtis Weissnat", 143 | "username": "Elwyn.Skiles", 144 | "email": "Telly.Hoeger@billy.biz", 145 | "address": { 146 | "street": "Rex Trail", 147 | "suite": "Suite 280", 148 | "city": "Howemouth", 149 | "zipcode": "58804-1099", 150 | "geo": { 151 | "lat": "24.8918", 152 | "lng": "21.8984" 153 | } 154 | }, 155 | "phone": "210.067.6132", 156 | "website": "elvis.io", 157 | "company": { 158 | "name": "Johns Group", 159 | "catchPhrase": "Configurable multimedia task-force", 160 | "bs": "generate enterprise e-tailers" 161 | } 162 | }, 163 | { 164 | "id": 8, 165 | "name": "Nicholas Runolfsdottir V", 166 | "username": "Maxime_Nienow", 167 | "email": "Sherwood@rosamond.me", 168 | "address": { 169 | "street": "Ellsworth Summit", 170 | "suite": "Suite 729", 171 | "city": "Aliyaview", 172 | "zipcode": "45169", 173 | "geo": { 174 | "lat": "-14.3990", 175 | "lng": "-120.7677" 176 | } 177 | }, 178 | "phone": "586.493.6943 x140", 179 | "website": "jacynthe.com", 180 | "company": { 181 | "name": "Abernathy Group", 182 | "catchPhrase": "Implemented secondary concept", 183 | "bs": "e-enable extensible e-tailers" 184 | } 185 | }, 186 | { 187 | "id": 9, 188 | "name": "Glenna Reichert", 189 | "username": "Delphine", 190 | "email": "Chaim_McDermott@dana.io", 191 | "address": { 192 | "street": "Dayna Park", 193 | "suite": "Suite 449", 194 | "city": "Bartholomebury", 195 | "zipcode": "76495-3109", 196 | "geo": { 197 | "lat": "24.6463", 198 | "lng": "-168.8889" 199 | } 200 | }, 201 | "phone": "(775)976-6794 x41206", 202 | "website": "conrad.com", 203 | "company": { 204 | "name": "Yost and Sons", 205 | "catchPhrase": "Switchable contextually-based project", 206 | "bs": "aggregate real-time technologies" 207 | } 208 | }, 209 | { 210 | "id": 10, 211 | "name": "Clementina DuBuque", 212 | "username": "Moriah.Stanton", 213 | "email": "Rey.Padberg@karina.biz", 214 | "address": { 215 | "street": "Kattie Turnpike", 216 | "suite": "Suite 198", 217 | "city": "Lebsackbury", 218 | "zipcode": "31428-2261", 219 | "geo": { 220 | "lat": "-38.2386", 221 | "lng": "57.2232" 222 | } 223 | }, 224 | "phone": "024-648-3804", 225 | "website": "ambrose.net", 226 | "company": { 227 | "name": "Hoeger LLC", 228 | "catchPhrase": "Centralized empowering task-force", 229 | "bs": "target end-to-end models" 230 | } 231 | } 232 | ] -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************************** 3 | // This example plugins/index.js can be used to load plugins 4 | // 5 | // You can change the location of this file or turn off loading 6 | // the plugins file with the 'pluginsFile' configuration option. 7 | // 8 | // You can read more here: 9 | // https://on.cypress.io/plugins-guide 10 | // *********************************************************** 11 | 12 | // This function is called when a project is opened or re-opened (e.g. due to 13 | // the project's config changing) 14 | 15 | /** 16 | * @type {Cypress.PluginConfig} 17 | */ 18 | module.exports = (on, config) => { 19 | // `on` is used to hook into various events Cypress emits 20 | // `config` is the resolved Cypress config 21 | } 22 | 23 | //For Cypress file Download 24 | const { downloadFile } = require('cypress-downloadfile/lib/addPlugin') 25 | 26 | //For Adding Tags to Tests 27 | const selectTestsWithGrep = require('cypress-select-tests/grep') 28 | 29 | //For connecting to SQL Server 30 | const mysql = require('mysql') 31 | function queryTestDb(query, config) { 32 | // creates a new mysql connection using credentials from cypress.json env's 33 | const connection = mysql.createConnection(config.env.db) 34 | // start connection to db 35 | connection.connect() 36 | // exec query + disconnect to db as a Promise 37 | return new Promise((resolve, reject) => { 38 | connection.query(query, (error, results) => { 39 | if (error) reject(error) 40 | else { 41 | connection.end() 42 | return resolve(results) 43 | } 44 | }) 45 | }) 46 | } 47 | 48 | module.exports = (on, config) => { 49 | on('task', { downloadFile }); //Cypress file Download 50 | on('file:preprocessor', selectTestsWithGrep(config)); //Adding Tags to Tests 51 | on('task', { queryDb: query => { return queryTestDb(query, config) }, }); //For running sql query 52 | require('cypress-grep/src/plugin')(config); return config //For cypress-grep to add tags to test 53 | } 54 | 55 | //For Cucumber Integration 56 | const createEsbuildPlugin = require('@badeball/cypress-cucumber-preprocessor/esbuild').createEsbuildPlugin; 57 | const createBundler = require('@bahmutov/cypress-esbuild-preprocessor'); 58 | const nodePolyfills = require('@esbuild-plugins/node-modules-polyfill').NodeModulesPolyfillPlugin; 59 | const addCucumberPreprocessorPlugin = require('@badeball/cypress-cucumber-preprocessor').addCucumberPreprocessorPlugin; 60 | module.exports = async (on, config) => { 61 | await addCucumberPreprocessorPlugin(on, config); // to allow json to be produced 62 | // To use esBuild for the bundler when preprocessing 63 | on( 64 | 'file:preprocessor', 65 | createBundler({ 66 | plugins: [nodePolyfills(), createEsbuildPlugin(config)], 67 | }), 68 | ); 69 | return config; 70 | } -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | 27 | //For File Import 28 | import 'cypress-file-upload'; 29 | 30 | //For File Download 31 | require('cypress-downloadfile/lib/downloadFileCommand'); 32 | 33 | //For handling iFrames 34 | Cypress.Commands.add('getIframe', (iframe) => { 35 | return cy.get(iframe) 36 | .its('0.contentDocument.body') 37 | .should('be.visible') 38 | .then(cy.wrap); 39 | }) 40 | 41 | //For Cypress drag and drop plugin 42 | require('@4tw/cypress-drag-drop') 43 | 44 | //For Cypress drag and drop custom command 45 | Cypress.Commands.add('draganddrop', (dragSelector, dropSelector) => { 46 | cy.get(dragSelector).should('exist') 47 | .get(dropSelector).should('exist'); 48 | 49 | const draggable = Cypress.$(dragSelector)[0]; // Pick up this 50 | const droppable = Cypress.$(dropSelector)[0]; // Drop over this 51 | 52 | const coords = droppable.getBoundingClientRect() 53 | draggable.dispatchEvent(new MouseEvent('mousedown')); 54 | draggable.dispatchEvent(new MouseEvent('mousemove', { clientX: 10, clientY: 0 })); 55 | draggable.dispatchEvent(new MouseEvent('mousemove', { 56 | clientX: coords.left + 10, 57 | clientY: coords.top + 10 // A few extra pixels to get the ordering right 58 | })); 59 | draggable.dispatchEvent(new MouseEvent('mouseup')); 60 | return cy.get(dropSelector); 61 | }) 62 | 63 | //Login Custom Command 64 | Cypress.Commands.add('loginOrangeCRM', (username, password) => { 65 | cy.get('#txtUsername').type(username) 66 | cy.get('#txtPassword').type(password) 67 | cy.get('#btnLogin').click() 68 | cy.get('#welcome').should('be.visible') 69 | }) -------------------------------------------------------------------------------- /cypress/support/e2e.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | import '../e2e/utils/login.js' 19 | import '../e2e/utils/dashboard.js' 20 | import "cypress-real-events/support" 21 | require('cypress-grep')() 22 | 23 | // Alternatively you can use CommonJS syntax: 24 | // require('./commands') 25 | -------------------------------------------------------------------------------- /cypress/support/filterTests.js: -------------------------------------------------------------------------------- 1 | const TestFilters = (givenTags, runTest) => { 2 | if (Cypress.env('tags')) { 3 | const tags = Cypress.env('tags').split(',') 4 | const isFound = givenTags.some((givenTag) => tags.includes(givenTag)) 5 | 6 | if (isFound) { 7 | runTest() 8 | } 9 | } else { 10 | runTest() 11 | } 12 | }; 13 | 14 | export default TestFilters -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "./node_modules/cypress", 4 | "cypress/**/*.js" 5 | ] 6 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cypress-automation", 3 | "version": "1.0.0", 4 | "description": "Cypress Automation by Testersdock", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "cypress open", 8 | "delete:reportFolder": "rm -rf mochawesome-report/", 9 | "test:cli": "npm run delete:reportFolder && cypress run", 10 | "merge:reports": "mochawesome-merge mochawesome-report/*.json > cypress-combined-report.json", 11 | "create:html:report": "npm run merge:reports && marge --reportDir TestReport cypress-combined-report.json" 12 | }, 13 | "author": "Alapan", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "@4tw/cypress-drag-drop": "^1.8.0", 17 | "@badeball/cypress-cucumber-preprocessor": "^11.0.0", 18 | "@bahmutov/cypress-esbuild-preprocessor": "^2.1.3", 19 | "@deploysentinel/cypress-recorder": "^0.1.0", 20 | "@esbuild-plugins/node-modules-polyfill": "^0.1.4", 21 | "cypress": "^10.6.0", 22 | "cypress-downloadfile": "^1.2.0", 23 | "cypress-file-upload": "^5.0.8", 24 | "cypress-grep": "^2.13.1", 25 | "cypress-real-events": "^1.5.1", 26 | "cypress-recurse": "^1.8.1", 27 | "cypress-select-tests": "^1.7.1", 28 | "mocha": "^8.3.2", 29 | "mochawesome": "^6.2.2", 30 | "mochawesome-merge": "^4.2.0", 31 | "mochawesome-report-generator": "^5.2.0", 32 | "mysql": "^2.18.1" 33 | }, 34 | "cypress-cucumber-preprocessor": { 35 | "stepDefinitions": "cypress/e2e/cucumber-test/**/*.{js,ts}" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Cypress-Automation 2 | Cypress is a next generation front end testing tool built for the modern web. This is a sample project which you can use to start your E2E testing with Cypress. 3 | 4 | # How to Start 5 | 1. Clone the project 6 | 2. `npm i` - Install all the dependencies 7 | 3. There are a lot dependencies that are not updated frequently in parallel with cypress. So while installing if you are seeing conflicts use`npm i --force`. 8 | 4. Run `npm test` to execute the tests in Test Runner | Run `npx cypress run` to execute the tests in CLI 9 | 5. To create HTML reports execute first `npm run test:cli` and then `npm run create:html:report` 10 | 11 | # Articles on Cypress 12 | - [How to Install Cypress](https://testersdock.com/how-to-install-cypress/) 13 | - [Understanding Cypress Folder Structure](https://testersdock.com/cypress-folder-structure/) 14 | - [How to execute Cypress Tests using Test Runner and CLI](https://testersdock.com/cypress-test-runner-cli/) 15 | - [Writing your First Test in Cypress](https://testersdock.com/first-cypress-test/) 16 | - [How to use Fixtures in Cypress Tests](https://testersdock.com/cypress-fixtures/) 17 | - [How to use readFile() and writeFile() in Cypress](https://testersdock.com/cypress-writefile-readfile/) 18 | - [How to interact with multiple elements using each()](https://testersdock.com/cypress-each/) 19 | - [Conditional Testing (If Else) in Cypress](https://testersdock.com/cypress-conditional-if-else-testing/) 20 | - [How to upload a file in Cypress](https://testersdock.com/cypress-file-upload/) 21 | - [How to download a file in Cypress](https://testersdock.com/cypress-file-download/) 22 | - [API Testing in Cypress](https://testersdock.com/cypress-api-testing/) 23 | - [How to chain Multiple APIs in Cypress](https://testersdock.com/cypress-chain-multiple-api/) 24 | - [Mock API Response in Cypress using cy.server() and cy.route()](https://testersdock.com/cypress-mock-api/) 25 | - [How to handle JS Alert, Confirm and Prompt in Cypress](https://testersdock.com/cypress-javascript-alert-confirm-prompt/) 26 | - [How to use Skip and Only in Cypress](https://testersdock.com/skip-only-cypress/) 27 | - [How to execute Cypress Tests in order(update for cypress 10)](https://testersdock.com/cypress-execute-tests-in-order/) 28 | - [How to handle Shadow DOM in Cypress](https://testersdock.com/cypress-shadow-dom/) 29 | - [How to retry tests X number of times in Cypress](https://testersdock.com/test-retries-in-cypress/) 30 | - [How to handle Iframes in Cypress](https://testersdock.com/iframes-cypress/) 31 | - [How to generate HTML reports in Cypress](https://testersdock.com/html-reports-cypress/) 32 | - [How to Add Tags like Smoke,E2E to Cypress Tests](https://testersdock.com/cypress-test-tags/) 33 | - [Cypress Page Object with Locator Functions and Custom Commands](https://testersdock.com/cypress-page-object-with-locator-function-and-custom-command/) 34 | - [Cypress Dashboard](https://testersdock.com/cypress-dashboard/) 35 | - [How to visually generate tests with no coding in Cypress Studio(Cypress 10 alternative)](https://testersdock.com/cypress-studio/) 36 | - [How to mock an API using cy.intercept()](https://testersdock.com/cypress-mock-api-intercept/) 37 | - [How to integrate cypress with cucumber(Cypress 10 Upgrade)](https://testersdock.com/cypress-cucumber-bdd/) 38 | - [How to hover over elements in Cypress](https://testersdock.com/cypress-hover/) 39 | - [How to perform Database Testing(SQL) in Cypress](https://testersdock.com/cypress-database-testing/) 40 | - [How to use parents(), parent() and children() commands in Cypress](https://testersdock.com/cypress-parents-parent-children/) 41 | - [How to perform Drag and Drop on HTML and Angular sites with Cypress](https://testersdock.com/cypress-drag-and-drop-html-angular/) 42 | - [How to handle new browser tab and window in Cypress](https://testersdock.com/cypress-new-window/) 43 | - [How to use filter(), find() and within() commands in Cypress](https://testersdock.com/cypress-filter-find-within/) 44 | - [Commonly used JQuery commands in Cypress](https://testersdock.com/cypress-jquery/) 45 | - [How to do recursion in Cypress](https://testersdock.com/cypress-recursion/) 46 | - [How to handle basic auth in Cypress](https://testersdock.com/cypress-basic-auth/) 47 | - [Cypress 10 Upgrade](https://testersdock.com/cypress-10-upgrade/) -------------------------------------------------------------------------------- /testdata/test1.txt: -------------------------------------------------------------------------------- 1 | Testersdock.com --------------------------------------------------------------------------------