Jenkins + Gitlab + Cypress.io 實現前端CI/CD

文章分爲三部分講解,項目採用vue-cli + vue/cli-plugin-e2e-cypress配合講解javascript

vue-cli項目生成 + 基本配置(雖然是傻瓜式😅)

npm install -g @vue/cli // 能夠用yarn 習慣npm了
vue create hello-world // 建立本身喜歡的工程吧 最近樓主不推薦配置eslint 本身配置eslint + Prettier吧 standard標準不支持Prettier 😭
複製代碼
  • 修改package.json文件
"start": "vue-cli-service serve", // 開發 + 測試環境
"serve": "vue-cli-service serve --mode test", // 聯調 + 後端小姐姐
"dev": "vue-cli-service build --mode dev", // 測試環境部署
"build": "vue-cli-service build", // 線上環境部署
複製代碼
  • 增長配置文件
// 不一樣環境配置
touch .env.test
echo NODE_ENV = 'development' > .env.test
// webpack alias + webstorm配置(實在不想寫../../這種)
touch vue.config.js
const path = require('path')
module.exports = {
  configureWebpack: {
    plugins: []
  },
  chainWebpack: config => {
    config.resolve.alias
      .set('@', path.join(__dirname, 'src'))
      .set('component', path.join(__dirname, 'src', 'components'))
      .set('config', path.join(__dirname, 'src', 'config'))
// webstorm配置
commond + ,
輸出webpack
自定義配置文件 node_modules/@vue-cli/server/webpack.config.js + apply
盡情的command + B 🎇🎇🎇🎇🎇🎇
// 不喜歡用lodash get方法 以爲寫起來很差看 又不是typescript 幸虧有Babel爸爸
npm i '@babel/plugin-proposal-optional-chaining' -D
touch .babelrc
module.exports = {
  'presets': [
    '@vue/app'
  ],
  'plugins': [
    '@babel/plugin-proposal-optional-chaining'
  ]
}
const a = { c: 1 }
console.log(a?.b) // 不會中斷程序執行 是否是寫起來很舒服
複製代碼
  • 讓咱們寫一個vue Loading插件玩玩吧 😢
import Vue from 'vue'
import Loading from './Loading' // Loading 怎麼實現 自由發揮
let instance
let ZIndex = 101

const LoadingBuilder = function (type) {
  return (options) => {
    if (Vue.prototype.$isServer) return false
    options = options || {}

    let data = Object.assign({}, options, { type: type, ZIndex: ZIndex })

    instance = new Loading({
      data: data
    })
    instance.vm = instance.$mount()
    document.body.appendChild(instance.vm.$el)
    instance.dom = instance.vm.$el
    instance.vm.open()
    ZIndex = ZIndex + 1
    return instance.vm
  }
}
const LoadingComponent = {}
LoadingComponent.install = function (Vue, opts = {}) {
  const Loading = LoadingBuilder()
  Vue.$loading = Loading
  window.$loading = Loading
  Object.defineProperties(Vue.prototype, {
    loading: {
      get () {
        return Loading
      }
    },
    $loading: {
      get () {
        return Loading
      }
    }
  })
}
export default LoadingComponent
複製代碼

Cypress.io 基本配置

  • 安裝Cypress在現有項目中
vue add @vue/e2e-cypress
複製代碼
  • 目錄介紹html

    如下是自動生成的vue

├── tests
│   └── e2e
│       ├── plugins // 配置測試文件保存的地方
│       │   └── index.js
│       ├── specs // 寫測試的地方
│       │   └── test.js
│       └── support // 寫自定義命令的地方
│           ├── commands.js
│           └── index.js
複製代碼
  • 修改package.json文件
"test": "vue-cli-service test:e2e --mode dev", // 本地開發用
"test:e2e": "vue-cli-service test:e2e --headless --mode dev", // 跑Jenkins用的
複製代碼
  • 基本語法(官網確定講的比我清楚,我這個快速入門java

    • 斷言語法和其餘測試框架同樣(支持各類斷言語法,包括自定義)
      expect([]).to.be.a('Array') // 判斷類型
      expect(a.b).to.exist // 判斷屬性是否存在
      expect(1).to.be.oneOf([1,2,3]) // 判斷值是不是其中之一
      expect('testing').to.match(/^test/) // 正則匹配
      ...
      複製代碼
    • UI測試(感受和python Selenium挺像)
    describe('Test Login', () => {
        before(() ={}) // 開始鉤子
        beforEach(() => {}) // 每一個測試開始前的鉤子
        it('login', () => {
            cy.visit('/') // 訪問根目錄 cy.visit('http://localhost:3000')
            cy.url().should('include', '/login') // 斷言url 裏面包含login
            cy.get('.user-input')
                .type('Jack z')
                .should('have.value', 'Jack z') // 找到input.user-input 並輸入Jack z 斷言輸入的值是Jack z
            cy.get('.submit-button').click() // 獲取.submit-button dom 並觸發click事件
            cy.get('#navbar').contains('關於').should('have.class', 'is-active') // 獲取id爲navbar文本內容是關於且有class是is-active
            cy.wait(1000) // 等待1s
            cy.pause() // 暫停
            cy.server({method: '', header: {token: ''}, ...}) + cy.router('method', 'url', 'config') // 這個網絡請求不能debugger
            cy.request(method, url, config).then(() => {}) // 這個能夠debugger
            cy.contains().find().eq().each() // 跟JQuery同樣 找DOM作出UI的判斷
            ... // 支持動畫測試(沒用過 明試試 再補充)
        })
        after(() => {})
        afterEach(() => {})
    }
    ...
    複製代碼
    • 自定義命令
    // 自定義 setLocalStorage
    Cypress.Commands.add('setLocalStorage', (key, value) => { window.localStorage.setItem(key, value)
    cy.setLocalStorage('a', JSON.strigify('Jack z'))
    複製代碼

gitlab webhook + jenkins + jenkinsFile基本配置

  • Jenkinsfile 配置
// 項目根目錄 touch Jenkinsfile
pipeline {
    agent {
        docker {
          image 'cypress/base:10' // 這個鏡像包含了cypress運行的環境 推薦(否則你懂得 主要還得運維配合)
          args '-u root:root' // 權限配置  否則npm install fail~~~~
        }
   }

    environment {
        CHROME_BIN = '/bin/google-chrome' // 全局配置環境變量
    }
    // Jenkins流水線下的配合
    stages {
        stage('下載依賴') { // 第一步pipe
            steps {
                sh 'rm -rf node_modules'
                sh 'npm install'
                sh 'npm rebuild node-sass'
            }
        }
        stage('運行測試') { 第二步pipe
            steps {
                sh 'npm run test:e2e'
            }
        }
    }
    post {
        always {
            junit 'results/cypress-report.xml' // CI不經過的錯誤信息配置文件
            // 釘釘通知  完美通知待更新
            script {
                def msg = "【${author}】你把服務器搞掛了,老詹喊你回家改BUG!"
                def imageUrl = "https://www.iconsdb.com/icons/preview/red/x-mark-3-xxl.png"
                if (currentBuild.currentResult=="SUCCESS"){
                    imageUrl= "http://icons.iconarchive.com/icons/paomedia/small-n-flat/1024/sign-check-icon.png"
                    msg ="【${author}】發佈成功,幹得不錯!"
                }
                dingTalk accessToken:"xxxx",message:"${msg}",imageUrl:"${imageUrl}",messageUrl:"${BUILD_URL}"
            }
        }
    }
}
複製代碼
  • 建立docker Jenkinsnode

    • jenkins初始化
docker run --name devops-jenkins --user=root -p 8080:8080 -p 50000:50000 -v /opt/data/jenkins_home:/var/jenkins_home -d jenkins/jenkins:lts
docker run --name devops-registry -p 5000:5000 -v /opt/devdata/registry:/var/lib/registry -d registry
啓動完jenkins後經過瀏覽器輸入地址http://部署jenkins主機IP:端口
以後主頁面上有怎麼查看登陸的密碼
以後選擇通用配置
進來以後 開始上圖
複製代碼

輸入完管理員帳號後,點擊continue as admin 進入管理界面點擊系統管理-插件管理中安裝nodepython

node版本管理 linux

node版本管理

打包完上傳文件 webpack

打包完上傳文件

... 插件缺啥按啥git

  • 建兩個任務web

    一、一個跑測試(這個能夠包含第二個 我的喜愛)

    建任務

    建任務
    代碼位置
    代碼位置
    jenkins webhook配置(須要裝gitlab webhook插件 跟GitHub webhook區別不大 可是jenkins仍是蠻大的 有須要我再補充) 紅線有用 copy
    webhook配置
    流水線配置
    流水線配置

    二、一個跑部署

    建任務

    建任務
    代碼位置
    代碼位置
    某個任務結束都執行(須要裝插件)
    某個任務結束都執行
    配置打包和傳輸文件
    配置打包和傳輸文件

  • gitlab配置

    gitlab webhook配置 箭頭填寫上面👆畫圈地方

    gitlab webhook配置

最後,寫的不對的地方,歡迎大佬更正

相關文章
相關標籤/搜索