- cypress-e2e-starter
- Introduction
- Getting Started
- Build and Test
- Contribute
- Appendix
- Rules
- indent
- linebreak-style
- quotes
- semi
- camelcase
- curly
- max-len
- no-mixed-spaces-and-tabs
- no-trailing-spaces
- no-multiple-empty-lines
- object-curly-newline
- @typescript-eslint/typedef
- operator-linebreak
- dot-location
- comma-spacing
- func-call-spacing
- key-spacing
- newline-per-chained-call
- @typescript-eslint/naming-convention
- sort-imports
- @stylistic/ts/padding-line-between-statements
- cypress/no-assigning-return-values
- cypress/no-unnecessary-waiting
- cypress/assertion-before-screenshot
- cypress/no-force
- cypress/no-async-tests
- cypress/no-pause
- Links
- Steps to create this proj from zero
- Rules
The objective of this project is to have a starter project that can be used when a new Cypress
testing project needs to be created. This can be used completely if the new test project is independent from the development one, in the other case this can also be used as a guide.
To be able to use this project Node.js and yarn need to be installed. This project is done using Typescript
so to be able to use it some knowledge of javascript, typescript, and how to use Cypress
. All the information/instructions in this document will be using a GNU/Linux
operating system.
This project, besides the main objective described in the Introduction, has the idea of setting some structure to organize the files, linting rules to have the code clean, and to implement the Page Object Model (POM)
.
To lint the project the ESLint is set in place with some rules configured in the file .eslintrc.json
and the rules could be changed, removed or add more. If the IDE used is the VS Code/VS Codium the ESLint extension could be installed and configured to give feedback if some rule is broken. Some VS Code configurations are already committed in the project, as some configurations for the extension.
To be comfortable using this we should have some knowledge on the OS that is using, and knowledge in the tools that are used.
Install the project dependencies, they are all defined in the package.json
, so just run in the project root path:
yarn
The package.json
file has some already created shortcuts to in the scripts
section to ease the use of Cypress
. More shortcuts can be added, or change the ones that were already created.
If using the VS Code in some cases it will confuse the Cypress
commands with other libraries when giving the help, to prevent this we should add 1 line at the top of every file that will have Cypress
code. So in every file add the following line:
///<reference types="cypress"/>
And it is basically it, the requirements are installed and every thing is in place to start creating and executing the tests.
It is not a good practice to store credentials to the test environment in the code, since this way they are store in every computer that can clone the project in plain text. A better approach to this that can leverage functionalities from the CI/CD tools is to use environment variables, not the environment variables stored in Cypress
config file but the OS
ones. They can be stored in the CI/CD tool and even can be stored as not readable by the users.
Cypress
can read automatically the OS
environment variables if we create the variables starting with CYPRESS_
or cypress_
, and we can retrieve the values the same way as if we created them in the configuration file.
For example:
export CYPRESS_HOST=dev.local
export cypress_api_server=http://localhost:8888/api/v1/
Can retrieve the values:
Cypress.env()
Cypress.env('HOST')
Cypress.env('api_server')
If we need to have access to the values in the configuration file, if they need to be used in a task
, we can use the following:
config.env.HOST
config.env.api_server
When creating E2E tests there are some issues testing under a mutable environment, in some cases the information in the environment is generated by a 3rd party or by hardware out of the testing control. With this type of context is hard to add E2E tests and to add the most coverage to the project, one way to add some more coverage can be interacting with the environment database, or with 3rd party databases where we can retrieve or add data to bypass or to assert.
For accessing to a Postgresql
can be used the pg
package that is a pure JavaScript client with some abstractions that enables the connection and query to this type of databases. To implement this and to handle the async operation one way is to use define Cypress tasks
in the config file and the .then()
function to wait and use the data retrieved.
cypress.config.ts
import { Client } from 'pg';
import Query from 'pg/lib/query';
on('task', {
async connectDB() {
const client: typeof Client = new Client({
host: config.env.db_host,
port: config.env.db_port,
database: config.env.db_dbname,
user: config.env.db_user,
password: config.env.db_passwd,
ssl: true
});
await client.connect();
const res: Query = await client.query('SELECT * FROM thetable order by created_at desc');
await client.end();
return res.rows[0];
}
});
test.cy.ts
cy.visit('/');
cy.task('connectDB')
.then((row: unknown) => {
cy.log(row['data']);
cy.get('#input')
.type(row['data']);
});
Links to the pg
official repository are in the Links section.
There are still some tests to be done to better understand how to implement this in real tests and how useful this can be.
There is an issue using this package related with certificates, to bypass it we can use the NODE_TLS_REJECT_UNAUTHORIZED
environment variable. The variable should be set to 0
in the environment before stating the tests.
export NODE_TLS_REJECT_UNAUTHORIZED=0 && yarn cy:open:chrome
In case the need to have and maintain multiple configuration files, like when we need to have a configuration to run locally and another to run in a pipeline, the number of environment variables and Cypress configurations could keep building in as the cost to maintain. One approach to keep this simple and easy to maintain is to create a base configuration file that has all the sharable configurations and use that to extend the other configurations.
There is some experiment of this approach with the base file cypress.config.js
that has the shared configuration and is used to run the tests locally during the tests development/maintenance. To run the tests in headless mode and in a pipeline a test report is an important feature, so there is another configuration file cypress.ex.config.ts
that import the base one and add the configurations related to the report.
At the moment didn't found a way to better handle the plugins, or all the plugins are implemented in base file and they will be imported to the other one. In case new plugins need to be added to the new file, it is required to add all the base plugins and the new ones so basically copying the setupNodeEvents
block from the base to the new.
To run tests with the base configuration file, use the following scripts:
yarn cy:open:chrome
yarn cy:run:chrome
To run the new configuration extending the base use:
yarn ex:run:chrome
yarn ex:run:firefox
To be able to force some rules regarding code format, commit messages, etc... we can use the GIT Hooks to add scripts that are triggered in each stage, this can be used to execute checks in the code, in the message, or even run tests.
In a first iteration, this project had a script to run the linter and another script that should be executed to set the previous as a hook. After some investigation the Husky package appeared. Husky will basically manage the hook scripts without the need to to set them in place, the scripts are stored in the .husky
folder and it will handle the integration with GIT Hooks.
Currently the project has two hooks integrated with Husky and it's only need to install the project packages and the package will handle the rest.
If a you want to change, correct, improve the project create an issue
in the project Issues
screen with the proposal and the necessary documentation. If the proposal or correction has already the implementation developed link the branch with the change in the issue
.
This rule enforces a consistent indentation style.
- error
- tab
This rule enforces consistent line endings independent of operating system, VCS, or editor used across your codebase.
- error
- unix
This rule enforces the consistent use of either backticks, double, or single quotes.
- error
- single
This rule enforces consistent use of semicolons.
- error
- always
Enforce camelcase naming convention.
- error
This rule is aimed at preventing bugs and increasing code clarity by ensuring that block statements are wrapped in curly braces. It will warn when it encounters blocks that omit curly braces.
- error
- all
This rule enforces a maximum line length to increase code readability and maintainability. The length of a line is defined as the number of Unicode characters in the line.
- error
- code: 150
This rule disallows mixed spaces and tabs for indentation.
- error
This rule disallows trailing whitespace (spaces, tabs, and other Unicode whitespace characters) at the end of lines.
- error
This rule aims to reduce the scrolling required when reading through your code. It will warn when the maximum amount of empty lines has been exceeded.
- error
- max: 1
- maxBOF: 0
- maxEOF: 1
This rule requires or disallows a line break between { and its following token, and between } and its preceding token of object literals or destructuring assignments.
- error
- multiline: true
This rule can enforce type annotations in locations regardless of whether they're required. This is typically used to maintain consistency for element types that sometimes require them.
- error
- "variableDeclaration": true,
- "variableDeclarationIgnoreFunction": false,
- "arrowParameter": true,
- "parameter": true,
- "propertyDeclaration": true
This rule enforces a consistent linebreak style for operators.
- error
- after
This rule aims to enforce newline consistency in member expressions. This rule prevents the use of mixed newlines around the dot in a member expression.
- error
- property
This rule enforces consistent spacing before and after commas in variable declarations, array literals, object literals, function parameters, and sequences.
- error
- "before": false
- "after": true
This rule requires or disallows spaces between the function name and the opening parenthesis that calls it.
- error
- never
This rule enforces consistent spacing between keys and values in object literal properties. In the case of long lines, it is acceptable to add a new line wherever whitespace is allowed.
- error
- "align": "value"
- "afterColon": true
This rule requires a newline after each call in a method chain or deep member access. Computed property accesses such as instance[something] are excluded.
- error
- "ignoreChainWithDepth": 1
Enforcing naming conventions helps keep the codebase consistent, and reduces overhead when thinking about how to name a variable.
- error
- "selector": ["variable", "function"]
- "format": ["camelCase"]
- "leadingUnderscore": "forbid"
- "trailingUnderscore": "forbid"
- error
- "ignoreCase": true,
- "ignoreDeclarationSort": false,
- "ignoreMemberSort": false,
- "memberSyntaxSortOrder": ["none", "all", "single", "multiple"],
- "allowSeparatedGroups": true
- error
- "blankLine": "always"
- "prev": "expression", "next": "expression"
- "prev": "if", "next": "if"
- "prev": "expression", "next": "if"
- "prev": "if", "next": "expression"
- "prev": "var", "next": "if"
- "prev": "if", "next": "var"
- "prev": "const", "next": "if"
- "prev": "if", "next": "const"
- "prev": "let", "next": "if"
- "prev": "if", "next": "let"
- "prev": "var", "next": "expression"
- "prev": "let", "next": "expression"
- "prev": "const", "next": "expression"
- "prev": "expression", "next": "var"
- "prev": "expression", "next": "let"
- "prev": "expression", "next": "const"
- error
- error
- warn
- warn
- error
- error
- Cypress
- Cypress Writing and Organizing Tests
- Cypress configuration
- Cypress typescript
- Cypress plugins
- Cypress Environment Variables
- Javascript
- Typescript
- ESLint
- ESLint Stylistic
- pg
- pg FAQ
- Faker
- cypress-mochawesome-reporter
- yarn init
- yarn add --dev typescript
- yarn add --dev cypress
- ./node_modules/cypress/bin/cypress open
- press E2E Testing button
- press Continue button
- select a browser and press Start E2E Testing in ...
- press Create new spec button
- press Create spec, and Okay, run the spec buttons
- yarn add --dev eslint eslint-plugin-cypress
- npm init @eslint/config