前端持续集成解决方案

前段时间读到一篇优秀的文章《前端开源项目持续集成三剑客》,就想试着运用到本身的项目中去。(好吧,老实说,我只是个徽章收集爱好者。)html

持续集成

持续集成,这个概念对后端来讲应该并不陌生,甚至能够说是司空见惯吧。可是,这对曾经(除了那些大厂)单元测试都不必定要写的前端来讲,或许是个陌生的词。前端

然而,随着前端飞速地发展,不断吸收后端长久以来积累的经验,以及前端对单元测试愈来愈重视,持续集成做为前端工程化中的一项也渐渐进入人们的视野。node

那么,持续集成到底是什么?react

持续集成(英语:Continuous integration,缩写为 CI),一种软件工程流程,将全部工程师对于软件的工做复本,天天集成数次到共用主线(mainline)上。 —— wikipedialinux

简单来讲,就是以必定的频率将代码整合到一块儿。git

使用持续集成能使项目:github

  • 保持可测试和可发布的状态web

  • 易于追踪错误,当集成产生错误时,能将错误产生的缩小范围到上次成功集成以后的提交chrome

  • 版本回滚也变得垂手可得npm

Travis-CI vs CircleCI

《前端开源项目持续集成三剑客》中,做者推荐了 2 个集成工具,分别是:travis-cicircleci

额...该选哪一个哪?

选择困难啊~

分别粗略地了解了这两个产品,它俩的网站的都很是简洁,文档也很清晰,功能上也大体相同。虽然,circleci 比 travis-ci 多了 Bitbucket 源码库的支持,可是,有一大硬伤 circleci 只对一个 container 免费,并且,若使用 OS X 须要额外收费。与之相反,travis-ci 只要是 Github 上的开源项目所有免费,且支持在 OS X 运行。

决定是你了

Travis-ci。

注册 travis 只需一步,点击 Sign In 按钮绑定 Github。登陆后,执行 travis 只需如下 3 步:

  1. 添加须要 travis 管理的项目

  2. 为项目添加 .travis.yml 配置文件

  3. 提交代码

与此同时,travis 的配置也极其简单。若是没有什么特别的需求,那么,只需配置运行语言类型及其版本就行。

// .travis.yml
language: node_js
node_js:
  - "6"

这样,一个简单、可用的 travis 配置就完成了。

Travis 构建过程主要分为两步:

  • install:安装依赖,在 node 环境下,默认运行 npm install

  • stript:运行构建命令,在 node 环境下,默认运行 npm test

那么,上面的代码就等价于:

language: node_js
node_js:
  - "6"
install: npm install
script: npm test

固然,travis 不止这两个生命周期,额外的配置需求均可以到官网查看

OK。提交代码试试吧。

travis 的运行信息均可以在 Job log 中看到。

若是运行成功,你就能够经过 https://img.shields.io/travis...https://img.shields.io/travis... 来给你的项目添加 badge 了,就像这样 Build Status

Tips:其中的 USER, REPO, BRANCH 都要替换成我的信息。

Codecov vs Coveralls

有了构建的徽章,接着再弄一个测试覆盖率的徽章。三剑客文章中用的是 coveralls,但进入它的官网发现,它和当今网站那种简洁风格不一样,画风有点 classic 啊~文档也不太详细,比较简单,就查了下有没有其余更好的?

因而,发现了 codecov

干净、免费,我喜欢。

文档也相对于 coveralls 更清晰、详细。在尝试以后,更是以为个人选择是明智的。^_^

codecov 的使用至关简单,甚至不用看文档就能够轻易配置。

首先,登陆首页,根据本身源码的存储位置选择相应的登陆按钮,这里我选择 Github,第一次登陆会须要你的受权。

受权成功以后,就能看到相似下面的图,分别对应你的我的帐户以及你所加入的组织。

codecov dashboard

第一次使用时,默认是没有 repository 的,须要经过点击 + Add my first repository 来添加须要 codecov 管理的 repository。

选择相应的 repository 以后,你能够看到一个相似下面的页面。固然,数据什么确定是没有的。

