Cypress Workshop Part 2: Code quality and static analysis
Tags: cypress, qa, automation, testing
Published: 2023-05-12 16:28:12

## LESSON 2: Code quality and static analysis


**A Brief Overview**

Firstly, we will discuss the purpose of linters. Put simply, a linter is a tool that assists in enhancing your code. While linters are not specific to JavaScript, it is predominantly JavaScript (or similar dynamically-typed languages) that attracts most individuals seeking information about linters. Linter functions as a valuable aid in code improvement. How does it achieve this? By thoroughly analysing your source code to identify any issues.

Now, what exactly is static analysis? Think of it as a form of pre-execution debugging. Static analysis involves utilizing specialized tools that thoroughly examine your source code for errors, deviations from established rules or conventions, and other potential problems.

**Benefits of Linting**

*Reduced production errors*: Linters play a crucial role in identifying and resolving technical issues, such as code smells, security issues or typos. This results in fewer defects slipping into the production environment.

*Improved code readability, maintainability, and consistency*: Linters contribute to achieving a more readable and consistent code style by enforcing specific rules. This helps teams maintain code that is easier to understand and maintain.

*Streamlined code review*: Linters eliminate lengthy debates over code style and aesthetic choices during code reviews. By adhering to the rules set by the linter, discussions can focus on more critical aspects of the code.

*Objective assessment of code quality*: Code quality discussions often involve subjective opinions. Linters provide an objective and quantifiable evaluation of code quality, enabling a more data-driven approach.

*Enhanced security and performance*: While not all linters analyse code for performance and safety, some do. These linters help identify potential security vulnerabilities and performance bottlenecks, resulting in more secure and efficient code.

*Increased exposure to code quality education*: Linters serve as valuable educational tools, especially for inexperienced developers. They assist in familiarizing developers with code quality standards and best practices, promoting continuous learning and improvement.

**Types of Checks Linters Provide**

1. Syntax Errors
3. Code Standards
5. Code Smells
7. Security Checks

**Importance of Linters in test automaton**

Test automation code is as important as application (development) code itself. It should also follow best coding standards. Without ensuring the quality of test automation code, we can’t assure application code either, since bugs in testing code mean flaky tests, test script bugs, and eventually failure of bug discovery in application code. 

**Linter installation in workshop project**

1: Install ESLint, Prettier and Husky libraries : Open VS terminal and execute following commands one after another. 

`npm install eslint --save-dev`

`npm install eslint-config-airbnb --save-dev`

`npm install eslint-config-prettier --save-dev`

`npm install eslint-plugin-chai-friendly --save-dev
`
`npm install eslint-plugin-cypress --save-dev
`
`npm install eslint-plugin-import --save-dev
`
`npm install eslint-plugin-jsx-a11y --save-dev
`
`npm install eslint-plugin-prettier --save-dev
`
`npm install eslint-plugin-react --save-dev
`
`npm install husky --save-dev
`
`npm install prettier --save-dev 
`

:eyes: To read: 

