Skip to content
Open
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
36 changes: 22 additions & 14 deletions .github/workflows/parallel.yml
Original file line number Diff line number Diff line change
@@ -1,35 +1,43 @@
name: Parallel Cypress Tests

name: Run Cypress Tests using print-env
# run workflow on git push and git pull
on: [push, pull_request]

jobs:
test:
name: Cypress run
runs-on: ubuntu-20.04
# OS
runs-on: ubuntu-latest
strategy:
# when one test fails, DO NOT cancel the other
# containers, because this will kill Cypress processes
# leaving the Dashboard hanging ...
# when one test fails, DO NOT cancel the other containers, because this will kill Cypress processes leaving the Dashboard hanging ...
# https://github.com/cypress-io/github-action/issues/48
fail-fast: false
matrix:
# run 3 copies of the current job in parallel
# split tests across three containers in parallel
containers: [1, 2, 3]
steps:
- name: Print CI env variables
run: |
npm i -g @bahmutov/print-env@2
print-env GITHUB BUILD ACTIONS || true
- name: Checkout
# checks-out your repository so your workflow can access it
uses: actions/checkout@v2

# because of "record" and "parallel" parameters
# these containers will load balance all found tests among themselves
# because of "record" and "parallel" parameters these containers will load balance all found tests among themselves
- name: Cypress run
# GitHub Action for running Cypress end-to-end tests
uses: cypress-io/github-action@v2
with:
record: true
parallel: true
build: npx cypress info
group: 'Actions example'
tag: parallelPrintEnv
env:
# pass the Dashboard record key as an environment variable
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
# Recommended: pass the GitHub token lets this action correctly
# determine the unique run id necessary to re-run the checks
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Recommended: pass the GitHub token lets this action correctly determine the unique run id necessary to re-run the checks (generates dynamically)
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# running here is also fine, but you will need to look in `cypress run` instead of `Cypress tests with cypress info`
- name: Cypress tests with cypress info
uses: cypress-io/github-action@v2
with:
build: npx cypress info
22 changes: 17 additions & 5 deletions .github/workflows/single.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
name: Cypress Tests
name: Run Cypress Tests using print-env
# run workflow on git push and git pull
on: [push, pull_request]
jobs:
cypress-run:
runs-on: ubuntu-latest
steps:
- name: Print CI env variables
run: |
npm i -g @bahmutov/print-env@2
print-env GITHUB BUILD ACTIONS || true
- name: Checkout
# checks-out your repository so your workflow can access it
uses: actions/checkout@v2
# Install NPM dependencies, cache them correctly
# and run all Cypress tests
# Install NPM dependencies, cache them correctly and run all Cypress tests
- name: Cypress run
# GitHub Action for running Cypress end-to-end tests
uses: cypress-io/github-action@v2
with:
record: true
build: npx cypress info
tag: singleMachinePrintEnv
env:
# pass the Dashboard record key as an environment variable
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
# pass GitHub token to allow accurately detecting a build vs a re-run build
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# running here is also fine, but you will need to look in `cypress run` instead of `Cypress tests with cypress info`
# - name: Cypress tests with cypress info
# uses: cypress-io/github-action@v2
# with:
# build: npx cypress info
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
# Testing GitHub Actions w/ Cypress

This branch adds [print-env](https://docs.cypress.io/guides/guides/command-line#cypress-info) by [Gleb Bahmutov](https://glebbahmutov.com/) for both a single machine and parallel using 3 containers to detect and print environment variables to assist with debugging

## Notes:
- When running in parallel, print-env will be printed for each machine/node/pod etc
- This example does not remove ASCII characters, so print-env will print in several colors. This functionality can be added by adding `NO_COLOR = '1'` as an env var
- `print-env` can be added to an existing workflow or broken out into their own workflow
5 changes: 5 additions & 0 deletions cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}
143 changes: 143 additions & 0 deletions cypress/integration/1-getting-started/todo.spec.js
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