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

feat(#92): add cypress test framework #551

Merged
merged 27 commits into from
Aug 25, 2022
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
158a53d
chore(#92): add steps to create local and Gitpod development environm…
captaindav Jul 29, 2022
323ddd4
chore(#92): add cypress to package.json and add test/cypress directory
captaindav Jul 29, 2022
b094d9a
chore(#92): added scripts to package.json
captaindav Aug 1, 2022
18ac47c
chore(#92): wip
captaindav Aug 10, 2022
cd0af7f
chore(#92): yarn lock update
captaindav Aug 14, 2022
61f0fc5
chore(#92): Add cypress scripts to package.json and added dev environ…
captaindav Aug 14, 2022
8335772
Merge branch 'develop' into feature/92-cypress-test-framework
captaindav Aug 14, 2022
b3bf023
chore(#92): improved dev environment setup info
captaindav Aug 16, 2022
f017078
chore(#92): added cyprus dependency and scripts
captaindav Aug 16, 2022
c195273
chore(#92): fixed error in druxt-site dependency
captaindav Aug 16, 2022
a3cc102
chore(#92): added login command
captaindav Aug 16, 2022
135398b
chore(#92): removed extraneous .gitkeep file
captaindav Aug 19, 2022
80cb1ed
chore(#92): update contributing guide
Decipher Aug 24, 2022
8b51bcd
chore(#92): updated cypress docs position
Decipher Aug 24, 2022
04c292c
chore(#92): fix contributing guide issues
Decipher Aug 24, 2022
8eaa321
chore(#92): add cypress to gitpod dockerfile
Decipher Aug 24, 2022
1eb7ec3
chore: update jest config
Decipher Aug 24, 2022
68bbf2c
chore(#92): update test scripts
Decipher Aug 24, 2022
b8ceb75
Merge branch 'develop' into feature/92-cypress-test-framework
Decipher Aug 24, 2022
93f678c
chore: temporarily disable login command
Decipher Aug 24, 2022
f185aea
chore(#92): test against dev
Decipher Aug 24, 2022
1b81c16
chore: removed cypress examples
Decipher Aug 24, 2022
7961bed
chore(#92): add test open script
Decipher Aug 24, 2022
138f939
chore(#92): update cypress test and config
Decipher Aug 25, 2022
23adbed
chore: remove example fixture
Decipher Aug 25, 2022
1ac0a6f
chore(#92): update circleci config
Decipher Aug 25, 2022
a612a33
chore(#92): update cypress docs
Decipher Aug 25, 2022
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
64 changes: 58 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,39 @@ Druxt is an open source project, built, supported and maintained by the communit

* * *

## Development Environment Setup
Decipher marked this conversation as resolved.
Show resolved Hide resolved

The Druxt development environment can be run both in the Cloud, using GitPod.io, or locally:

* * *

### Gitpod

1. Go to the [druxt/druxt.js](https://github.com/druxt/druxt.js) and fork the repository. e.g., `https://github.com/USER/druxt.js`
2. Open the forked repository in GitPod by appending `https://gitpod.io#` to your GitHub repository. e.g., `https://gitpod.io#github.com/USER/druxt.js`
3. Wait patiently for the environment to setup...
4. Run DruxtSite example: `yarn example:druxt-site`

GitPod will automatically run the following tasks:
- Install all core dependencies: `yarn install`
- Build the Druxt modules: `yarn build`
- Geneate the documentation: `yarn build:docs`
- Start a Drupal backend: `cd docs/drupal && ddev start -y`
- Display a welcome message: `cat .gitpod/WELCOME.md`

* * *

### Local Development

1. Go to the [druxt/druxt.js](https://github.com/druxt/druxt.js) and fork the repository. e.g., `https://github.com/USER/druxt.js`
2. Clone the forked repository to your local development environment. e.g., `git clone https://github.com/USER/druxt.js`
3. Install dependencies: `yarn`
4. Build packages: `yarn build`
5. Start a Drupal backend (requires DDev): `cd docs/drupal && ddev start -y && ddev drupal-install`
6. Run DruxtSite example: `yarn example:druxt-site`

* * *

## Bug reports, feature requests

One of the easiest ways to contribute to Druxt is to open issues, giving as much detail as possible to make it easier other contributors and maintainers: http://github.com/druxt/druxt.js/issues/new/choose
Expand All @@ -23,9 +56,10 @@ If you are able to resolve an issue, or have improvements you would like to prop

1. If this a new issue, make sure to open a bug report or feature request.
2. Fork the repository.
3. Make a `feature/#` branch from the `develop` branch.
4. Make and commit your changes.
5. Create a Pull request: https://github.com/druxt/druxt.js/compare
3. Setup a development environment (see [steps below](#development-environment-setup)).
4. Make a `feature/#` branch from the `develop` branch.
5. Make and commit your changes.
6. Create a Pull request: https://github.com/druxt/druxt.js/compare

* * *

Expand Down Expand Up @@ -72,7 +106,8 @@ The Druxt repository is setup with tools and automated processes to help with de
- [Conventional commits](#conventional-commits) - Standardised commit messages
- [Docgen](#docgen) - Documentation generator
- [Gitpod](#gitpod) - Cloud based IDE
- [Jest](#jest) - Automated testing
- [Jest](#jest) - Automated unit testing
- [Cypress](#cypress) - Automated end-to-end testing
- [Linting](#linting) - Coding styles and standards
- [Siroc](#siroc) - Zero-config build tools

Expand Down Expand Up @@ -128,10 +163,10 @@ To build your changed documentation, run the following command:
yarn build:docs
```

The documentation website is a Nuxt site located in the `/docs/nuxt` directory, to test your changes run the following command:
The documentation website is a Nuxt site located in the `/docs` directory, to test your changes run the following command:

```sh
cd docs/nuxt && yarn dev
cd docs && yarn dev
```

* * *
Expand Down Expand Up @@ -164,6 +199,23 @@ Test files are located within the relevant packages `test` directories. E.g., `p

* * *

### Cypress

Automated end-to-end testing is implemented using Cypress.

To run the Cypress tests:

```sh
yarn add node-gyp
yarn add cypress --dev
yarn run cypress install
yarn run cypress open
```

- For more details, refer to the [Cypress documentation](https://docs.cypress.io/guides).

* * *

### Linting

Code styles and standards are enforced by linting tools, including **ESLint**.
Expand Down
9 changes: 7 additions & 2 deletions examples/druxt-site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@
"dev": "nuxt dev",
"generate": "nuxt generate",
"start": "nuxt start",
"storybook": "nuxt storybook"
"storybook": "nuxt storybook",
"test:cypress:run": "npx cypress run --project test",
"test:cypress:run:mobile": "cypress run --project test --config viewportWidth=375,viewportHeight=667",
"test:cypress:open": "npx cypress open --project test",
"test:cypress:open:mobile": "cypress open --project test --config viewportWidth=375,viewportHeight=667"
},
"dependencies": {
"druxt-auth": "^0.1.0",
"druxt-site": "link:../../../packages/druxt-site",
"druxt-site": "link:../../packages/druxt-site",
"nuxt": "latest"
},
"devDependencies": {
"@nuxt/postcss8": "latest",
"@nuxtjs/storybook": "latest",
"cypress": "^10.3.0",
"postcss": "latest"
}
}
9 changes: 9 additions & 0 deletions examples/druxt-site/test/cypress.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const { defineConfig } = require("cypress");

module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
});
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/// <reference types="cypress" />

// Welcome to Cypress!
//
// This spec file contains a variety of sample tests
// for a todo list app that are designed to demonstrate
// the power of writing tests in Cypress.
//
// To learn more about how Cypress works and
// what makes it such an awesome testing tool,
// please read our getting started guide:
// https://on.cypress.io/introduction-to-cypress

describe('example to-do app', () => {
beforeEach(() => {
// Cypress starts out with a blank slate for each test
// so we must tell it to visit our website with the `cy.visit()` command.
// Since we want to visit the same URL at the start of all our tests,
// we include it in our beforeEach function so that it runs before each test
cy.visit('https://example.cypress.io/todo')
})

it('displays two todo items by default', () => {
// We use the `cy.get()` command to get all elements that match the selector.
// Then, we use `should` to assert that there are two matched items,
// which are the two default items.
cy.get('.todo-list li').should('have.length', 2)

// We can go even further and check that the default todos each contain
// the correct text. We use the `first` and `last` functions
// to get just the first and last matched elements individually,
// and then perform an assertion with `should`.
cy.get('.todo-list li').first().should('have.text', 'Pay electric bill')
cy.get('.todo-list li').last().should('have.text', 'Walk the dog')
})

it('can add new todo items', () => {
// We'll store our item text in a variable so we can reuse it
const newItem = 'Feed the cat'

// Let's get the input element and use the `type` command to
// input our new list item. After typing the content of our item,
// we need to type the enter key as well in order to submit the input.
// This input has a data-test attribute so we'll use that to select the
// element in accordance with best practices:
// https://on.cypress.io/selecting-elements
cy.get('[data-test=new-todo]').type(`${newItem}{enter}`)

// Now that we've typed our new item, let's check that it actually was added to the list.
// Since it's the newest item, it should exist as the last element in the list.
// In addition, with the two default items, we should have a total of 3 elements in the list.
// Since assertions yield the element that was asserted on,
// we can chain both of these assertions together into a single statement.
cy.get('.todo-list li')
.should('have.length', 3)
.last()
.should('have.text', newItem)
})

it('can check off an item as completed', () => {
// In addition to using the `get` command to get an element by selector,
// we can also use the `contains` command to get an element by its contents.
// However, this will yield the <label>, which is lowest-level element that contains the text.
// In order to check the item, we'll find the <input> element for this <label>
// by traversing up the dom to the parent element. From there, we can `find`
// the child checkbox <input> element and use the `check` command to check it.
cy.contains('Pay electric bill')
.parent()
.find('input[type=checkbox]')
.check()

// Now that we've checked the button, we can go ahead and make sure
// that the list element is now marked as completed.
// Again we'll use `contains` to find the <label> element and then use the `parents` command
// to traverse multiple levels up the dom until we find the corresponding <li> element.
// Once we get that element, we can assert that it has the completed class.
cy.contains('Pay electric bill')
.parents('li')
.should('have.class', 'completed')
})

context('with a checked task', () => {
beforeEach(() => {
// We'll take the command we used above to check off an element
// Since we want to perform multiple tests that start with checking
// one element, we put it in the beforeEach hook
// so that it runs at the start of every test.
cy.contains('Pay electric bill')
.parent()
.find('input[type=checkbox]')
.check()
})

it('can filter for uncompleted tasks', () => {
// We'll click on the "active" button in order to
// display only incomplete items
cy.contains('Active').click()

// After filtering, we can assert that there is only the one
// incomplete item in the list.
cy.get('.todo-list li')
.should('have.length', 1)
.first()
.should('have.text', 'Walk the dog')

// For good measure, let's also assert that the task we checked off
// does not exist on the page.
cy.contains('Pay electric bill').should('not.exist')
})

it('can filter for completed tasks', () => {
// We can perform similar steps as the test above to ensure
// that only completed tasks are shown
cy.contains('Completed').click()

cy.get('.todo-list li')
.should('have.length', 1)
.first()
.should('have.text', 'Pay electric bill')

cy.contains('Walk the dog').should('not.exist')
})

it('can delete all completed tasks', () => {
// First, let's click the "Clear completed" button
// `contains` is actually serving two purposes here.
// First, it's ensuring that the button exists within the dom.
// This button only appears when at least one task is checked
// so this command is implicitly verifying that it does exist.
// Second, it selects the button so we can click it.
cy.contains('Clear completed').click()

// Then we can make sure that there is only one element
// in the list and our element does not exist
cy.get('.todo-list li')
.should('have.length', 1)
.should('not.have.text', 'Pay electric bill')

// Finally, make sure that the clear button no longer exists.
cy.contains('Clear completed').should('not.exist')
})
})
})
Loading