codecov repository detail

前几个 tab 是用来展现信息的,在配置完成并运行以前是没有信息的,配置的时候只须要看最后一个 setting tab。

codecov repository setting

切换左侧的菜单,就能分别看到 setting 和 badge 的信息,是否是超级赞?

不管 codecov 仍是 coveralls,它自身都不会去运行测试用例来得到项目代码的覆盖率,而是经过收集覆盖率报告及其余关键信息来静态分析。

codecov 能够接收 lcov, gcov 以及正确的 json 数据格式做为输入信息。

因而,若是你使用 JEST 做为测试框架,并开启测试覆盖率(collectCoverage),因为,JEST 使用 istanbul 生成覆盖率报告,即 lcov。那么,上传报告就异常简单了。只需安装 codecov

npm install codecov --save-dev

而后,在 CI 执行以后,上传报告就行。好比,像这样

language: node_js
node_js:
  - "6"
cache:
  directories: node_modules
script:
  - npm run test:coverage
  # 这里我没有全局安装 codecov,因此要经过 npm 来运行 codecov
  - npm run codecov
os:
  - linux
  - osx

此次的 badge 如何获取上面有写到,这里就再也不展现了。

SAUCELABS vs BrowserStack

跨浏览器测试一样有 2 个选择,此次我同三剑客的做者站在了同一战线,选择使用 SAUCELABS

SAUCELABS 开源免费帐号注册方式隐藏得比较好,找不到的能够点这里

不过,因为 JEST 不支持 end-to-end 测试,因此,为了作跨浏览器测试咱们不得不寻求其余的测试框架来帮助完成这一工做。这里我并不打算使用 karma,即便是 karma 同 SAUCELABS 有现成的集成插件 karma-sauce-launcher 可使用。

不要问我为何,就是这么任(jue)性(jiang)。

你真不问么?那我就说了吧。由于现有的测试框架 JEST 已经能够完成 karma 的大部分工做,单纯为 end-to-end 测试单独引入 karma 就没有必要了。

通过一番资料收集和比较以后,我选择 Nightwatch 来解决跨浏览器测试的问题。

What's Nightwatch?

Nightwatch.js is an automated testing framework for web applications and websites, written in Node.js and using the W3C WebDriver API (formerly Selenium WebDriver).

It is a complete browser (End-to-End) testing solution which aims to simplify the process of setting up Continuous Integration and writing automated tests.

能够从官网的介绍中看到,Nightwatch 对咱们当前想解决的问题简直是正中下怀啊!(若是你的项目使用的是 Angular,那么,你也能够试试 Protractor)

在查资料时,发现 nightwatch 的第一个 issue 居然是尤大大提的。

走得越远,越是发现一路都是大大们留下的足迹。

膜拜大大。

回到正题,使用 nightwatch 创建 e2e 测试也是至关容易的,这里就简要说一下流程。

首先,使用 npm 进行安装,这就很少说了。
而后,在根目录下添加配置文件,能够是 nightwatch.conf.js,也能够是 nightwatch.json。
接着,写对应的测试,API 参考官网
最后,跑测试命令就行了。

主要是来看看,怎么将 nightwatch 的测试同 saucelabs 以及 travis-ci 整合到一块儿。先看看测试文件。

