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 21 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
3 changes: 3 additions & 0 deletions .gitpod/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ SHELL ["/bin/bash", "-c"]

RUN sudo apt-get -qq update

# Install cypress dependencies
RUN sudo DEBIAN_FRONTEND=noninteractive apt-get install -y libgtk2.0-0 libgtk-3-0 libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb

# Install ddev
RUN brew update && brew install drud/ddev/ddev

Expand Down
60 changes: 56 additions & 4 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 above](#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 @@ -70,9 +104,10 @@ The Druxt repository is setup with tools and automated processes to help with de
- [Changesets](#changesets) - Changelog and versioning
- [Codecov](#codecov) - Automated code coverage
- [Conventional commits](#conventional-commits) - Standardised commit messages
- [Cypress](#cypress) - Automated end-to-end testing
- [Docgen](#docgen) - Documentation generator
- [Gitpod](#gitpod) - Cloud based IDE
- [Jest](#jest) - Automated testing
- [Jest](#jest) - Automated unit testing
- [Linting](#linting) - Coding styles and standards
- [Siroc](#siroc) - Zero-config build tools

Expand Down Expand Up @@ -118,6 +153,23 @@ A **husky** git hook is used to ensure the standard is enforced, and will explai

* * *

### 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).

* * *

### Docgen

Druxt uses a custom Docgen module to generate API documentation from the package source code, using a combination of **JSDoc** and the **Vue Docgen API**.
Expand Down
16 changes: 13 additions & 3 deletions examples/druxt-site/package.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
{
"name": "druxt-site",
"scripts": {
"cypress:open": "npx cypress open --project test",
"cypress:run": "npx cypress run --project test",
"dev": "nuxt dev",
"generate": "nuxt generate",
"serve": "yarn generate && yarn start",
"start": "nuxt start",
"storybook": "nuxt storybook"
"storybook": "nuxt storybook",
"test": "start-server-and-test 'yarn dev' http://localhost:3000 'yarn cypress:run'",
Decipher marked this conversation as resolved.
Show resolved Hide resolved
"test:cypress:run": "yarn cypress:run",
"test:cypress:run:mobile": "yarn cypress:run --config viewportWidth=375,viewportHeight=667",
"test:cypress:open": "yarn cypress:open",
"test:cypress:open:mobile": "yarn cypress:open --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",
"postcss": "latest"
"cypress": "^10.3.0",
"postcss": "latest",
"start-server-and-test": "^1.14.0"
}
}
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