在Cypress运行时,通常采用​​cypress run​​​或者​​cypress open​​命令,但这不是唯一的运行方式,Cypress允许将它视为一个Node Module来运行,这种方式可以使你更加灵活地定制测试行为,比如挑选测试用例执行、整个测试用例执行并形成完整的HTML测试报告、重新运行单个失败的Spec文件、针对失败的用例并发送通知给用户,并且附带错误截图等等

cypress.run()

cypress.run()支持的参数跟cypress run支持的参数一样

//cypress.run()实例
const cypress=require('cypress')
describe('ModuleAPIExample',()=>{
beforeEach(()=>{
console.log('test')
})
it('test Module API', ()=>{
cypress.run({
//要测试的spec
spec.'./iTesting.js',
//运行的配置文件
config:'../../cypress.json'
})
.then((results)=>{
console.log(results)
})
.catch((err)=>{
console.error(err)
})
})
})

cypress.open()

cypress.open()支持的参数跟cypress open支持的参数一样

//cypress.open()实例
const cypress=require('cypress')
describe('ModuleAPIExample', ()=>{
beforeEach(()={
console.log('test')
})
it('teset Module API',()=>{
cypress.open()
})
})

Module API 实践

挑选测试用例执行

//将命令行切换到项目根目录下例如E:\Cypress
//安装globby
npm install globby --save-dev
//安装console.table
npm install console.table --save-dev

然后再E:\Cypress\cypress\integration文件夹下创建3个测试文件

//first-spce.js
/// <reference types="cypress" />
describe('第一个用例', () => {
it('测试 Module API', () => {
expect(1).to.equal(1)
})
it('测试 Module API', () => {
expect(2).to.equal(2)
})
})
/// <reference types="cypress" />
describe('第二个用例', () => {
it('测试 Module API', () => {
expect(1).not.equal(2)
})
})
//第三个测试文件
/// <reference types="cypress" />
describe('第 3 个用例', () => {
it('测试 Module API', () => {
expect('iTesting').to.equal('iTesting')
})
})

然后在E:\Cypress中创建​​testPickRunSimple.js​

///<reference types="cypress"/>
const cypress = require('cypress')
const globby = require('globby')
const Promise = require('bluebird')
const fs = require('fs')
require('console.table')

//待运行用例,实际项目中您从外部文件读入。
//本例简写,仅为演示 Module API的使用
const constFileList = ['./cypress/integration/first-spec.js', './cypress/integration/third-spec.js']

//判断仅运行存在于 constFileList 中的测试用例。
const filterCaseToRun = (filenames) => {
const withFilters = filenames.map((filename) => ({
filename,
run: constFileList.includes(filename),
}))

for (const i in withFilters) {
if (withFilters[i].run !== true) {
withFilters.splice(i, 1)
}
}
return withFilters
}

const runOneSpec = (spec) =>
cypress.run({
config: {
video: false,
},
spec: spec.filename,
})

globby('./cypress/integration/*-spec.js')
.then(filterCaseToRun)
.then((specs) => {
console.table('测试现在开始,仅允许constFileList中的用例运行', specs)
return Promise.mapSeries(specs, runOneSpec)
})
.then((runsResults) => {
//您可以定制您的测试报告或者对测试结果进行处理,本例仅用来演示 Module API

const summary = runsResults
.map((oneRun) => oneRun.runs[0])
.map((run) => ({
spec: run.spec.name,
tests: run.stats.tests,
passes: run.stats.passes,
failures: run.stats.failures,
}))
console.table('测试结果一览', summary)
})

然后命令行切换到E:\Cypress目录下,执行命令

node testPickRunSimple.js

自动化测试框架[Cypress API]_json

Module API 完整项目实践

从3.0版本开始,Cypress将每个测试文件单独隔离执行了,这导致Cypress的报告也是隔离的,每个测试文件一个,但期望的是依次执行仅生成一份融合的测试报告

创建项目

//在目录文件夹例如E:下命令行执行
mkdir moduleAPIProject

生成package.json文件

//进入项目路径下E:\moduleAPIProject
cd moduleAPIProject
//执行如下命令,过程中根据实际情况填写即可
npm init

本地安装Cypress

//进入项目路径下E:\moduleAPIProject
yarn add cypress --dev

