---
# System prepended metadata

title: Cypress
tags: [實習]

---

# Cypress
###### tags: `實習`
> version 10.3.1

[TOC]

## 安裝
> [官方文件](https://docs.cypress.io/guides/getting-started/installing-cypress#What-you-ll-learn)

```javascript
$ npm install cypress --save-dev
```
安裝後就能看到 cypress 目錄了

![](https://i.imgur.com/InhDvfM.png =30%x)

## 終端機執行測試

> [官方文件](https://docs.cypress.io/guides/references/configuration#Intelligent-Code-Completion)
```=
cd 2021Intern
npx cypress run --config-file "cypress.config.js"
```

- 測試檔案的執行順序在`cypress.config.js`的 specPattern 中

```js=
specPattern: [
  "cypress/e2e/系統/帳號管理/帳號管理.cy.js",
  "cypress/e2e/IP資產管理者功能/網段管理.cy.js",
  "cypress/e2e/IP資產使用者功能/IP配發申請.cy.js",
  "cypress/e2e/IP資產使用者功能/IP配發許可.cy.js",
  "cypress/e2e/IP資產查詢/IP資產查詢.cy.js"
]
```

:::info
specPattern 的內容會影響到執行`npx cypress open`後，瀏覽器上呈現的檔案內容
:::

- 執行過程
![](https://i.imgur.com/mSz4653.png)

---

## 開啟測試執行環境
```
% npx cypress open
```
-  之後會出現下面的視窗，有 E2E Testing 和 Component Testing 兩種測試方法

    - E2E Testing：模擬使用者使用網站
    - Component Testing：檢查程式碼中元件的問題

![](https://i.imgur.com/iOR29xu.png =60%x)

- 再點選其中一個瀏覽器就能打開 Cypress 的測試環境了

    ![](https://i.imgur.com/Qqa6H6w.png =60%x)

- 進入瀏覽器後可以看到 cypress 中所有的測試檔案

    ![](https://i.imgur.com/22VdQA0.png)

- 點選測試檔進去後就會開始執行測試，右邊的畫面可以看到實際測試網頁的過程

    ![](https://i.imgur.com/BWVG5Qv.png)

---

## 目錄架構

:::info
整個架構都可以在外面的編輯器撰寫，像是 VScode

如果在寫測試檔案時，發現 Cypress 和 cy 沒有被定義而報錯，這不會影響測試執行
:::

- ### cypress/support：寫自定義方法，類似函式
    - e2e.js：support 目錄的 root
    - 目前寫好的函式結構：
        - commands.js：Login/Logout
        - formActions.js：對表單會使用到的基本操作
        - baseAction.js：對基本動作(ex:click,type...)加上 {force:true}
        
    - 操作方法
        ```javascript=
        //In /support

        Cypress.Commands.add('Login', (data) => {
          cy.visit('http://localhost:8080')
          cy.get('input[placeholder="請填入帳號"]')
            .type(data.account)
          cy.get('input[placeholder="請填入密碼"]')
            .type(data.password)
          cy.get('button')
            .contains('Login')
            .click()
        });

        //In /e2e
        cy.Login({account:'admin', password:'admin123!'})
        ```
        

- ### cypress/fixtures：存放測試資料，json 格式
    > 和其對應的函式: [cy.fixture()](#cyfixture‘’-引用-fixtures-中的資料)
    
    [fixtures 測資翻譯對照表](/5QRzIvGiSiurV9NZykJlmQ)

- ### cypress/e2e：存放測試腳本

    > 檔案格式都是 `.cy.js` 結尾


---

## 腳本基本架構

```javascript=
// 父目錄名稱
let prev = ''
// 子分頁名稱
let title = ''

it('', ()=>{
    // 要到哪個分頁
    cy.GoToPage(title)
    //如果一個腳本有兩個測試檔，就會有兩個 fixture
    //cy.fixture() 會去抓 cypress/fixtures 相對應的測資檔案
    cy.fixture(prev+title).then((data) => {
        describe('', () => {
            ...
        })
        describe('', () => {
            context('', () => {
                
            })
        })
    })
})
```

其中第 10 行的 data，就是前面 fixture 抓到的檔案

- `it()`: 撰寫測試內容的地方，會把瀏覽器資料清空
- 測試以外的內容

    |   比較   | before | beforeEach | afterEach | after |
    |:--------:| :------: | :----------: |:-----:| :---------: |
    | 執行順序 | 1      | 2          |   3   | 4         |
    | 執行時間 | `it()`前 | `it()`前 | `it()`後 | `it()`後 |
    | 執行次數 | 一次 | `it()`次數決定跑幾次 | `it()`次數決定跑幾次 | 一次 |

- `describe()`和`context()` 功能是一樣的，裡面可以包很多小測試檔，可視為一個測試的群組，這兩個要放哪都可以

---
## 指令

> [官方文件](https://docs.cypress.io/api/commands/and#Syntax)
> 每句指令前面都會加上"cy."

- 每行指令(cy.開頭)抓取的元素都是獨立的，寫到下一行就會重新抓取元素

    ```json=
    // 如果想在 input 中輸入 admin

    // Correct
    cy.get('input[placeholder="請填入帳號"]').type("admin")

    // Wrong
    cy.get('input[placeholder="請填入帳號"]')
    cy.type("admin")
    ```
    
---
## Cypress.Commands.add

> [官方文件](https://docs.cypress.io/api/cypress-api/custom-commands#Syntax)

- 各測試目錄底下的 commands.js：只有該測試目錄抓得到
- cypress/support/actions：這種的所有測試腳本都抓得到

---
## 遇到的問題

:::danger
主控台只要一出現錯誤訊息，Cypress 就會視為測試失敗
:::

- 解決方法：
    想要跳過錯誤訊息，可以在 describe() 中加入以下程式碼，就能無視錯誤訊息了
    ```javascript=
    // cypress/support/e2e.js

    Cypress.on('uncaught:exception', (err, runnable) => {
        return false
    })
    ```    
    ![](https://i.imgur.com/PcMjZvL.png =60%x)
    
:::danger
Dropdown 選到的選項失蹤或是跳到別的欄位去
:::

- 問題：

    有可能是其他欄位的選項或是標籤和現在要選的目標是一樣的，可能要避開
    1. 標籤名稱一樣：目前的做法是另外寫個函式直接指定哪個欄位(command.js)
    2. 選項一樣：選別的選項

:::danger
本來應該選到表單欄位，腳本卻選到關鍵字那邊的欄位
:::

- 問題：

    現在抓取表單欄位的方法：
    1. 利用`.el-form-item__label`元素的文字內容(表單欄位標籤)選取元素
    2. 往上一層`.el-form-item`
    3. 再往下一層`.el-form-item__content`
    
    但因為關鍵字欄位本身也是表單，也具有上面這些元素，而且腳本會優先選到關鍵字那邊的欄位，所以需要寫另外的函式直接抓到表單欄位

    ![](https://i.imgur.com/SlkwJHB.png)
    
- 解決方法：
    另外寫個函式直接指定哪個欄位(command.js)
    
:::danger
在跑`npx cypress run --config-file "cypress.config.js"`的時候，有的檔案被跳過
:::

- 解決方法：代表檔案路徑有錯


---
## cypress/support/actions：自定義函式

[連結](/fuK7j_D5RWCb6-hZ8j7x2Q)