用 jest + gitlab-ci 搭建前端UI自动化测试环境
前言
下面以 github创建仓库为例 测试领域中比较麻烦的就是前端UI测试
gitlab地址: https://gitlab.com/yunqiangwu/devops-test.git
前置要求
- 拥有gitlab账号(公司内部的也可以)
 
- gitlab 已经配置了 CI Runner(具体方法百度)
 
功能实现效果
- 修改过测试用例后push触发自动测试
 
- 测试完成后生成测试报告
 
- 测试报告部署到 git pages 上
 
- 发送邮件通知测试结果,以及报告查看链接
 
先看下我在实际项目中的效果,下面是我收到的自动化测试完成后的邮件:

预览地址
自动化测试报告
测试覆盖率报告  
创建项目
1 2 3 4 5 6 7 8 9
   | mkdir devops-test cd devops-test npm init 
 
  cnpm i jest jest-report nightmare --save cnpm i babel-jest babel-plugin-import babel-plugin-transform-class-properties babel-plugin-transform-decorators-legacy babel-plugin-transform-runtime   babel-preset-env --save-dev
 
   | 
 
重点依赖库介绍: 
- jest 测试框架
 
- nightmare 浏览器运行库
 
- jest-report 测试报告生产库
 
配置jest环境
- 在 
package.json 的 scripts 中叫如 test 命令 
1 2 3 4 5 6 7 8 9 10 11 12 13
   | {       "name": "devops-test",       "version": "1.0.0",       "description": "",       "main": "index.js",       "scripts": {         "test": "jest e2e.js"       },       "author": "",
             }
  | 
 
- 创建
jasmine配置文件 项目根目录/tests/jasmine.js 配置测试超时时间 
1
   | jasmine.DEFAULT_TIMEOUT_INTERVAL = 12000; 
   | 
 
- 在
package.json 中添加两个字段 babel 和 jest ,这样就能跑 es6 的代码 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
   | {   "name": "devops-test",   "version": "1.0.0",    	          "babel": {     "presets": [       "env"     ],     "plugins": [       "transform-decorators-legacy",       "transform-class-properties",       "transform-es2015-destructuring"     ]   },   "jest": {     "testResultsProcessor": "jest-report",     "setupTestFrameworkScriptFile": "<rootDir>/tests/jasmine.js",     "testMatch": [       "**/?(*.)(spec|test|e2e).js?(x)"     ]   },                     }   
  | 
 
编写测试用例
测试github登录功能<rootDir>/src/e2e/test-github-login.e2e.js 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
   | import Nightmare from 'nightmare'; import { helperBuilder } from 'jest-report';
  describe('Login', () => {     let page;     beforeEach(() => {         page = Nightmare({ show: true }).viewport(1024, 768);         page.goto('https://github.com/login');     });
                               
      it('should login with failure', async() => {         const reportHelper = helperBuilder('Login', 'should login with failure');
          reportHelper.monitorPage(page);         await page             .type('#login_field', 'mockuser')             .type('#password', 'wrong_password')             .click('input[type="submit"]')             .wait('#js-flash-container > div > div');          await page.screenshot(reportHelper.genPicturePath());         const text = await page.wait('#js-flash-container > div > div')             .evaluate(() => document.body.innerText)             .end();         await page.end();         expect(text).toContain('Incorrect username or password');     });
      it('should login successfully', async() => {         const reportHelper = helperBuilder('Login', 'should login successfully');
          reportHelper.monitorPage(page);         await page             .type('#login_field', '正确用户名')             .type('#password', '正确密码')             .click('input[type="submit"]')             .wait('#your_repos > div > div.boxed-group-action > a');          await page.screenshot(reportHelper.genPicturePath());         const title = await page             .evaluate(() => document.title)             .end();         await page.end();                  expect(title).toBe('GitHub');     }); });
 
   | 
 
运行测试生成测试报告
1. 执行命令npm test,运行测试脚步

2. 生成测试报告
生成的文件路径默认是 `<rootDir>/dist/test-report`
 
3. 测试报告效果


添加项目到gitlab
1 2 3 4 5 6
   | git init git remote add origin https://gitlab.com/yunqiangwu/devops-test.git git add . git commit -m "Initial commit" git push -u origin master
 
   | 
 