// nightwatch.conf.js
module.exports = {
    src_folders: ['tests/e2e'], // 测试文件目录
    output_folder: 'tests/reports', // 测试报告地址
    custom_commands_path: 'tests/saucelabs', // 自定义命令,这里用来更新测试信息到 saucelabs
    custom_assertions_path: '',
    page_objects_path: '',
    globals_path: '',

    test_workers: {
        enabled: true,
        workers: 'auto'
    },

    test_settings: {
        default: {
            launch_url: 'http://localhost:8080', // 目标地址,用于测试中读取
            selenium_port: 4445, // selenium server 的端口(selenium server 由 saucelabs 提供)
            selenium_host: 'localhost', // selenium server 的地址(selenium server 由 saucelabs 提供)
            username: process.env.SAUCE_USERNAME,
            access_key: process.env.SAUCE_ACCESS_KEY,
            silent: true,
            screenshots: {
                enabled: false,
                path: ''
            },
            globals: {
                waitForConditionTimeout: 15000
            },
            // 如下重要!!!
            desiredCapabilities: {
                build: `build-${process.env.TRAVIS_JOB_NUMBER}`,
                public: 'public',
                'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER
            }
        },

        // 如下是不一样环境的配置
        chrome: {
            desiredCapabilities: {
                browserName: 'chrome'
            }
        },

        firefox: {
            desiredCapabilities: {
                browserName: 'firefox'
            }
        },

        internet_explorer_10: {
            desiredCapabilities: {
                browserName: 'internet explorer',
                version: '10'
            }
        },

        internet_explorer_11: {
            desiredCapabilities: {
                browserName: 'internet explorer',
                version: '11'
            }
        },

        edge: {
            desiredCapabilities: {
                browserName: 'MicrosoftEdge'
            }
        }
    }
};

这里要注意如下几点:(重要!!!这些折磨了我近一周)

  • 运行 localhost 测试,要开启 sauce connect

  • 开启 sauce connect 以后,设置运行环境 selenium_port: 4445, selenium_host: 'localhost'

以上几点是本地测试时需注意的,下面是连通 travis 时需注意的:

  • 配置 'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER,其中 process.env.TRAVIS_JOB_NUMBER 是 travis 运行时的全局变量

  • 配置 process.env.SAUCE_USERNAMEprocess.env.SAUCE_ACCESS_KEY,后面细讲

  • 配置 buildpublic 属性,分别用于标识测试和查看权限,这两点对最后生成 browser matrix badge 有用,这两点在三剑客的文章中也有提到

配置好了 nightwatch 同 saucelabs,再修改下 travis 的配置,将 saucelabs 整合进去。

// .travis.yml
language: node_js
node_js:
- '6'
cache:
  directories: node_modules
# 用于打包,并在 travis 上启动本地服务,用于 e2e test
before_script:
- npm run build
- node server.js &
script:
- npm run test:coverage
- npm run codecov
- npm run test:e2e
os:
- linux
- osx
env:
  global:
  - secure: v6CRj4CKMqxEQ9MSYKAkbmrBgIBZvoppICx6JyjQXhexPOVQKBvboCgdL0lOOZdGZ9rEqSMXvud97kBAFYd1sdP/kSwXdUct5BOMIT3a5GLtY5aQfOocBwR6IvmZpO2U+4VhrCwkzdaq2Ehq0fAXF1pkxDj9YkJZmwDNhTdfDGkib+AwDyr4TLQFC1QrD/4vmrULb3NZdW1KadFYjLzVF8FMa2tDSYMFFVymYu5nuCa/Z0dqSfFy8McYwBMzThDkDRHMT/sf4zKDPyxUwN7xGfC6T88xzCEaltN6K7MGMGKvl7Y0p7VjYW/+rO38936kj6xuPU6J7Vh2yKPJhhT2LtM7ucuo0XSpIxCxaKXWeEmYl2KkCMWNHgrWACE//WBFRNx/JQHimw+abr1Zt/3V9QmSEvnB3hHB0NQgJ2nVrVDjk51RSVaiP4sfQ8GVqEwr1+wJqe4wz7fV+jvRB9uUGgGsjsBbZi6ZycoMtOBoJ+miviRCjZvf9sOZKfIDjcuE5vETQcE37d/++yplCG0N83Kx+q67mbWXirfNj2CfXp7pwHTN+n21v1BSicXqQ6+jaNzD/pcN/GTHgZ5A+VkdcjSmEziuQTO035i1nnCB9TQdFeRdGdfo6DAiq8YOfyVkQ1lml6lWqbPqa4QWokRUD2yA/hAIzNWe5BeLF2JFQBc=
  - secure: S0vWVM74eiAHhk+kqqvym9aIgqaaGyGz9H3rfmEZoG4iuvXjXRaHOOSHxIRVsh5RYXr0PWHAj24fpN5AyUOlu5NQiwACBqmpw9KZBgVekWFshA5uYmpNpCG9w5/UAQa9q2+EcndOCM4lAyuT2wVJ5WfsHRzIA5jUpK1YmUYtuVICTSkumRoEaxfPkwzcGLF7f6aP7mG1YRKeO1F9+RhBfaGN1kYordxIk/fniH8OFB0XiLZ5OIovaAIYFKic0P1wUFwa78jU2fovdObS8JySl2LP19eaLX0MgAFoPB7oLFPxFBN7FCID41TEodDdZtcNnKJT4uQ/iWRqww2BOwVQM9whyBTg8J4kJZALicR4CzGCuUbdyQd2kh/hNZ9d9SKb6YXdcZElFmh3FY6zgfgv5PAx+jDlkfzmgBh7OD5OM4GVrsCsjnaAlmTUNtRPx9B4ps0gbr25F1PxuNy+MXfwSYJdliL+N01BTpiGyts/EXAraWvEm5YkhWfTnbgc8osd3cX9vwB0QHksK+BpkaEs6XCwU6kGMxAJIlafRv6RslREdTPBpYaXB4sGqdYXWY+YFqNxsAwTB3KWIq/uhZmSkou1jZfZa2QonMuVot68U11U7afmPzX8KOVeO2IEcUjt6I4eCYQ+31xO/wSLIQ1uoRySQ2S9VCzr+yzDpu0KVps=
