diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml index 698ac7eb..d8ab0b1f 100644 --- a/bitbucket-pipelines.yml +++ b/bitbucket-pipelines.yml @@ -4,16 +4,23 @@ # The workflow allows running tests and code linting on the default branch. # Node LTS -image: node:14.15.5 +image: cypress/base:14.15.4 pipelines: default: - parallel: - step: - name: Build and Test + name: Build and test caches: - node + - npm + - cypress script: - yarn install - yarn build - yarn lint + - yarn test +definitions: + caches: + npm: $HOME/.npm + cypress: $HOME/.cache/Cypress \ No newline at end of file diff --git a/package.json b/package.json index af871ed9..e3c283ae 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "build": "lerna run build", "clean": "lerna clean && rm -rf node_modules", "lint": "lerna run lint", - "test": "lerna run test" + "test": "lerna run test --stream" }, "private": true, "devDependencies": { @@ -22,7 +22,7 @@ "Ezequiel Bergamaschi" ], "engines": { - "node": "=14.15.5" + "node": "=14.15.4" }, "browserslist": { "production": [ diff --git a/packages/webapp/.gitignore b/packages/webapp/.gitignore new file mode 100644 index 00000000..b1f0ba59 --- /dev/null +++ b/packages/webapp/.gitignore @@ -0,0 +1,3 @@ +cypress/screenshots +cypress/videos +cypress/downloads \ No newline at end of file diff --git a/packages/webapp/cypress.json b/packages/webapp/cypress.json new file mode 100644 index 00000000..6e3d8315 --- /dev/null +++ b/packages/webapp/cypress.json @@ -0,0 +1,4 @@ +{ + "video": false, + "videoUploadOnPasses": false +} diff --git a/packages/webapp/cypress/README.md b/packages/webapp/cypress/README.md new file mode 100644 index 00000000..1ea5d072 --- /dev/null +++ b/packages/webapp/cypress/README.md @@ -0,0 +1,26 @@ +# Running tests with cypress. + +For details on why we picked Cypress, check the following [PR](https://bitbucket.org/wisemapping/wisemapping-react/pull-requests/1) + +Check the [Cypress docs](https://docs.cypress.io/guides/overview/why-cypress.html) for more information + +## How to run it + +- To run the test cases headless run: `yarn test` +- To debug the tests you can use cypress interactive UI by running `yarn cypress open` (You will need to have the UI running in a separate terminal `yarn start`) + + +## How to write a new test case + +Any new test cases should be added under the `cypress/integration` folder. Aim to group similar test cases in one file. + +If any stub/mock is needed, those should be added to `cypress/fixtures` folder. Cypress has a [built in way](https://docs.cypress.io/api/commands/fixture.html#Usage) of using those. + +We use `data-testid` as a practice to define selectors in the code and we leverage the [Cypress Testing Library plugin](https://testing-library.com/docs/cypress-testing-library/intro/) to find the elements in the tests. +- We leverage a `data-testid` or selecting by text (`findAllByText`, `findByText`) to make sure the test cases are decoupled from the implementation. + +We leverage the [Page Object Pattern](https://martinfowler.com/bliki/PageObject.html) to abstract away selectors and actions and simplify changes required to future refactors. Take a look to any example under the `cypress/pageObject` folder to see how that pattern is implemented. + +Finally any common functionality such as for example `login` should be abstracted into a command. CY Commands can be added into the `cypress/support` folder. Feel free to group similar commands into files (You only need to make sure those get imported into the `cypress/support/index.ts` file) + +Happy testing!!! \ No newline at end of file diff --git a/packages/webapp/cypress/integration/maps.test.ts b/packages/webapp/cypress/integration/maps.test.ts new file mode 100644 index 00000000..de55c77d --- /dev/null +++ b/packages/webapp/cypress/integration/maps.test.ts @@ -0,0 +1,16 @@ +import MapsPage from "../pageObject/MapsPage"; + +context("Maps Page", () => { + beforeEach(() => { + cy.visit("http://localhost:3000/c/maps"); + }); + + it("should load the maps page", () => { + MapsPage.isLoaded(); + }); + + it("should open the create dialog", () => { + MapsPage.create(); + MapsPage.isCreateDialogVisible(); + }); +}); diff --git a/packages/webapp/cypress/pageObject/MapsPage.ts b/packages/webapp/cypress/pageObject/MapsPage.ts new file mode 100644 index 00000000..1df20628 --- /dev/null +++ b/packages/webapp/cypress/pageObject/MapsPage.ts @@ -0,0 +1,14 @@ +export default class MapsPage { + static isLoaded() { + return cy.findByTestId("create"); + } + + static create() { + return cy.findByTestId("create").click(); + } + + static isCreateDialogVisible() { + //TODO move to findByText when the double create dialog issue is solved + return cy.findAllByText("Create a new mindmap"); + } +} diff --git a/packages/webapp/cypress/plugins/index.ts b/packages/webapp/cypress/plugins/index.ts new file mode 100644 index 00000000..5bfdbc45 --- /dev/null +++ b/packages/webapp/cypress/plugins/index.ts @@ -0,0 +1,7 @@ +/** + * @type {Cypress.PluginConfig} + */ +module.exports = (on, config) => { + // `on` is used to hook into various events Cypress emits + // `config` is the resolved Cypress config +} diff --git a/packages/webapp/cypress/support/commands.ts b/packages/webapp/cypress/support/commands.ts new file mode 100644 index 00000000..5aed0db5 --- /dev/null +++ b/packages/webapp/cypress/support/commands.ts @@ -0,0 +1 @@ +import '@testing-library/cypress/add-commands' diff --git a/packages/webapp/cypress/support/index.ts b/packages/webapp/cypress/support/index.ts new file mode 100644 index 00000000..f65e7f7c --- /dev/null +++ b/packages/webapp/cypress/support/index.ts @@ -0,0 +1 @@ +import './commands' \ No newline at end of file diff --git a/packages/webapp/package.json b/packages/webapp/package.json index 3a058104..b02fc7fa 100644 --- a/packages/webapp/package.json +++ b/packages/webapp/package.json @@ -7,6 +7,8 @@ "build": "webpack --config webpack.prod.js", "build-dev": "webpack --config webpack.dev.js", "lint": "eslint src", + "cy:run": "cypress run", + "test": "start-server-and-test start http-get://localhost:3000 cy:run", "extract": "formatjs extract", "compile": "formatjs compile" }, @@ -16,6 +18,8 @@ "private": false, "devDependencies": { "@formatjs/cli": "^2.13.15", + "@testing-library/cypress": "^7.0.3", + "@types/testing-library__cypress": "^5.0.8", "@typescript-eslint/eslint-plugin": "^4.8.1", "@typescript-eslint/parser": "^4.8.1", "brotli-webpack-plugin": "^1.1.0", @@ -23,6 +27,7 @@ "compression-webpack-plugin": "^7.1.2", "copy-webpack-plugin": "^7.0.0", "css-loader": "^5.0.1", + "cypress": "^6.5.0", "eslint": "^7.14.0", "eslint-plugin-react": "^7.21.5", "eslint-plugin-react-hooks": "^4.2.0", @@ -56,6 +61,7 @@ "react-redux": "^7.2.2", "react-router": "^5.1.8", "react-router-dom": "^5.2.0", + "start-server-and-test": "^1.12.0", "styled-components": "^5.1.7" } } diff --git a/packages/webapp/src/components/maps-page/index.tsx b/packages/webapp/src/components/maps-page/index.tsx index bff959d7..0b2b7bd7 100644 --- a/packages/webapp/src/components/maps-page/index.tsx +++ b/packages/webapp/src/components/maps-page/index.tsx @@ -145,6 +145,7 @@ const MapsPage = (): ReactElement => {