點燈坊

失くすものさえない今が強くなるチャンスよ

使用 Docker Compose + MSW 執行 Cypress (Vue CLI)

Sam Xiao's Avatar 2021-06-05

雖然可以在 Cypress 的 Test 對 API 加以 Mock,但也可以使用 MSW 負責 Mock,Cypress 則完全負責 Test。

Version

Vue 2.6.11
Cypress 7.4.0
MSW 0.29.0

Docker Compose

docker-compose.yml

version: "3"
services:
  vue:
    image: nginx:alpine
    restart: always
    ports:
      - "8080:80"
    volumes:
      - ./dist:/usr/share/nginx/html
  cypress:
    image: cypress/included:7.4.0
    environment:
      - CYPRESS_baseUrl=http://vue
    volumes:
      - ./cypress:/cypress
      - ./cypress.json:/cypress.json
    command: npx cypress run

第 3 行

vue:
  image: nginx:alpine
  restart: always
  ports:
    - "8080:80"
  volumes:
    - ./dist:/usr/share/nginx/html

設定 Vue container:

  • image: nginx:alpine:使用 Nginx 官方所提供 image
  • ports::設定對外為 port 8080,對內為 port 80
  • volumns:將 dist 目錄對應用 container 內部的 /usr/share/nginx/html

10 行

cypress:
  image: cypress/included:7.4.0
  environment:
    - CYPRESS_baseUrl=http://vue
  volumes:
    - ./cypress:/cypress
    - ./cypress.json:/cypress.json
  command: npx cypress run

設定 Cypress container:

  • image: cypress/included:7.4.0:使用 Cypress 官方所提供 image
  • environment:設定 baseUrl 環境變數,直接指向 vue container
  • volumes:將專案的 cypress 目錄與 cypress.json 設定檔對應到 container 內部
  • command: npx cypress run:執行 Cypress

CYPRESS 為開頭的變數將成為 Node 環境下的全域變數

Main

main.js

import Vue from 'vue'
import worker from './mock'
import App from './App.vue'

Vue.config.productionTip = false

if (process.env.NODE_ENV === 'mock')
  worker.start()

new Vue({
  render: h => h(App),
}).$mount('#app')

process.env.NODE_ENV 判斷目前的 mode,若為 mock 則啟動 MSW。

NPM Script

package.json

"scripts": {
  "test:docker": "NODE_ENV=mock yarn build && docker compose up",
  "mock": "NODE_ENV=mock vue-cli-service serve"
},
  • test:docker:以 docker compose 執行,在 yarn build 之前加上 NODE_ENV=mock 表示以 mock 模式編譯
  • mock:以 Dev Server 執行,之前加上 NODE_ENV=mock 表示以 mock 模式執行

Conclusion

  • 直覺會想在 docker-compose.ymlenvironment 設定環境變數啟動 MSW,但這只是設定了 Nginx 的環境變數,而 Vue 是跑在 browser 內,因此 Vue 無法讀取,必須在編譯時期就將環境變數準備好