addons:
  sauce_connect: true

你确定会诧异 global 下面的那两串长?是什么东西。它们其实就是在 nightwatch.conf.js 中用到的 process.env.SAUCE_USERNAMEprocess.env.SAUCE_ACCESS_KEY

那它们是怎么来的哪?

首先,安装 travis 工具 gem install travis
而后,使用 github 帐户登陆 travis login
登陆后,就能够分别使用 travis encrypt SAUCE_USERNAME=saucelabs用户名 --add
travis encrypt SAUCE_ACCESS_KEY=saucelabs的access_key --add
将 username 和 access_key 加密,--add 参数会自动将结果追加到 .travis.yml 文件中。因此,已彻底不用担忧字符贴错或贴漏。

这样整个跨浏览器测试就同 CI 集成好了,配置信息比较多,有兴趣的能够结合项目一块儿看。(点这里

最后,不要忘(tian)了(jia)初(hui)衷(zhang)。这能够在 saucelabs 的 Dashboard -> Automated Builds 下看到。

总的来讲,nigthwatch + saucelabs + travis 来作跨浏览器自动测试仍是比较方便的,只是一开始不熟悉,相应的资料也比较少,saucelabs 的文档也不够友好,耗费了些时间。覆盖率测试时, JEST 占的那点小便宜全都还回来了。

Automatically Publish

看到这里,你是否是觉得 CI 只是帮你跑跑测试、显示覆盖率?那你就错了。

CI 并非单单只能帮你跑测试,它还能够将构建成功的代码发布到服务器上。试想一下,当你将代码合并到主分支以后,CI 不但帮你运行测试,还将测试经过以后的代码发布到了你的服务器上,而不须要你人工进行额外的操做。这是否是很 cool!

这里就举一个经过 Travis-ci 将代码发布到 github.io 上的例子。

再修改一下上面 .travis.yml 文件。

language: node_js
node_js:
- '6'
cache:
  directories: node_modules
before_script:
- npm run build
- node server.js &
script:
- npm run test:coverage
- npm run codecov
- npm run test:e2e
after_success:
- bash ./deploy.sh
os:
- linux
- osx
env:
  global:
  - USER_NAME: Disciple_D
  - USER_EMAIL: disciple.ding@gmail.com
  - GIT_DEPLOY_KEY: XXXXXXXX
  - secure: v6CRj4CKMqxEQ9MSYKAkbmrBgIBZvoppICx6JyjQXhexPOVQKBvboCgdL0lOOZdGZ9rEqSMXvud97kBAFYd1sdP/kSwXdUct5BOMIT3a5GLtY5aQfOocBwR6IvmZpO2U+4VhrCwkzdaq2Ehq0fAXF1pkxDj9YkJZmwDNhTdfDGkib+AwDyr4TLQFC1QrD/4vmrULb3NZdW1KadFYjLzVF8FMa2tDSYMFFVymYu5nuCa/Z0dqSfFy8McYwBMzThDkDRHMT/sf4zKDPyxUwN7xGfC6T88xzCEaltN6K7MGMGKvl7Y0p7VjYW/+rO38936kj6xuPU6J7Vh2yKPJhhT2LtM7ucuo0XSpIxCxaKXWeEmYl2KkCMWNHgrWACE//WBFRNx/JQHimw+abr1Zt/3V9QmSEvnB3hHB0NQgJ2nVrVDjk51RSVaiP4sfQ8GVqEwr1+wJqe4wz7fV+jvRB9uUGgGsjsBbZi6ZycoMtOBoJ+miviRCjZvf9sOZKfIDjcuE5vETQcE37d/++yplCG0N83Kx+q67mbWXirfNj2CfXp7pwHTN+n21v1BSicXqQ6+jaNzD/pcN/GTHgZ5A+VkdcjSmEziuQTO035i1nnCB9TQdFeRdGdfo6DAiq8YOfyVkQ1lml6lWqbPqa4QWokRUD2yA/hAIzNWe5BeLF2JFQBc=
  - secure: S0vWVM74eiAHhk+kqqvym9aIgqaaGyGz9H3rfmEZoG4iuvXjXRaHOOSHxIRVsh5RYXr0PWHAj24fpN5AyUOlu5NQiwACBqmpw9KZBgVekWFshA5uYmpNpCG9w5/UAQa9q2+EcndOCM4lAyuT2wVJ5WfsHRzIA5jUpK1YmUYtuVICTSkumRoEaxfPkwzcGLF7f6aP7mG1YRKeO1F9+RhBfaGN1kYordxIk/fniH8OFB0XiLZ5OIovaAIYFKic0P1wUFwa78jU2fovdObS8JySl2LP19eaLX0MgAFoPB7oLFPxFBN7FCID41TEodDdZtcNnKJT4uQ/iWRqww2BOwVQM9whyBTg8J4kJZALicR4CzGCuUbdyQd2kh/hNZ9d9SKb6YXdcZElFmh3FY6zgfgv5PAx+jDlkfzmgBh7OD5OM4GVrsCsjnaAlmTUNtRPx9B4ps0gbr25F1PxuNy+MXfwSYJdliL+N01BTpiGyts/EXAraWvEm5YkhWfTnbgc8osd3cX9vwB0QHksK+BpkaEs6XCwU6kGMxAJIlafRv6RslREdTPBpYaXB4sGqdYXWY+YFqNxsAwTB3KWIq/uhZmSkou1jZfZa2QonMuVot68U11U7afmPzX8KOVeO2IEcUjt6I4eCYQ+31xO/wSLIQ1uoRySQ2S9VCzr+yzDpu0KVps=
addons:
  sauce_connect: true

能够看到,我又给它添加了一个 after_success 的配置,只有当以前的测试运行成功以后,才运行以后的命令。固然你也能够选用其余的配置,好比:deploy

要将代码发布到 github.io 上,就势必要 push 代码至仓库的 gh-pages 分支。然而,若是要经过 travis-ci 向 github 提交代码,那么,就要首先创建 ssh 连接。由于,这里是发布特定的仓库代码,因此,我推荐你们经过给 repository 设置 deploy key 的方式来给 travis-ci 受权,而不是 access token。

那么,如何设置 deploy key?

  1. 本地新建一个 ssh key(不清楚的点这里

  2. 进入 github 你要发布的仓库中,选择 settings -> Deploy keys -> Add deploy key,并将你刚刚生成的 key.pub 文件中的内容复制到输入框中,记得勾选 Allow write access,再点击 Add key。这样就设置好了 deploy key,但确定不能将 key 直接放到 github 上,须要先加密。

  3. 使用 travis 工具加密 deploy key travis encrypt-file key,这会生成一个 key.enc 文件,将这个文件加入到代码仓库中就行,不要向代码库提交生成的 key 和 key.pub 文件

  4. 加密完成后,控制台会输出一串日志,其中有相似这样的一条 openssl aes-256-cbc -K $encrypted_c7881d9cb8b5_key -iv $encrypted_c7881d9cb8b5_iv -in key.enc -out key -d,这就是用来创建 ssh 连接的。将其中 $encrypted_..._key 之间的字符提取出来,做为系统运行变量,也就是以前 .travis.yml 中的 GIT_DEPLOY_KEY: XXXXXXXX,这样发布脚步中就能使用这个变量

OK。这样 deploy key 就准备好了,下面是发布脚本。

#!/bin/bash
set -e # Exit with nonzero exit code if anything fails

# Git variables
TARGET_PATH="build/"
TARGET_BRANCH="gh-pages"

# Travis encrypt variables
ENCRYPTED_KEY="encrypted_${GIT_DEPLOY_KEY}_key"
ENCRYPTED_IV="encrypted_${GIT_DEPLOY_KEY}_iv"

# Save some useful information
REPO=`git config remote.origin.url`
SSH_REPO=${REPO/https:\/\/github.com\//git@github.com:}
SHA=`git rev-parse --verify HEAD`

# Build source
npm run build

# Set committer git info
git config user.name $USER_NAME
git config user.email $USER_EMAIL

# Force add build folder to git
git add -f $TARGET_PATH

# Commit the build code, that is a local commit for git subtree split
git commit -m "Deploy to GitHub Pages: ${SHA}"

# Split build file as a $TARGET_BRANCH of git
git subtree split -P $TARGET_PATH -b $TARGET_BRANCH

# Add ssh authorization
openssl aes-256-cbc -K ${!ENCRYPTED_KEY} -iv ${!ENCRYPTED_IV} -in deploy_key.enc -out deploy_key -d

# Change the deploy_key mod to fix ssh permissions too open error
chmod 600 deploy_key
eval `ssh-agent -s`
ssh-add deploy_key

# Push code to git
git push -f $SSH_REPO $TARGET_BRANCH

这个脚本只需简单的变量改动就能适应你的项目,固然,你也能够为本身的项目编写本身的发布脚本。

Jenkins

以上说的都是源代码放在 Github 上的开源代码,但我相信你们接触得更多的应该是本身公司的私有代码,好比和 Jira 相关的 Stash。

首先,Stash 现已更名为以前提到过的 Bitbucket,那么,只要将 travis-ci 替换成 circleci 就能够了,其他两个插件都是支持 Bitbucket 的。

其次,若是项目仓库,既不是 Github, 也不是 Bitbucket 或 Gitlab,不要着急,这时候就须要祭出万金油 Jenkins 了。

Jenkins 那成千上万的 Plugin,相信总有一款适合你。好比,老版的 stash 就能够参照这篇文章来配置。

最后

最后,回顾一下整个 CI 流程。

当代码被提交到 github 分支上时,travis-ci 会被触发开始整套的测试及发布。

首先,安装项目依赖;
而后,运行测试,其中包括 UT 和 e2e test;
测试无误后,自动将打包后的代码发布到 gh-pages 分支;
因而,就能够经过 https://用户名.github.io/项目名 访问项目了。

完成~

来看当作(hui)果(zhang)吧。查看源码点这里

关于徽章

全部的徽章信息均可以在 shields.io 中查看,甚至能够自定义徽章,就像这样 custom badge。哈哈哈~

少年们,想要集徽章么?快把测试补起来吧~

参考文章:

  1. 前端开源项目持续集成三剑客

  2. 一个靠谱的前端开源项目须要什么?

  3. Zero to Hero with End-to-End tests using Nightwatch, SauceLabs and Travis

  4. Auto-deploying built products to gh-pages with Travis

  5. Continuous Integration with Stash and Jenkins

相关文章
相关标签/搜索