https://github.com/tyler36/cypress-demo
https://github.com/tyler36/cypress-demo
cypress github-workflow node vanilla
Last synced: 10 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/tyler36/cypress-demo
- Owner: tyler36
- Created: 2024-08-07T02:16:00.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-03-04T00:39:29.000Z (10 months ago)
- Last Synced: 2025-03-04T01:26:51.415Z (10 months ago)
- Topics: cypress, github-workflow, node, vanilla
- Language: JavaScript
- Homepage:
- Size: 2.78 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Cypress
- [Install](#install)
- [Run via Docker image](#run-via-docker-image)
- [Connecting to a locally hosted site](#connecting-to-a-locally-hosted-site)
- [Add GUI ability through WSL](#add-gui-ability-through-wsl)
- [Configure](#configure)
- [Cypress GUI font support](#cypress-gui-font-support)
- [Browser language](#browser-language)
- [Chrome](#chrome)
- [Media output](#media-output)
- [Screenshots](#screenshots)
- [Videos](#videos)
- [Reporter](#reporter)
- [Plugins](#plugins)
- [TypeScript](#typescript)
- [Cucumber](#cucumber)
- [Tips](#tips)
- [Iframes](#iframes)
- [Network stubbing](#network-stubbing)
- [Return fixture results](#return-fixture-results)
- [Dynamic](#dynamic)
- [Handling errors](#handling-errors)
- [GitHub Actions](#github-actions)
- [Node Projects](#node-projects)
- [DDEV projects](#ddev-projects)
- [Help](#help)
- [Element **not** exists](#element-not-exists)
- [Environmental Variables](#environmental-variables)
- [Basic authentication](#basic-authentication)
- [VScode](#vscode)
- ["Marcosvfranco.cucumberautocomplete-behat"](#marcosvfrancocucumberautocomplete-behat)
- [Troubleshooting](#troubleshooting)
- ["Cypress: error while loading shared libraries: libnss3.so"](#cypress-error-while-loading-shared-libraries-libnss3so)
## Install
- [Installing Cypress](https://docs.cypress.io/guides/getting-started/installing-cypress.html)
```bash
npm install cypress --save-dev
```
- Add scripts to `package.json`
```json
{
"scripts": {
...
"cypress:open": "cypress open",
"cypress:run": "cypress run"
}
}
```
- The first time Cypress runs, it can take a while to initialize.
- The `cypress` folder contains boilerplate.
- `./cypress/integration/examples` directory is safe to delete.
## Run via Docker image
- [Running Cypress via a single Docker command](https://www.cypress.io/blog/2019/05/02/run-cypress-with-a-single-docker-command/)
```bash
docker run -it --rm -v ${PWD}:/e2e -w /e2e --entrypoint=cypress cypress/included:13.11.0 run
```
| switch | description |
| -------------------------- | --------------------------------------------------------------- |
| `-it` | interactive terminal |
| `-v ${PWD}:/e2e` | `${PWD}:/e2e` maps the current directory to `/e2e` in the image |
| | - Replace `${PWD}` with `%CD%` if in CMD prompt |
| | - `${PWD}` & `$(pwd)` *should* would in PowerShell & Ubuntu |
| `-w /e2e` | set working directory to `/e2e` |
| `cypress/included:13.11.0` | Cypress image:version to use |
| `run` | command to execute |
- Show container information by replacing `run` with `info`
```bash
docker run -it --rm -v ${PWD}:/e2e -w /e2e --entrypoint=cypress cypress/included:13.11.0 info
```
- Specify a browser using the `--browser` switch. For example: `--browser chrome`, default is `electron`
```bash
docker run -it --rm -v ${PWD}:/e2e -w /e2e --entrypoint=cypress cypress/included:13.11.0 run --browser chrome
```
### Connecting to a locally hosted site
- Run command and pass an environmental variable to point to docker: `-e CYPRESS_baseUrl=http://host.docker.internal:8000`
- `https://host.docker.internal:8000` shares a local port `8000` with docker.
```bash
docker run -it --rm -v ${PWD}:/e2e -w /e2e --entrypoint=cypress -e CYPRESS_baseUrl=http://host.docker.internal:8000 cypress/included:13.11.0 run
```
### Add GUI ability through WSL
- Make sure BASH / Zsh has `DISPLAY` environment variable
```bashrc
echo $DISPLAY
```
- Run command from **`BASH`** with required switches:
- `-e CYPRESS_baseUrl=http://host.docker.internal:8000`,
- `-e DISPLAY`,
- `open --project .`
```bash
docker run -it --rm -v ${PWD}:/e2e -w /e2e --entrypoint=cypress -e CYPRESS_baseUrl=http://host.docker.internal:8000 -e DISPLAY cypress/included:13.11.0 open --project .
```
| switch | description |
| ------------- | ----------------------------------------------- |
| `-e DISPLAY` | pass the DISPLAY variable through to docker |
| `open` | open cypress |
| `--project .` | specify the project is in the current directory |
## Configure
### Cypress GUI font support
- If Cypress GUI displays `□` in the step logs, a character set/font is missing.
- A straight forward solution is to map your local font directory as a volume:
```docker
services:
cypress:
image: cypress/included:13.11.0
volumes:
- /usr/share/fonts:/usr/share/fonts/shared
```
### Browser language
- Firefox removed the language [Command Line Option](https://wiki.mozilla.org/Firefox/CommandLineOptions).
#### Chrome
- On Linux systems, set an environmental variable
```shell
export LANG="ja_JP.UTF-8"
```
- On Cypress Docker images, replicate the Linux method by update `docker-compose.yml`.
```yaml
services:
cypress:
environment:
- LANG=ja_JP.UTF-8
```
- Chrome Windows can add a [launch option](https://developer.chrome.com/extensions/i18n#locales-testing)
```js
// cypress/plugins/index.js
module.exports = (on, config) => {
on('before:browser:launch', (browser, launchOptions) => {
// Windows only!!
if (browser.family === 'chromium') {
launchOptions.args.push('--lang=ja')
return launchOptions
}
});
}
```
### Media output
#### Screenshots
- Manually take a screenshot
```js
cy.screenshot()
cy.screenshot('screengrab')
```
- Automatically take screenshot when tests fall.
```js
{
screenshotOnRunFailure: true,
}
```
- Configure the screenshot output directory:
```js
{
screenshotsFolder: 'logs/screenshots',
}
```
@see
NOTE: Sites using `height: 100%` or `sticky` elements may generate [issue](https://github.com/cypress-io/cypress/issues/2681).
Cypress stitches together viewport images to create screenshots.
This can result in elements, such as headers, scroll-to-top, or colors repeating.
- To resolves `height:100%` issues:
```js
cy.get("html, body").invoke(
"attr",
"style",
"height: auto; scroll-behavior: auto;"
);
```
- To resolve `sticky` issues
```js
cy.get('header').invoke('css', 'position', 'relative')
cy.screenshot()
```
#### Videos
- Enable Video output in `cypress.config.js`
```js
{
video: true,
}
```
- Configure the video output directory:
```js
{
videosFolder: 'logs/video',
}
```
@see
### Reporter
- To output a 'junit' log file:
```js
{
reporter: 'junit',
reporterOptions: {
mochaFile: 'logs/cypress-junit.xml',
},
}
```
## Plugins
### TypeScript
- Add TypeScript compiler
```shell
npm install ts-node typescript -D
```
- Change `.js` files to `.ts`;
- Configure `cypress/tsconfig.json`
```json
{
"compilerOptions": {
"target": "es5",
"lib": [
"es5",
"dom"
],
"types": [
"cypress",
"node"
]
},
"include": [
"**/*.ts"
]
}
```
- To help with IDE completion, add commands types to `cypress/support/index.ts`
```js
// cypress/support/index.ts
declare global {
namespace Cypress {
interface Chainable {
/**
* Custom command to select DOM element by data-cy attribute.
* @example cy.dataCy('greeting')
*/
dataCy(value: string): Chainable>
}
}
}
```
@see
### Cucumber
- Install `cypress-cucumber-preprocessor`
```bash
npm install @badeball/cypress-cucumber-preprocessor @bahmutov/cypress-esbuild-preprocessor --save-dev
```
- Update `cypress.config.js` to include `feature` files
```js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
// Determines what filetypes are considered tests.
specPattern: 'cypress/e2e/**/*.{cy.js,cy.ts,feature}',
// Add Cucumber processor plugin.
async setupNodeEvents(
on: Cypress.PluginEvents,
config: Cypress.PluginConfigOptions,
): Promise {
// This is required for the preprocessor to be able to generate JSON reports after each run, and more,
await addCucumberPreprocessorPlugin(on, config)
on(
'file:preprocessor',
createBundler({
plugins: [createEsbuildPlugin(config)],
}),
)
// Make sure to return the config object as it might have been modified by the plugin.
return config
},
},
})
```
- Add `cucumber` to `./cypress/plugins/index.js`
```javascript
const cucumber = require('cypress-cucumber-preprocessor').default
/**
* @type {Cypress.PluginConfig}
*/
module.exports = (on, config) => {
on('file:preprocessor', cucumber());
}
```
## Tips
### Iframes
- Find the element
```js
// Find the specific iframe
cy.get('iframe[name="my-iframe"]').then(($iframe) => {
// Get it contents
const iframeContents = $iframe.contents()
// Create an alias for later usage
cy.wrap(iframeContents.find('form')).as('form')
})
```
- Interact with the element
```js
// Prefix the alias name (as('form)) with @
cy.get('@form').find('[name="name"]').type('FirstName LastName')
```
### Network stubbing
#### Return fixture results
```js
describe('Network Stubbing', () => {
beforeEach(() => {
// Intercept GET calls to the URL and replace with a fixture
cy.intercept('GET', 'https://api.example.com/users', {
fixture: 'users.json'
}).as('getUsers')
})
it('Visits a website that uses an external API', () => {
cy.visit('https://www.example.com')
// Wait for the AJAX call to finish and assert response
cy.wait('@getUsers').then(({ response }) => {
expect(response.statusCode).to.equal(200)
expect(response.body).to.have.length(2)
expect(response.body[0]).to.have.property('name', 'FirstName LastName')
})
})
})
```
#### Dynamic
```js
it('Handles dynamic response', () => {
// Intercept the dynamic API route and respond with user data
cy.intercept('GET', '/api/users/*', req => {
req.reply({
statusCode: 200,
body: {
id: req.path.split('/')[3],
name: 'FirstName LastName',
email: 'fullname@example.com',
age: 30
}
})
}).as('dynamicApiRoute')
// Visit a website and wait for response from mocked API route
cy.visit('/')
cy.wait('@dynamicApiRoute')
// Assert that the response contains the correct user data
cy.get('@dynamicApiRoute')
.its('response.body')
.should('deep.equal', {
id: '1',
name: 'FirstName LastName',
email: 'fullname@example.com',
age: 30
})
})
```
#### Handling errors
```js
it('Handles errors', () => {
// Intercept an API route that returns a 500 server error
cy.intercept('GET', '/api/error', {
statusCode: 500,
body: 'Internal Server Error'
}).as('errorRoute')
// Visit the website and wait for response from mocked API route
cy.visit('/')
cy.wait('@errorRoute').then(({ response }) => {
expect(response.statusCode).to.equal(500)
expect(response.body).to.equal('Internal Server Error')
})
})
```
## GitHub Actions
### Node Projects
Use the following for Node Projects:
```yaml
- name: '✅ Run Cypress'
if: ${{ !env.ACT }} # Skip if using local runner
uses: cypress-io/github-action@v6
with:
# Install npm dependencies, cache them correctly and run all Cypress tests
build: npm run build
start: npm start
# browser: chrome
```
### DDEV projects
Use the following for DDEV-hosted projects:
```yml
jobs:
e2e:
- name: '✅ Run Cypress'
runs-on: ubuntu-latest
steps:
- name: "☁️ checkout repository"
uses: actions/checkout@v4
- name: "⚙️ Setup DDEV"
uses: ddev/github-action-setup-ddev@v1
- name: "⚙️ Setup Project"
run: |
ddev composer install
ddev artisan migrate
ddev artisan key:generate
- name: "✅ Cypress tests"
run: ddev cypress-run | grep 'All specs passed'
- name: "☁️ Archive Artifacts"
uses: actions/upload-artifact@v4
with:
name: logs
path: |
logs
```
## Help
### Element **not** exists
```js
// Text does not exist
cy.contains('pinches of pepper')
.should('not.exist')
// Element does not exist
cy.get('.foo').should('not.exist')
```
### Environmental Variables
- Add `cypress.env.json` to `.gitignore`
- Any settings in `cypress.env.json` will override `cypress.json`
```json
{
"user_name": "admin",
"user_password": "s3creT-p@ssw0rd"
}
```
```js
describe('Login', () => {
it('successfully', () => {
cy.visit('https://example.com/login')
cy.get('#user').type(Cypress.env('user_name'))
cy.get('#password').type(Cypress.env('user_password'))
cy.contains('Login').click()
})
})
```
### Basic authentication
- Set the `baseUrl` to `http://username:password@site.local` // secretlint-disable-line
## VScode
### "Marcosvfranco.cucumberautocomplete-behat"
[Homepage](https://marketplace.visualstudio.com/items?itemName=marcosvfranco.cucumberautocomplete-behat)
Settings:
```json
"cucumberautocomplete.steps": [
"cypress/support/step_definitions/**/*.js",
],
"cucumberautocomplete.strictGherkinCompletion": true,
"cucumberautocomplete.syncfeatures": "test/features/*feature"
```
## Troubleshooting
### "Cypress: error while loading shared libraries: libnss3.so"
- [Install missing libraries](https://stackoverflow.com/questions/55835870/cypress-failed-to-start-on-ubuntu-linux)
```bash
# spell-checker: disable
sudo apt-get update -y
sudo apt-get install xvfb libgtk2.0-0 libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2
# spell-checker: enable
```