Jenkins + Gitlab + Cypress.io 实现前端CI/CD

Jenkins + Gitlab + Cypress.io 实现前端CI/CD

技术杂谈小彩虹2021-08-24 3:54:51260A+A-

文章分为三部分讲解,项目采用vue-cli + vue/cli-plugin-e2e-cypress配合讲解

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
  • 目录介绍

    以下是自动生成的

├── 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用的
  • 基本语法(官网肯定讲的比我清楚,我这个快速入门

    • 断言语法和其他测试框架一样(支持各种断言语法,包括自定义)
      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 Jenkins

    • 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 进入管理界面点击系统管理-插件管理中安装node

node版本管理

node版本管理

打包完上传文件

打包完上传文件

... 插件缺啥按啥

  • 建两个任务

    1、一个跑测试(这个可以包含第二个 个人喜好)

    建任务

    建任务
    代码位置
    代码位置
    jenkins webhook配置(需要装gitlab webhook插件 跟GitHub webhook区别不大 但是jenkins还是蛮大的 有需要我再补充) 红线有用 copy
    webhook配置
    流水线配置
    流水线配置

    2、一个跑部署

    建任务

    建任务
    代码位置
    代码位置
    某个任务结束都执行(需要装插件)
    某个任务结束都执行
    配置打包和传输文件
    配置打包和传输文件

  • gitlab配置

    gitlab webhook配置 箭头填写上面画圈地方

    gitlab webhook配置

最后,写的不对的地方,欢迎大佬更正

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1
本网站由 提供CDN/云存储服务

联系我们