├── login_spec.gif ├── examples ├── nav.spec.js ├── location.spec.js └── profile.spec.js └── README.md /login_spec.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codica2/cypress-best-practices/HEAD/login_spec.gif -------------------------------------------------------------------------------- /examples/nav.spec.js: -------------------------------------------------------------------------------- 1 | import { inputFields } from '../constants/BuyingProfile'; 2 | 3 | describe('Navigation', () => { 4 | 5 | it(`unfinished steps`, () => { 6 | cy.visit('/'); 7 | cy.get('.navigation-controls-wrapper') 8 | .contains('Continue') 9 | .click(); 10 | 11 | cy.get('.ant-steps') 12 | .children() 13 | .eq(i) 14 | .should('have.class', 'ant-steps-item-error'); 15 | }); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /examples/location.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | const checkedNode = 'ant-tree-treenode-checkbox-checked'; 4 | const indeterminate = 'ant-tree-treenode-checkbox-indeterminate'; 5 | 6 | describe('Locations', () => { 7 | before(() => { 8 | cy.visit('/locations'); 9 | }); 10 | 11 | it('Checks Austria', () => { 12 | 13 | cy.get('[role="treeitem"]') 14 | .contains('span', 'Western Europe') 15 | .closest('li') 16 | .find('.ant-tree-switcher') 17 | .click() 18 | 19 | cy.get('[role="treeitem"]') 20 | .contains('span', 'Austria') 21 | .as('Austria') 22 | .click() 23 | 24 | .closest('li') 25 | .should('have.class', checkedNode) 26 | }); 27 | 28 | it('Have required error message', () => { 29 | cy.get('.ant-tree-checkbox-checked') 30 | .click(); 31 | 32 | cy.contains('Please select at least one region!') 33 | .should('be.visible'); 34 | }) 35 | }); -------------------------------------------------------------------------------- /examples/profile.spec.js: -------------------------------------------------------------------------------- 1 | import faker from 'faker'; 2 | 3 | import { 4 | transactionType, 5 | checkboxFields, 6 | euroFields 7 | } from '../constants/Profile'; 8 | 9 | describe("Byuing profile", () => { 10 | before(() => { 11 | cy.visit('/'); 12 | }); 13 | 14 | context('Currency fields', () => { 15 | euroFields.forEach(field => { 16 | const { name, fake, required, validation } = field; 17 | const text = faker.fake(fake); 18 | 19 | it(`Test ${name} euro input`, () => { 20 | cy.get(`[data-cy="Profile.${name}"]`).as('input') 21 | .type(text) 22 | .should('have.value', `€ ${text.replace(/\B(?=(\d{3})+(?!\d))/g, ",")}`) 23 | .clear(); 24 | 25 | cy.get('.ant-form-explain') 26 | .contains(required) 27 | .should('exist') 28 | .and('be.visible'); 29 | 30 | cy.get('@input') 31 | .type(text); 32 | }); 33 | }); 34 | }) 35 | 36 | context('Checkboxes', () => { 37 | it('Test transactionType checkbox group', () => { 38 | 39 | cy.get('[type=checkbox]') 40 | .check(transactionType) 41 | .should('be.checked') 42 | .uncheck() 43 | .should('not.be.checked'); 44 | 45 | cy.get('.ant-form-explain') 46 | .contains('At least one transaction type is required!') 47 | .should('exist'); 48 | 49 | cy.get('[type=checkbox]') 50 | .check(transactionType[0]) 51 | .should('be.checked'); 52 | }); 53 | 54 | checkboxFields.forEach(checkbox => { 55 | it(`Test ${checkbox} checkbox`, () => { 56 | 57 | cy.get(`[data-cy="Profile.${checkbox}"]`) 58 | .check() 59 | .should('be.checked'); 60 | }); 61 | }); 62 | }) 63 | 64 | }); 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Testing frontend applications with Cypress 2 | ![](login_spec.gif) 3 | 4 | [Cypress](https://www.cypress.io/how-it-works/) is an all-in-one testing framework, assertion library, with mocking and stubbing, all without Selenium. 5 | ## Cypress installation 6 | Cypress is realy easy to install, just use your package manager: 7 | npm 8 | ```sh 9 | npm install cypress --save-dev 10 | ``` 11 | or yarn: 12 | ```sh 13 | yarn add -D cypress 14 | ``` 15 | ## Running Cypress 16 | After Cypress installation you can call it from your project root: 17 | ```sh 18 | ./node_modules/.bin/cypress open 19 | ``` 20 | While there’s nothing wrong with writing out the full path to the Cypress executable each time, it’s much easier and clearer to add Cypress commands to the scripts field in your package.json file. 21 | ```json 22 | { 23 | "scripts": { 24 | "cypress:open": "cypress open" 25 | } 26 | } 27 | ``` 28 | Now you can call cypress via: 29 | ```sh 30 | npm run cypress:open 31 | ``` 32 | ## Setting up CI 33 | Configure Cypress in CI is almost the same as running it locally. You generally only need to do two things: 34 | 35 | * Install Cypress 36 | ```sh 37 | npm install cypress --save-dev 38 | ``` 39 | * Run cypress 40 | ```sh 41 | cypress run 42 | ``` 43 | ## Feature tests examples 44 | Cypress uses pretty simple DSL for writing tests 45 | 46 | ```js 47 | describe("Home", () => { 48 | 49 | beforeEach(() => { 50 | cy.visit("/"); 51 | cy.get("input").first().type("test@email.com"); 52 | cy.get("input").last().type("password"); 53 | cy.server(); 54 | }); 55 | 56 | it("Should login with email and password", () => { 57 | cy.route("POST", "/api/v1/admin/user_token", "fixture:login.json"); 58 | cy.route("GET", "/api/v1/admin/contacts", "fixture:contacts.json"); 59 | cy.get("button").click(); 60 | cy.url().should("include", "/contacts"); 61 | }); 62 | 63 | it("Should not login ", () => { 64 | cy.route("POST", "/api/v1/admin/user_token"); 65 | cy.get("button").click(); 66 | cy.get(".notices").contains("Invalid login or password"); 67 | cy.url().should("include", "/login"); 68 | }); 69 | }); 70 | ``` 71 | [More examples](examples/) 72 | ## Fixtures examples 73 | Fixtures load a fixed set of data located in a file. 74 | It is very useful if you want to stub server response. 75 | For example, after login we need to include access token in the server response, we will create a file: 76 | 77 | ```fixtures/login.json``` 78 | ```json 79 | { 80 | "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdwpMeJf36POk6yJV_adQssw5c" 81 | } 82 | ``` 83 | Or return users data after GET request to ```/users``` page 84 | 85 | ```fixtures/users.json``` 86 | ```json 87 | { 88 | "data": [ 89 | { "id": 1, "attributes": { "name": "John", "email": "john@snow.qwe", "id": 1 } }, 90 | { "id": 2, "attributes": { "name": "Ned", "email": "ned@stark.com", "id": 2 } } 91 | ] 92 | } 93 | ``` 94 | ## License 95 | Copyright © 2015-2019 Codica. It is released under the [MIT License](https://opensource.org/licenses/MIT). 96 | 97 | ## About Codica 98 | 99 | [![Codica logo](https://www.codica.com/assets/images/logo/logo.svg)](https://www.codica.com) 100 | 101 | We love open source software! See [our other projects](https://github.com/codica2) or [hire us](https://www.codica.com/) to design, develop, and grow your product. 102 | --------------------------------------------------------------------------------