初始化Cypress

yarn cypress open

编写测试用例

在E:\moduleAPIProject\cypress\integration文件夹下,创建如下3个测试用例

//第一个测试文件first-spec.js代码如下
/// <reference types="cypress" />
describe('第一个用例', () => {
it('测试 Module API', () => {
expect(1).to.equal(1)
})

it('[smoke]测试 Module API', () => {
expect(2).to.equal(2)
})
})
//第二个测试文件second-spec.js代码如下
/// <reference types="cypress" />
describe('[smoke]第二个用例', () => {
it('测试 Module API', () => {
expect(1).not.equal(2)
})
})
//第三个测试文件third-spec.js代码如下
/// <reference types="cypress" />
describe('第 3 个用例', () => {
it('[smoke]测试 Module API', () => {
expect('iTesting').to.equal('iTesting')
})
})

编写动态挑选测试用例的运行代码

在E:\moduleAPIProject\cypress文件夹下,简历utils文件夹,在该文件夹下创建PickTestsToRun.js文件

/*本段代码更改it和describe的行为,使它实现类似mocha中的grep功能,接受4个参数
-i<value>,仅运行指定的it(),该it()的描述中含有<value>
-I<value>,仅运行describe(),该describe()的描述中含有<value>
-e<value>,排除运行it(),该it()的描述中含有<value>
-E<value>,排除运行describe(),该describe()的描述中含有<value>
*/
function pickIts() {
if (global.it.itHadSet) return
const include = Cypress.env('i') && Cypress.env('i').split(',')
const exclude = Cypress.env('e') && Cypress.env('e').split(',')
const originIt = it
global.it = function (...rest) {
const itDesc = rest[0]
if (include) {
if (include.findIndex(item => itDesc.indexOf(item) > -1) > -1) {
originIt(...rest)
}
}

if (exclude) {
if (!(exclude.findIndex(item => itDesc.indexOf(item) > -1) > -1)) {
originIt(...rest)
}
}
if (!exclude && !include) {
originIt(...rest)
}
}
global.it.itHadSet = true
}
function pickDescribes() {
if (global.describe.describeHadSet) return
const include = Cypress.env('I') && Cypress.env('I').split(',')
const exclude = Cypress.env('E') && Cypress.env('E').split(',')
const originDescribe = describe
global.describe = function (...rest) {
const describeDesc = rest[0]
if (include) {
if (include.findIndex(item => describeDesc.indexOf(item) > -1) > -1) {
originDescribe(...rest)
}
}
if (exclude) {
if (!(exclude.findIndex(item => describeDesc.indexOf(item) > -1) > -1)) {
originDescribe(...rest)
}
}
if (!exclude && !include) {
originDescribe(...rest)
}
}
global.describe.describeHadSet = true
}
pickIts()
pickDescribes()

动态挑选用例配置及动态更改运行环境配置

在E:\moduleAPIProject\cypress\supoort\index.js文件里引入PickTestsToRun.js及动态配置测试环境

require('../utils/PickTestsToRun')
import './commands'
beforeEach(() => {
const targetEnv = Cypress.env('testEnv') || Cypress.config('targetEnv')
cy.log(`Set target environment to: \n ${JSON.stringify(targetEnv)}`)
cy.log(`Environment details are: \n ${JSON.stringify(Cypress.env(targetEnv))}`)
cy.log('Now the test starting...')
Cypress.config('baseUrl', Cypress.env(targetEnv).baseUrl)
})

配置项目文件cypress.json

{
"targetEnv": "staging",
"baseUrl": "http://www.helloqa.com",
"env": {
"staging": {
"baseUrl":"http://www.staging.helloqa.com",
"username": "stagingUser",
"password": "stagingPwd"
},
"prod": {
"baseUrl":"http://www.helloqa.com",
"username": "User",
"password": "Pwd"
}
}
}

编写Moduld API运行项目及融合测试报告代码

首先使用​​npm install​​命令安装​​colors​​、​​commander​​、​​moment​

在项目根目录下建立moduleRunIndex.js

// / <reference types="cypress" />

const cypress = require('cypress')
const fse = require('fs-extra')
const { merge } = require('mochawesome-merge')
const generator = require('mochawesome-report-generator')
var colors = require('colors');
const program = require('commander');
const moment = require('moment')