添加到持续集成
自动部署测试报告 到gitlab pages 网页
1
   | cnpm i --save-dev gh-pages
   | 
 
在 package.json 添加 scripts
1 2 3 4
   | "scripts": {   "test": "jest e2e.js",   "site": "gh-pages -d dist" },
  | 
 
 配置邮件通知工具
 <rootDir>/tool/emailnotice.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
   | #!/bin/bash MAIL_FROM='supportman@yeah.net'
  MAIL_TO_ARR_ARG=$1 MAIL_SUBJECT=$2 shift 2 MAIL_CONTENT=$* MAIL_CONTENT_FILE="/tmp/`/bin/date +%s`.txt" MAIL_SMTP='smtp://smtp.yeah.net' MAIL_USER='supportman@yeah.net' MAIL_PASSWORD='wu950429'
  OLD_IFS="$IFS"
  IFS="," MAIL_TO_ARR=($MAIL_TO_ARR_ARG) IFS="$OLD_IFS" split_1() {
    MAIL_TO=$1   echo "发送邮件到:"$1         echo "From:${MAIL_FROM} To:$MAIL_TO Subject: $MAIL_SUBJECT
  $MAIL_CONTENT "> ${MAIL_CONTENT_FILE}
       curl -s --url "${MAIL_SMTP}" --mail-from "${MAIL_FROM}" --mail-rcpt ${MAIL_TO} --upload-file ${MAIL_CONTENT_FILE} --user "${MAIL_USER}:${MAIL_PASSWORD}"
  }
  for s in ${MAIL_TO_ARR[@]} do split_1 "$s" done
  rm -rf ${MAIL_CONTENT_FILE}
 
   | 
 
gitlab-ci.yml 配置文件  .gitlab-ci.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
   |  image: jonneywu/node-xvfb-cnpm
  cache:   key: "$CI_REPOSITORY_URL"   paths:     - node_modules     - dist
  stages:  - test  - email
 
  test:    script:      - if [ ! -d node_modules ]; then cnpm i; fi      - if [ ! -d node_modules/nightmare ]; then cnpm i nightmare; fi      - export DISPLAY=':99.0'      - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &      - npm run test && echo test FAIL      - kill -9 `ps -ef | grep Xvfb| grep -v grep|awk '{print $2}'`      - npm run site    stage: test    only:      - master    artifacts:      paths:        - dist
  email:   script:     - echo email     - if [[ ! -n $MAIL_TO ]]; then export MAIL_TO=842269153@qq.com,yunqiang.wu@hand-china.com ; fi     - export root_url=http://`cat CNAME`     - export test_passed_rate=$(printf "%.2f" `cat dist/test-report/testResultData.json | jq '100*.numPassedTests/.numTotalTests'`)%     - bash ./tool/emailnotice.sh $MAIL_TO '前端自动化测试' `echo -e "  测试分支: ${CI_COMMIT_REF_NAME} \r\n 提交人:${GITLAB_USER_NAME} \r\n 测试通过率:${test_passed_rate} \r\n 触发来源:${CI_PIPELINE_SOURCE} \r\n 测试环境:mockApi环境 \r\n\r\n预览地址: ${root_url}/index.html \r\n 自动化测试报告:${root_url}/test-report/reporter.html \r\n 测试覆盖率报告: ${root_url}/coverage/lcov-report/index.html \r\n"`   stage: email   only:     - master   artifacts:     paths:       - dist
 
 
  | 
 
注意事项
- react 开发是如果用了
css modules的技术开发时,会把 class 名换掉 ,测试框架就无法通过 css selector 找到并操作 Dom元素,在开发时,可以为主要控制的dom节点给id,data-custom 自定义属性,比如用户名输入框、登录按钮, 
- 我这里的介绍的自动化测试,只是测试系统的功能交互是否能正常,如果需要靠自动化测试来判断UI界面的样式对比是符合要求,可能还是要靠人力测试,不过测试的目的保证系统功能成正常使用不出BUG。
 
参考
        
            
        
        
          
              原文链接: http://blog.jajabjbj.top/2018/05/09/2018-05-21/
              版权声明: 转载请注明出处.