testrail-jest-reporter
Advanced tools
Comparing version 1.0.6 to 1.0.7
{ | ||
"name": "testrail-jest-reporter", | ||
"version": "1.0.6", | ||
"version": "1.0.7", | ||
"description": "Custom Jest reporter for Testrail synchronization", | ||
@@ -55,4 +55,6 @@ "main": "index.js", | ||
"dependencies": { | ||
"@prantlf/jsonlint": "^10.2.0", | ||
"chalk": "^4.1.0", | ||
"fs-extra": "^9.0.1", | ||
"lodash": "^4.17.20", | ||
"process": "^0.11.10", | ||
@@ -59,0 +61,0 @@ "request": "^2.88.2", |
@@ -138,2 +138,4 @@ [![TestRail v6.7](https://img.shields.io/badge/TestRail%20API-v2-green.svg)](http://docs.gurock.com/testrail-api2/start) [![NPM](https://img.shields.io/npm/l/testrail-jest-reporter)](https://github.com/AntonChaukin/testrail-jest-reporter/blob/main/LICENSE) [![NPM](https://img.shields.io/node/v/testrail-jest-reporter)](https://github.com/AntonChaukin/testrail-jest-reporter/blob/main/package.json) | ||
- ~~Added ability to specify several case_ids in one test description~~ >> **Done in 1.0.6** | ||
- ~~Added JSON validator to API interface~~ >> **Done in 1.0.7** | ||
- Migrate to GOT | ||
@@ -140,0 +142,0 @@ <br>**Version 2:** |
'use strict'; | ||
const chalk = require('chalk'), tr_api = require('./interface'), Utils = require('./utils'), | ||
ReporterError = require('./error'); | ||
const chalk = require('chalk'), tr_api = require('./interface'), ReporterError = require('./error'); | ||
const error = chalk.bold.red; | ||
const util = new Utils(); | ||
@@ -18,22 +16,8 @@ module.exports = { | ||
tr_api.defaults.headers['Authorization'] = _options.auth; | ||
tr_api.defaults.uri = this._baseUrl + '/index.php?/api/v2/'; | ||
tr_api.defaults.baseUrl = this._baseUrl + '/index.php?/api/v2/'; | ||
} | ||
function add_results(testsResults) { | ||
if (!util.isArray(testsResults)) { | ||
throw new ReporterError(`Something was wrong with tests results! | ||
\n\nContexts: ${JSON.stringify(testsResults)}`); | ||
} | ||
return Promise.all( | ||
testsResults.map(run => { | ||
if (!util.isArray(run.results)) { | ||
throw new ReporterError(`The Run results is not an array! | ||
\n\n Context: ${JSON.stringify(run.results)}`); | ||
} | ||
for(let i=0, len=run.results.length; i<len; i++) { | ||
if (!util.isPlainObject(run.results[i])) { | ||
throw new ReporterError(`Something was wrong with the Run results! | ||
\n\n Context: ${JSON.stringify(run.results)}`); | ||
} | ||
} | ||
return tr_api.add_results_for_cases(run.id, {"results": run.results}); | ||
@@ -45,15 +29,5 @@ }) | ||
response.map(run => { | ||
if (run) { | ||
switch (run.statusCode) { | ||
case 200: | ||
if (util.isArray(run.body)) run.body.map((result) => { | ||
if (result && result.id) count++; | ||
}); | ||
break; | ||
case 500: | ||
throw new ReporterError(run.error); | ||
default: | ||
throw new ReporterError(`TestRail API add_results_for_cases resolved ${JSON.stringify(run)}`); | ||
} | ||
} else throw new ReporterError(`TestRail API add_results_for_cases resolved ${JSON.stringify(run)}`); | ||
run.map((result) => { | ||
if (result && result.id) count++; | ||
}); | ||
}); | ||
@@ -74,6 +48,3 @@ return count; | ||
.then(res => { | ||
let _milestone = null; | ||
if (res && util.isArray(res)) { | ||
_milestone = res.filter((milestone) => milestone.name === this._milestone_name); | ||
} else throw new ReporterError(`TestRail API get_milestones resolved ${JSON.stringify(res)}`); | ||
const _milestone = res.filter((milestone) => milestone.name === this._milestone_name); | ||
@@ -87,6 +58,5 @@ if (_milestone && !!_milestone.length) { | ||
.then(res => { | ||
if (res && util.isArray(res)) { | ||
if (res) { | ||
return Promise.all(res.map(plan => tr_api.get_plan(plan.id))); | ||
} | ||
else if (this._milestone_id) throw new ReporterError(`TestRail API get_plans resolved ${JSON.stringify(res)}`); | ||
return false; | ||
@@ -99,5 +69,5 @@ }) | ||
.then(res => { | ||
for(let i=0, res_len=res.length; i<res_len; i++) { | ||
const plan = res[i]; | ||
if (plan && plan.entries) { | ||
if (res) { | ||
for(let i=0, res_len=res.length; i<res_len; i++) { | ||
const plan = res[i]; | ||
for (let j=0, len = plan.entries.length; j<len; j++) { | ||
@@ -107,3 +77,2 @@ plan.entries[j].runs.map(run => this._runs_ids.push(run.id)); | ||
} | ||
else console.log(error(`TestRail API get_plan resolved ${JSON.stringify(res[i])}`)); | ||
} | ||
@@ -120,3 +89,3 @@ if (this._milestone_id) { | ||
.then(res => { | ||
if (res && util.isArray(res)) { | ||
if (res) { | ||
for (let i=0, len = res.length; i<len; i++) { | ||
@@ -132,5 +101,5 @@ if (res[i] && res[i].id) this._runs_ids.push(res[i].id); | ||
.then(res => { | ||
for(let i=0, len=res.length; i<len; i++) { | ||
const tests = res[i]; | ||
if (tests && util.isArray(tests)) { | ||
if (res) { | ||
for(let i=0, len=res.length; i<len; i++) { | ||
const tests = res[i]; | ||
for(let j=0, t_len=tests.length; j<t_len; j++) { | ||
@@ -140,3 +109,3 @@ if (tests[j] && tests[j].case_id) this._tests | ||
} | ||
} else console.log(error(`TestRail API get_tests resolved ${JSON.stringify(res[i])}`)); | ||
} | ||
} | ||
@@ -143,0 +112,0 @@ if (!!this._tests.length) { |
'use strict'; | ||
const rp = require('request-promise'), chalk = require('chalk'), Utils = require('./utils'); | ||
const rp = require('request-promise'), chalk = require('chalk'), Utils = require('./utils'), | ||
ReporterError = require('./error'), {compile} = require('@prantlf/jsonlint/lib/validator'), | ||
{body: schema_body, data: schema_data} = require('./schemas'); | ||
const error = chalk.bold.red; | ||
@@ -10,7 +12,7 @@ const utils = new Utils(); | ||
headers: { | ||
'Authorization': null, | ||
'Content-Type': 'application/json' | ||
}, | ||
json: true, | ||
jar: true | ||
jar: true, | ||
resolveWithFullResponse: true | ||
} | ||
@@ -25,21 +27,52 @@ | ||
* | ||
* @param {Object} config The config specific for this request (merged with this.defaults) | ||
* @param {string} uri | ||
* @param {array} args The config specific for this request (merged with this.defaults) | ||
*/ | ||
Testrail_api.prototype.request = function request(config) { | ||
if (typeof config === 'string') { | ||
config = arguments[1] || {}; | ||
config.uri = arguments[0]; | ||
Testrail_api.prototype.request = function request(uri, ...args) { | ||
const _base = rp.defaults(this.defaults); | ||
let caller; | ||
let _path = uri; | ||
const data = utils.isPlainObject(args[args.length - 1]) ? args[args.length - 1] : null; | ||
if (data) args.pop(); | ||
if(utils.isPlainObject(args[0]) && args[0].method === 'POST') { | ||
args.shift(); | ||
const validate_data = compile(JSON.stringify(schema_data[uri])); | ||
try { | ||
validate_data(JSON.stringify(data)); | ||
} | ||
catch (err) { | ||
throw new ReporterError(`\nInvalid request data for method ${uri} | ||
Context: ${JSON.stringify(data)}\n${err.message}`); | ||
} | ||
caller = _base.defaults({ | ||
method: 'POST', | ||
body: data, | ||
followAllRedirects: true | ||
}); | ||
} else { | ||
config = config || {}; | ||
caller =_base.defaults({qs: data}); | ||
} | ||
config = mergeConfig(this.defaults, config); | ||
for(let i=0, len = args.length; i<len; i++) {_path += `/${args[i]}`} | ||
if (config.method) { | ||
config.method = config.method.toUpperCase(); | ||
} else if (this.defaults.method) { | ||
config.method = this.defaults.method.toUpperCase(); | ||
} | ||
return rp(config); | ||
return caller(_path) | ||
.then(resp => { | ||
switch (resp.statusCode) { | ||
case 200: | ||
break; | ||
default: | ||
throw new ReporterError(`\nUnexpected response status code ${resp.statusCode} | ||
\n${JSON.stringify(resp, null, 2)}`) | ||
} | ||
const validate_body = compile(JSON.stringify(schema_body[uri])); | ||
try { | ||
validate_body(JSON.stringify(resp.body)); | ||
} | ||
catch (err) { | ||
throw new ReporterError(`\nTestRail API response parsing error:\n${err.message}`); | ||
} | ||
return resp.body; | ||
}) | ||
.catch(error => {throw new ReporterError(`\n${error.message}`)}); | ||
}; | ||
@@ -50,14 +83,3 @@ | ||
Testrail_api.prototype[method] = function(...args) { | ||
const data = typeof args[args.length - 1] === 'object' ? args[args.length - 1] : null; | ||
if (data) args.pop(); | ||
let uri = method; | ||
for(let i=0, len = args.length; i<len; i++) {uri += `/${args[i]}`} | ||
return this.request({ | ||
method: 'POST', | ||
uri: uri, | ||
body: data, | ||
followAllRedirects: true, | ||
resolveWithFullResponse: true | ||
}).catch((err) => console.log(error(err))); | ||
return this.request(method, {method: 'POST'}, ...args) | ||
}; | ||
@@ -69,11 +91,3 @@ }); | ||
Testrail_api.prototype[method] = function(...args) { | ||
const data = typeof args[args.length - 1] === 'object' ? args[args.length - 1] : null; | ||
if (data) args.pop(); | ||
let uri = method; | ||
for(let i=0, len = args.length; i<len; i++) {uri += `/${args[i]}`} | ||
return this.request({ | ||
uri: uri, | ||
qs: data | ||
}).catch((err) => {throw new Error(err)}); | ||
return this.request(method, ...args) | ||
}; | ||
@@ -126,37 +140,1 @@ }); | ||
} | ||
function mergeConfig(config1, config2) { | ||
config2 = config2 || {}; | ||
let config = {}; | ||
let otherKeys = Object | ||
.keys(config1) | ||
.concat(Object.keys(config2)) | ||
.filter(function filterKeys(key) { | ||
return key !== 'headers' || key !== 'uri'; | ||
}); | ||
mergeProperties('headers'); | ||
utils.forEach(otherKeys, mergeProperties); | ||
config['uri'] = config1['uri'] + config2['uri']; | ||
return config; | ||
function getMergedValue(target, source) { | ||
if (utils.isPlainObject(target) && utils.isPlainObject(source)) { | ||
return utils.merge(target, source); | ||
} else if (utils.isPlainObject(source)) { | ||
return utils.merge({}, source); | ||
} else if (utils.isArray(source)) { | ||
return source.slice(); | ||
} | ||
return source; | ||
} | ||
function mergeProperties(prop) { | ||
if (typeof config2[prop] !== 'undefined') { | ||
config[prop] = getMergedValue(config1[prop], config2[prop]); | ||
} else if (typeof config1[prop] !== 'undefined') { | ||
config[prop] = getMergedValue(undefined, config1[prop]); | ||
} | ||
} | ||
} |
@@ -483,161 +483,2 @@ const Utils = require('../src/utils'), ReporterError = require('../src/error'); | ||
it('get_tests if get_plans return undefined', async () => { | ||
const caller = require('../src/caller'); | ||
const api = require('../src/interface'); | ||
caller.init({milestone: milestone_name, project_id: 1}); | ||
jest.spyOn(api, 'get_milestones').mockResolvedValueOnce(get_milestones_resp); | ||
jest.spyOn(api, 'get_plans').mockResolvedValueOnce(undefined); | ||
const get_plan_spy = jest.spyOn(api, 'get_plan').mockResolvedValueOnce(get_plan_resp); | ||
jest.spyOn(api, 'get_runs').mockResolvedValueOnce(get_runs_resp); | ||
const get_tests_spy = jest.spyOn(api, 'get_tests') | ||
.mockResolvedValueOnce([test_1]) | ||
.mockResolvedValueOnce([test_2]) | ||
.mockResolvedValue([]); | ||
await caller.get_tests(); | ||
get_plan_spy.mockRestore(); | ||
get_tests_spy.mockRestore(); | ||
expect(caller._tests).toEqual([case_1]); | ||
expect(caller._runs_ids).toHaveLength(1); | ||
expect(caller._milestone_id).toEqual(milestone_id); | ||
}); | ||
it('get_tests if get_plans return empty', async () => { | ||
const caller = require('../src/caller'); | ||
const api = require('../src/interface'); | ||
caller.init({milestone: milestone_name, project_id: 1}); | ||
jest.spyOn(api, 'get_milestones').mockResolvedValueOnce(get_milestones_resp); | ||
jest.spyOn(api, 'get_plans').mockResolvedValueOnce([{}]); | ||
jest.spyOn(api, 'get_plan').mockResolvedValueOnce({}); | ||
jest.spyOn(api, 'get_runs').mockResolvedValueOnce(get_runs_resp); | ||
const get_tests_spy = jest.spyOn(api, 'get_tests') | ||
.mockResolvedValueOnce([test_1]) | ||
.mockResolvedValueOnce([test_2]) | ||
.mockResolvedValue([]); | ||
await caller.get_tests(); | ||
get_tests_spy.mockRestore(); | ||
expect(caller._tests).toEqual([case_1]); | ||
expect(caller._runs_ids).toHaveLength(1); | ||
expect(caller._milestone_id).toEqual(milestone_id); | ||
}); | ||
it('get_tests if get_plan return undefined', async () => { | ||
const caller = require('../src/caller'); | ||
const api = require('../src/interface'); | ||
caller.init({milestone: milestone_name, project_id: 1}); | ||
jest.spyOn(api, 'get_milestones').mockResolvedValueOnce(get_milestones_resp); | ||
jest.spyOn(api, 'get_plans').mockResolvedValueOnce(get_plans_resp); | ||
jest.spyOn(api, 'get_plan').mockResolvedValueOnce(undefined); | ||
const get_runs_spy = jest.spyOn(api, 'get_runs').mockResolvedValueOnce(get_runs_resp); | ||
const get_tests_spy = jest.spyOn(api, 'get_tests') | ||
.mockResolvedValueOnce([test_1]) | ||
.mockResolvedValueOnce([test_2]) | ||
.mockResolvedValue([]); | ||
await caller.get_tests(); | ||
get_runs_spy.mockRestore(); | ||
get_tests_spy.mockRestore(); | ||
expect(caller._tests).toEqual([case_1]); | ||
expect(caller._runs_ids).toHaveLength(1); | ||
expect(caller._milestone_id).toEqual(milestone_id); | ||
}); | ||
it('get_tests if get_runs return undefined', async () => { | ||
const caller = require('../src/caller'); | ||
const api = require('../src/interface'); | ||
caller.init({milestone: milestone_name, project_id: 1}); | ||
jest.spyOn(api, 'get_milestones').mockResolvedValueOnce(get_milestones_resp); | ||
jest.spyOn(api, 'get_plans').mockResolvedValueOnce(get_plans_resp); | ||
jest.spyOn(api, 'get_plan').mockResolvedValueOnce(get_plan_resp); | ||
const get_runs_spy = jest.spyOn(api, 'get_runs').mockResolvedValueOnce(undefined); | ||
const get_tests_spy = jest.spyOn(api, 'get_tests') | ||
.mockResolvedValueOnce([test_2]) | ||
.mockResolvedValue([]); | ||
await caller.get_tests(); | ||
get_runs_spy.mockRestore(); | ||
get_tests_spy.mockRestore(); | ||
expect(caller._tests).toEqual([case_2]); | ||
expect(caller._runs_ids).toHaveLength(runs_len); | ||
expect(caller._milestone_id).toEqual(milestone_id); | ||
}); | ||
it('get_tests if get_runs return empty', async () => { | ||
const caller = require('../src/caller'); | ||
const api = require('../src/interface'); | ||
caller.init({milestone: milestone_name, project_id: 1}); | ||
jest.spyOn(api, 'get_milestones').mockResolvedValueOnce(get_milestones_resp); | ||
jest.spyOn(api, 'get_plans').mockResolvedValueOnce(get_plans_resp); | ||
jest.spyOn(api, 'get_plan').mockResolvedValueOnce(get_plan_resp); | ||
const get_runs_spy = jest.spyOn(api, 'get_runs').mockResolvedValueOnce([{}]); | ||
const get_tests_spy = jest.spyOn(api, 'get_tests') | ||
.mockResolvedValueOnce([test_2]) | ||
.mockResolvedValue([]); | ||
await caller.get_tests(); | ||
get_runs_spy.mockRestore(); | ||
get_tests_spy.mockRestore(); | ||
expect(caller._tests).toEqual([case_2]); | ||
expect(caller._runs_ids).toHaveLength(runs_len); | ||
expect(caller._milestone_id).toEqual(milestone_id); | ||
}); | ||
it('get_tests if get_tests return empty', async () => { | ||
const caller = require('../src/caller'); | ||
const api = require('../src/interface'); | ||
caller.init({milestone: milestone_name, project_id: 1}); | ||
jest.spyOn(api, 'get_milestones').mockResolvedValueOnce(get_milestones_resp); | ||
jest.spyOn(api, 'get_plans').mockResolvedValueOnce(get_plans_resp); | ||
jest.spyOn(api, 'get_plan').mockResolvedValueOnce(get_plan_resp); | ||
jest.spyOn(api, 'get_runs').mockResolvedValueOnce(get_runs_resp); | ||
const get_tests_spy = jest.spyOn(api, 'get_tests') | ||
.mockResolvedValue([]); | ||
await caller.get_tests(); | ||
get_tests_spy.mockRestore(); | ||
expect(caller._tests).toEqual([]); | ||
expect(caller._runs_ids).toHaveLength(runs_len+1); | ||
expect(caller._milestone_id).toEqual(milestone_id); | ||
}); | ||
it('get_tests if get_tests return undefined', async () => { | ||
const caller = require('../src/caller'); | ||
const api = require('../src/interface'); | ||
caller.init({milestone: milestone_name, project_id: 1}); | ||
jest.spyOn(api, 'get_milestones').mockResolvedValueOnce(get_milestones_resp); | ||
jest.spyOn(api, 'get_plans').mockResolvedValueOnce(get_plans_resp); | ||
jest.spyOn(api, 'get_plan').mockResolvedValueOnce(get_plan_resp); | ||
jest.spyOn(api, 'get_runs').mockResolvedValueOnce(get_runs_resp); | ||
const get_tests_spy = jest.spyOn(api, 'get_tests') | ||
.mockResolvedValue(undefined); | ||
await caller.get_tests(); | ||
get_tests_spy.mockRestore(); | ||
expect(caller._tests).toEqual([]); | ||
expect(caller._runs_ids).toHaveLength(runs_len+1); | ||
expect(caller._milestone_id).toEqual(milestone_id); | ||
}); | ||
it('add_results successful', async() => { | ||
@@ -652,3 +493,3 @@ const api = require('../src/interface'); | ||
const add_results_for_cases_spy = jest.spyOn(api, 'add_results_for_cases') | ||
.mockResolvedValueOnce(resp); | ||
.mockResolvedValueOnce(resp.body); | ||
@@ -669,3 +510,3 @@ const res = await caller.add_results([{id: 1, results: [testcase]}]); | ||
try { | ||
resp =await caller.add_results([{id: 1, results: [testcase]}]); | ||
resp = await caller.add_results([{id: 1, results: [testcase]}]); | ||
} | ||
@@ -686,3 +527,3 @@ catch (err) { | ||
try { | ||
resp =await caller.add_results([{id: 1, results: testcase}]); | ||
resp = await caller.add_results([{id: 1, results: testcase}]); | ||
} | ||
@@ -703,3 +544,3 @@ catch (err) { | ||
try { | ||
resp =await caller.add_results([{id: 1, results: [testcase, 'test']}]); | ||
resp = await caller.add_results([{id: 1, results: [testcase, 'test']}]); | ||
} | ||
@@ -712,23 +553,2 @@ catch (err) { | ||
it('add_results add_results_for_cases return error', async() => { | ||
const api = require('../src/interface'); | ||
const caller = require('../src/caller'); | ||
const console_spy = jest.spyOn(global.console, 'log'); | ||
let utils = new Utils(); | ||
const testResult = passed(); | ||
const [testcase] = utils.formatCase(testResult); | ||
const err = new Error('Request rejected'); | ||
const resp = {statusCode: 500, error: err}; | ||
const add_results_for_cases_spy = jest.spyOn(api, 'add_results_for_cases') | ||
.mockResolvedValueOnce(resp); | ||
const res = await caller.add_results([{id: 1, results: [testcase]}]); | ||
add_results_for_cases_spy.mockRestore(); | ||
expect(res).toBeFalsy(); | ||
expect(console_spy).toHaveBeenCalledWith(error("Testrail Jest Reporter Error: "+err)); | ||
console_spy.mockRestore(); | ||
}); | ||
it('add_results add_results_for_cases rejected', async() => { | ||
@@ -754,40 +574,4 @@ const api = require('../src/interface'); | ||
it('add_results add_results_for_cases return empty', async() => { | ||
const api = require('../src/interface'); | ||
const caller = require('../src/caller'); | ||
let utils = new Utils(); | ||
const testResult = passed(); | ||
const [testcase] = utils.formatCase(testResult); | ||
const add_results_for_cases_spy = jest.spyOn(api, 'add_results_for_cases') | ||
.mockResolvedValue({statusCode: 200, body: [{}]}); | ||
const res = await caller.add_results([{id: 1, results: [testcase]}]); | ||
add_results_for_cases_spy.mockRestore(); | ||
expect(res).toBeFalsy(); | ||
}); | ||
it('add_results add_results_for_cases return undefined', async() => { | ||
const api = require('../src/interface'); | ||
const caller = require('../src/caller'); | ||
const console_spy = jest.spyOn(global.console, 'log'); | ||
let utils = new Utils(); | ||
const err = new ReporterError("TestRail API add_results_for_cases resolved undefined"); | ||
const testResult = passed(); | ||
const [testcase] = utils.formatCase(testResult); | ||
const add_results_for_cases_spy = jest.spyOn(api, 'add_results_for_cases') | ||
.mockResolvedValue(undefined); | ||
const res = await caller.add_results([{id: 1, results: [testcase]}]); | ||
add_results_for_cases_spy.mockRestore(); | ||
expect(res).toBeFalsy(); | ||
expect(console_spy).toHaveBeenCalledWith(error(err)); | ||
console_spy.mockRestore() | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
117897
17
2240
152
8
+ Added@prantlf/jsonlint@^10.2.0
+ Addedlodash@^4.17.20
+ Added@prantlf/jsonlint@10.2.0(transitive)
+ Addedajv@6.10.2(transitive)
+ Addedcommander@4.0.1(transitive)
+ Addedfast-deep-equal@2.0.1(transitive)