program
.requiredOption('-t, --targetEnvironment <string>', 'Specify the running Env', 'staging')
.requiredOption('-s, --specFile <string>', 'Spec the running file path', 'cypress/integration/*')
.option('-i, --onlyRunTest <string>', 'Only run the test cases in it(). for example -i smoke, run cases that contains smoke in description', '[smoke]')
.option('-e, --excludeTest <string>', 'Exclude to run the test cases in it(), for example -e smoke, exclude to run cases that contains smoke in description')
.option('-I, --onlyRunSuites <string>', 'Only run the test suits in describe(), for example -I smoke, run test suites that contains smoke in description')
.option('-E, --excludeSuites <string>', 'only run the test suits in describe(), for example -E smoke, exclude to run run test suits that contains smoke in description')
.allowUnknownOption()
.parse(process.argv)

var envParams;
var args = program.opts();
envParams = `testEnv=${args.targetEnvironment}`

if (args.onlyRunTest) envParams = envParams.concat(`,i=${args.onlyRunTest}`);
if(args.excludeTest) envParams = envParams.concat(`,e=${args.excludeTest}`);
if(args.onlyRunSuites) envParams = envParams.concat(`,I=${args.onlyRunSuites}`);
if(args.excludeSuites) envParams = envParams.concat(`,E=${args.excludeSuites}`);

function getTimeStamp () {
let now = new moment().format('YYYY-MM-DD--HH_mm_ss')
return now
}

const currRunTimestamp = getTimeStamp()

const sourceReport = {
reportDir: `${'reports/' + 'Test Run - '}${currRunTimestamp}/mochawesome-report`,
}


const finalReport = {
reportDir: `${'reports/' + 'Test Run - '}${currRunTimestamp}`,
saveJson: true,
reportFilename: 'Run-Report',
reportTitle: 'Run-Report',
reportPageTitle: 'Run-Report',
}

async function mergeReport() {
console.log(`The target Environment are set to: ${program.targetEnvironment}`.bold.yellow)
console.log(`The target TestPath are set to: ${program.specFile}`.bold.yellow)
console.log(`The running Env are : ${envParams}`.bold.yellow)

fse.ensureDirSync(sourceReport.reportDir)

const { totalFailed } = await cypress.run({
spec: `${args.specFile}`,
//Cypress run with provided parameters.
env: envParams,
browser: 'chrome',
config: {
pageLoadTimeout: 10000,
screenshotsFolder: `${sourceReport.reportDir}/screenshots`,
video: false,
videosFolder: `${sourceReport.reportDir}/videos`,
},
reporter: 'mochawesome',
reporterOptions: {
reportDir: sourceReport.reportDir,
overwrite: false,
html: true,
json: true,
},
})
const jsonReport = await merge(sourceReport)
await generator.create(jsonReport, finalReport)
process.exit(totalFailed)
}

mergeReport()

配置package.json文件

在E:\moduleAPIProject\package.json的scripts代码块中做如下更改

{
"name": "modualapiproject",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"ModuleRun": "node moduleRunIndex.js"
},
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"commander": "^4.0.1",
"console.table": "^0.10.0",
"cypress": "^3.7.0",
"globby": "^10.0.1",
"mocha": "^5.2.0",
"mochawesome": "^4.1.0",
"mochawesome-merge": "^2.1.0",
"mochawesome-report-generator": "^4.0.1"
}
}

安装测试报告融合依赖

npm install mochawesome -D
//切换到项目根目录下进行(E:\moduleAPIProject)
//安装mocha
npm install mocha@5.2.0 --save-dev
//安装mochawesome-merge
npm install mochawesome-merge --save-dev
//安装commander
npm install commander --save-dev
//安装mochawesome-report-generator
npm install mochawesome-report-generator --save-dev

指定参数运行测试并查看结果

//指定环境为prod,运行所有包含[smoke]字样的it(),还可以根据实际需要更改测试环境及测试配置
//在项目根目录E:\moduleAPIProject下执行命令
yarn ModuleRun -t prod -i '[smoke]'

自动化测试框架[Cypress API]_json_02


测试运行不仅为每条测试用例单独生成了测试报告machawesome_001.html等,还生成了融合的测试报告Run-Report.html