Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add e2e tests #206

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"plugin:import/errors",
"airbnb",
"plugin:prettier/recommended",
"prettier/react"
"prettier/react",
"plugin:cypress/recommended"
],
"env": {
"browser": true
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ Run the following to get started locally:

**Note:** Reach out to your team lead for directions on how to receive the `CHECK_ACCESS_TOKEN`

#### Run tests

```sh
yarn test-dev
```

## Attribution

Promise Tracker is modelled on [Rouhani Meter](https://rouhanimeter.com) and made possible thank you to the generous support of DW Akademie and Meedan. Built by the Code for Africa Tech team and content courtesy of PesaCheck and ANCIR's iLab teams.
Expand Down
5 changes: 5 additions & 0 deletions cypress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"baseUrl": "http://localhost:3000",
"viewportWidth": 1536,
"viewportHeight": 960
}
23 changes: 23 additions & 0 deletions cypress/integration/actNowPage.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
describe("Act Now page", () => {
it("renders Act Now page", () => {
cy.visit("/");
cy.get("[data-cy=navigation-buttons]").contains("Act Now").click();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have we modified the navigation buttons to contain data-cy=navigation-buttons? This fails when I run locally.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The fail is probably from a timeout issue

cy.location("pathname", { timeout: 10000 }).should("include", "/act-now");
cy.get("[data-cy=actnow-desc]").contains(
"Act now and create the change you want in your area."
);
});
it("select promise to petition", () => {
cy.get("[data-cy=promise-select]").click();
cy.get("[data-cy=promise-item").first().click();
});
it("displays petiton form", () => {
cy.get("[data-cy=start-petition]").click();
cy.get("[data-cy=petition-form]").contains("Petition Title");
cy.get("[data-cy=petition-form]").contains("Category & Promise");
cy.get("[data-cy=petition-form]").contains("Recipient");
cy.get("[data-cy=petition-form]").contains("What is the Issue");
cy.get("[data-cy=petition-form]").contains("Featured Image");
cy.get("[data-cy=close-form]").click();
});
});
48 changes: 48 additions & 0 deletions cypress/integration/homePage.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
describe("Home page", () => {
it("renders Key Promises", () => {
cy.visit("/");
cy.get("[data-cy=key-promises]").contains("Key Promises");
});

it("renders Latest Promises", () => {
cy.get("[data-cy=latest-promises]").contains("Latest Promises");
cy.get("[data-cy=latest-promises]")
.find("img")
.its("length")
.then((length) => {
expect(length).to.equal(5);
});
});

it("renders Latest Articles", () => {
cy.get("[data-cy=latest-articles]").contains("Latest Articles");
cy.get("[data-cy=latest-articles]")
.find("img")
.its("length")
.then((length) => {
expect(length).to.equal(2);
});
});

it("renders Partners", () => {
cy.get("[data-cy=partners]").contains("Partners");
cy.get("[data-cy=partners]")
.find("a")
.its("length")
.then((length) => {
expect(length).to.equal(6);
});
});

it("has Neswletter section", () => {
cy.get("[data-cy=subscribe]").contains("Subscribe");
});

it("has Act Now section", () => {
cy.get("[data-cy=act-now]").contains("Act Now");
});

it("renders Latest Promises", () => {
cy.get("[data-cy=latest-promises]").contains("Latest Promises");
});
});
105 changes: 105 additions & 0 deletions cypress/integration/promisesPage.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
describe("Promises page", () => {
it("renders Promises page", () => {
cy.visit("/");
cy.get("[data-cy=navigation-buttons]").contains("Promises").click();
cy.location("pathname", { timeout: 10000 }).should("include", "/promises");
cy.get("[data-cy=promises-section]").contains("Promises");
});
it("renders Promises categories", () => {
cy.get("[data-cy=promises-section]").contains("Promises by status");
cy.get("[data-cy=promises-section]").contains("Promises by category");
});
it("filter in-progress promises", () => {
cy.get("[data-cy=promises-section]")
.find("img")
.its("length")
.then((length) => {
expect(length).to.equal(5);
});
cy.get("[data-cy=filter-buttons]").contains("In Progress").click();
cy.get("[data-cy=promises-section]")
.find("img")
.its("length")
.then((length) => {
expect(length).to.equal(3);
});
cy.get("[data-cy=filter-buttons]").contains("In Progress").click();
});

it("filter unrated promises", () => {
cy.get("[data-cy=promises-section]")
.find("img")
.its("length")
.then((length) => {
expect(length).to.equal(5);
});
cy.get("[data-cy=filter-buttons]").contains("Unrated").click();
cy.get("[data-cy=promises-section]")
.find("img")
.its("length")
.then((length) => {
expect(length).to.equal(1);
});
cy.get("[data-cy=filter-buttons]").contains("Unrated").click();
});

it("filter stalled promises", () => {
cy.get("[data-cy=promises-section]")
.find("img")
.its("length")
.then((length) => {
expect(length).to.equal(5);
});
Comment on lines +46 to +52
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm getting this correct, it means everytime the PromiseTracker team add/remove promises in Check, these tests will fail. Correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Precisely. That's the problem I have at the moment, since I am using production database it is bound to change any time. And how to mock that data is a challenge on Cypress as it runs on the client side and the pages are SSR - so they already come with the data.

cy.get("[data-cy=filter-buttons]").contains("Stalled").click();
cy.get("[data-cy=promises-section]")
.find("img")
.its("length")
.then((length) => {
expect(length).to.equal(1);
});
cy.get("[data-cy=filter-buttons]").contains("Stalled").click();
});

it("filter governance category promises", () => {
cy.get("[data-cy=promises-section]")
.find("img")
.its("length")
.then((length) => {
expect(length).to.equal(5);
});

cy.get("[data-cy=filter-buttons]").contains("Governance").click();
cy.get("[data-cy=promises-section]")
.find("img")
.its("length")
.then((length) => {
expect(length).to.equal(1);
});
cy.get("[data-cy=filter-buttons]").contains("Governance").click();
});

it("filter health category promises", () => {
cy.get("[data-cy=promises-section]")
.find("img")
.its("length")
.then((length) => {
expect(length).to.equal(5);
});
cy.get("[data-cy=filter-buttons]").contains("Health").click();
cy.get("[data-cy=promises-section]")
.find("img")
.its("length")
.then((length) => {
expect(length).to.equal(2);
});
cy.get("[data-cy=filter-buttons]").contains("Health").click();
});

it("share promise to social platforms", () => {
cy.get("[data-cy=share-button").first().click();
cy.get("[data-cy=twitter]").should("be.visible");
cy.get("[data-cy=facebook]").should("be.visible");
cy.get("[data-cy=linkedin]").should("be.visible");
cy.get("[data-cy=share-button").first().click();
});
});
17 changes: 17 additions & 0 deletions cypress/integration/singlePromisePage.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
describe("Single Promise page", () => {
it("renders promise radar", () => {
cy.visit("/promises");
cy.get("[data-cy=promises-section]").contains("Promises");
/* eslint-disable cypress/no-unnecessary-waiting */
cy.get("[data-cy=promises-section").find("a").first().click().wait(20000);
cy.get("[data-cy=promise-radar]").should("be.visible");
});
it("renders promise chart, dataset and datasource", () => {
cy.get("[data-cy=datasource]").scrollIntoView();
cy.get("[data-cy=datasource").should("be.visible");
cy.get("[data-cy=dataset]").scrollIntoView();
cy.get("[data-cy=dataset]").should("be.visible");
cy.get("[data-cy=promise-chart]").scrollIntoView();
cy.get("[data-cy=promise-chart]").should("be.visible");
});
});
21 changes: 21 additions & 0 deletions cypress/plugins/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************

// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)

/**
* @type {Cypress.PluginConfig}
*/
module.exports = () => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
};
25 changes: 25 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// ***********************************************
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need empty files like these?

// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
20 changes: 20 additions & 0 deletions cypress/support/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
import "./commands";

// Alternatively you can use CommonJS syntax:
// require('./commands')
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,13 @@
"babel-eslint": "^10.1.0",
"babel-plugin-module-resolver": "^4.0.0",
"babel-plugin-transform-imports": "^2.0.0",
"cypress": "^6.1.0",
"cypress-graphql-mock": "^0.5.0-alpha.4",
"eslint": "^7.14.0",
"eslint-config-airbnb": "^18.2.0",
"eslint-config-prettier": "^6.15.0",
"eslint-import-resolver-babel-module": "^5.1.2",
"eslint-plugin-cypress": "^2.11.2",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-json": "^2.1.2",
"eslint-plugin-jsx-a11y": "^6.4.1",
Expand All @@ -65,6 +68,8 @@
"build": "next build",
"dev": "yarn dev:next",
"dev:next": "next dev",
"cy-open": "cypress open",
"test-dev": "yarn dev & yarn cy-open",
"export": "yarn run build && next export",
"format": "yarn prettier --write --ignore-path './.gitignore' \"**/*.+(json|md|yml)\" './'",
"format-staged": "prettier --write",
Expand Down
6 changes: 5 additions & 1 deletion src/components/ActNow/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,11 @@ function ActNow({ actionLabel, description, title, ...props }) {
<Grid container className={classes.content}>
<Grid item xs={12} lg={6} container alignItems="center">
<div className={classes.textContainer}>
<Typography variant="h1" className={classes.title}>
<Typography
data-cy="act-now"
variant="h1"
className={classes.title}
>
{title}
</Typography>
<Typography
Expand Down
2 changes: 1 addition & 1 deletion src/components/DataSource/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function DataSource({ classes: classesProp, documents, label, promise }) {
return null;
}
return (
<div className={classes.root}>
<div className={classes.root} data-cy="datasource">
<div className={classes.titleShareContainer}>
<Typography className={classes.title} variant="h4">
{label}
Expand Down
7 changes: 6 additions & 1 deletion src/components/Dataset/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,12 @@ function Dataset({ dataset, ...props }) {
const hasHxlTags =
tags && tags.find((tag) => tag.name.toLowerCase() === "hxl");
return (
<Grid container direction="column" className={classes.root}>
<Grid
container
direction="column"
className={classes.root}
data-cy="dataset"
>
<A
href={`${config.CKAN_BACKEND_URL}/dataset/${name}`}
underline="none"
Expand Down
2 changes: 1 addition & 1 deletion src/components/FormDialog/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ function Form({ ...props }) {
: "body2";

return (
<form>
<form data-cy="petition-form">
<FormTextField
labelText={petitionLabel}
helperDescription={petitionHelper}
Expand Down
1 change: 1 addition & 0 deletions src/components/FormDialog/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ function FormDialog({ open, handleFormClose, ...props }) {
>
<Typography variant="h2">{petitionTitle}</Typography>
<IconButton
data-cy="close-form"
disableRipple
disableFocusRipple
aria-label="close"
Expand Down
1 change: 1 addition & 0 deletions src/components/KeyPromises/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ function KeyPromises({ actionLabel, items, title, titleProps, ...props }) {
return (
<div className={classes.root}>
<Section
data-cy="key-promises"
title={title}
titleProps={{ ...DEFAULT_TITLE_PROPS, ...titleProps }}
classes={{ root: classes.section, title: classes.sectionTitle }}
Expand Down
1 change: 1 addition & 0 deletions src/components/LatestArticles/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ function LatestArticles({ actionLabel, items, title, ...props }) {
}
return (
<Section
data-cy="latest-articles"
title={title}
classes={{ root: classes.section, title: classes.sectionTitle }}
>
Expand Down
1 change: 1 addition & 0 deletions src/components/LatestPromises/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ function LatestPromises({ actionLabel, items, title, ...props }) {
}
return (
<Section
data-cy="latest-promises"
title={title}
classes={{ root: classes.section, title: classes.sectionTitle }}
>
Expand Down
Loading