What is ESLint? [ESLint](https://eslint.org/)
What is Prettier? [Prettier](https://prettier.io/)
What is Husky? [Husky](https://khalilstemmler.com/blogs/tooling/enforcing-husky-precommit-hooks/)
Eslint plugin vs extends: [Plugins/Extends](https://prateeksurana.me/blog/difference-between-eslint-extends-and-plugins/)

2: Add ESLint and Prettier configuration in project root:

Open your VS terminal and execute the following commands one after another: 

`touch .eslintrc.json
`
`touch .prettierrc.json
`
You will see that those two files are created in project root. 

Open `.eslintrc.json` and type the following: 

```json
{
    "plugins": [
      "cypress",
      "chai-friendly",
      "prettier"
    ],
    "extends": [
      "airbnb",
      "prettier"
    ],
    "rules": {
      "no-unused-expressions": 0,
      "chai-friendly/no-unused-expressions": 2,
      "cypress/no-force": 0,
      "cypress/no-async-tests": "error",
      "prettier/prettier": ["error"],
      "camelcase": 0,
      "no-plusplus": 0,
      "func-names": 0,
      "class-methods-use-this": 0,
      "no-prototype-builtins": 0,
      "no-restricted-syntax": 0,
      "radix": 0,
      "consistent-return": 0
    },
    "env": {
        "cypress/globals": true
      }
}

```

Open `.prettierrc.json` and type following: 

```json
{
    "printWidth": 100,
    "singleQuote": true
}
```
3: Add commands to `package.json` file

```json
{
  "name": "cypress-workshop",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "cypress-cli": "cypress open",
    "cypress-headed": "cypress run -b chrome",
    "cypress-headless": "cypress run --headless -b chrome",
    "eslint": "eslint cypress",
    "eslint-fix": "eslint cypress --fix"
  },
  "author": "",
  "license": "ISC",
  "husky": {
    "hooks": {
      "pre-commit": "npm run eslint-fix"
    }
  },
  "devDependencies": {
    "cypress": "^10.0.0",
    "eslint": "^8.16.0",
    "eslint-config-airbnb": "^19.0.4",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-chai-friendly": "^0.7.2",
    "eslint-plugin-cypress": "^2.12.1",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-jsx-a11y": "^6.5.1",
    "eslint-plugin-prettier": "^4.0.0",
    "eslint-plugin-react": "^7.30.0",
    "husky": "^8.0.1",
    "prettier": "^2.6.2"
  }
}
```
So - now with everything installed and written for linters, every time you want to check your code, you can run in your VS terminal: 

`npm run eslint
`
If you discover there are errors, you will see error logs, and you will be able to identify what is wrong in the code. Some errors can be fixed automatically, so if you want to do that, just run:

`npm run eslint-fix 
`
and code will be fixed for you automatically. 

Make it a habit to check the quality of your code before you push anything to GitHub. If in case you forget, that is why we set up Husky hook. What this will do is prevent you to commit code to GitHub if there are errors. As you can see in `package.json` we defined which command will be executed when you try to commit something to GitHub `"pre-commit": "npm run eslint-fix"`. ESLint will try to automatically fix your errors and if you had any, you will obviously have a change in code base, which means you have to run 

`git add .
`
again, and then try to commit the change again. If you still see errors, that means that those specific errors can’t be fixed automatically, and you will have to change your code manually according to guidance provided in ESLint log. 

An example error from ESLint would look something like this: 


![ESLint error: I forgot to close the bracket { in the test](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/currpbrzm45b57giq6ag.png)

This is an example where I can’t fix this error by running `npm run eslint-fix `. I have to go to the file specified in the log and look for my error on line 32. 


## LESSON 3 PREPARATION: 

Please do the following steps to prepare for Lesson 3. These changes are not related to Lesson 2, but we need them for lesson 3. 

1: Add error handler under `support/e2e.js`:

The reason why we need this is because we don’t want that our test execution fail because of console error events in the production application. This is something the people usually decide on the project if they should test or not, but for the purposes of this workshop we won’t bother with application error events in the console. 


![Example of the application error that would stop cypress code from running](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2g330gdy4e33tk8buytk.png)

```javascript
// Import commands.js using ES2015 syntax:
import './commands';

// Alternatively you can use CommonJS syntax:
// require('./commands')
Cypress.on('uncaught:exception', () => false);

```

![error handler](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/792hk0fizj9bear40z9d.png)

Read more about cypress event types: [Link](https://docs.cypress.io/api/events/catalog-of-events#Event-Types)

2: Add Cypress configuration in `cypress.config.js` file  

This is the configuration where we define how would we want Cypress to run our tests, how long to wait on commands, if we want to retry tests if they fail, set the size of runner window etc. 

```javascript
const { defineConfig } = require("cypress");

module.exports = defineConfig({
  defaultCommandTimeout: 5000,
  video: false,
  screenshotOnRunFailure: false,
  chromeWebSecurity: false,
  retries: 3,
  viewportWidth: 1920,
  viewportHeight: 1080,

  e2e: {
    baseUrl: 'https://demoqa.com',
    setupNodeEvents(on, config) {
      // implement node event listeners here
    },
  },
});
```
[Config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ah97wlrk53yypxoan59u.png)

Learn more about cypress config: [Cypress Config](https://docs.cypress.io/guides/references/configuration#cypress-json)

## :pencil2: HOMEWORK: 

Read about linters from the above links, and try to understand their purpose. You should be able to tell the purpose of Linters and why it is important to maintain good code quality.

Don’t forget to push everything you did today on Github :wink: Remember git commands? :wink: 

`git add .
`
`git commit -am "add: linter support and cypress configs" 
`
`git push 
`

<img width="100%" style="width:100%" src="https://media2.giphy.com/media/qBVuJruzlI4zPLeWjp/200w.gif?cid=6c09b952c1v9wd480fkrqynphdj5oksnx6x8yv4o99cruw6p&ep=v1_gifs_search&rid=200w.gif&ct=g">

THANK YOU AND SEE YOU SOON IN LESSON No.3!:raised_hands: 

[Completed code for this lesson](https://github.com/ViktorijaFilipov/cypress-workshop/tree/main/LESSON_2)

If you have learned something new, feel free to support my work by buying me a coffee :coffee:

[![Buy Me A Coffee][2]][1]

[1]: https://www.buymeacoffee.com/viktorija3141
[2]: https://cdn.buymeacoffee.com/buttons/default-black.png