├── .npmrc
├── testMochaVersions.sh
├── testMochaVersions.ps1
├── .travis.yml
├── .gitignore
├── .npmignore
├── test
├── browser
│ ├── sumTest.js
│ └── mocha.html
├── example
│ ├── rootHooks.js
│ ├── exampleSimple.js
│ ├── failingHook.js
│ ├── failingIgnoreHook.js
│ └── failingIgnoreHookNoRoot.js
├── test_data
│ └── simple.js
├── functional
│ ├── thisSkipExample.js
│ ├── topLevelSuiteOutput.js
│ ├── testOutput.js
│ ├── useStdError.js
│ ├── recordHookFailuresDisabled.js
│ ├── actualVsExpected.js
│ ├── testMultipleOptions.js
│ ├── recordHookFailuresEnabled.js
│ ├── displayIgnoredAsIgnored.js
│ ├── ignoreHookWithNameEnabled.js
│ └── ignoreHookWithNameDisabled.js
├── testHelpers.js
├── programmatic
│ └── testOutput.js
└── excluded tests
│ ├── ignoreHookWithNameEnabledRoot.js
│ └── ignoreHookWithNameDisabledRoot.js
├── appveyor.yml
├── .github
├── ISSUE_TEMPLATE.md
└── PULL_REQUEST_TEMPLATE.md
├── LICENSE
├── package.json
├── .eslintrc.json
├── lib
├── teamcityBrowser.js
└── teamcity.js
├── CHANGELOG.md
└── README.md
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
--------------------------------------------------------------------------------
/testMochaVersions.sh:
--------------------------------------------------------------------------------
1 | npm install mocha@6
2 | npm run test
3 | npm install mocha@7
4 | npm run test
5 | npm install mocha@8
6 | npm run test
--------------------------------------------------------------------------------
/testMochaVersions.ps1:
--------------------------------------------------------------------------------
1 | npm install mocha@6
2 | npm run test
3 | npm install mocha@7
4 | npm run test
5 | npm install mocha@8
6 | npm run test
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | script:
4 | - npm run lint
5 | - npm install mocha
6 | - npm test
7 |
8 | node_js:
9 | - "10"
10 | - "lts/*"
11 |
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | *.seed
3 | *.log
4 | *.csv
5 | *.dat
6 | *.out
7 | *.pid
8 | *.gz
9 |
10 | pids
11 | logs
12 | results
13 |
14 | npm-debug.log
15 | node_modules
16 | \.idea/
17 | package-lock.json
18 |
19 | test/browser/teamcityBrowser.js
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | #tests
2 | test
3 | coverage
4 |
5 | #build tools
6 | .travis.yml
7 | .jenkins.yml
8 | .codeclimate.yml
9 | appveyor.yml
10 |
11 | #linters
12 | .jscsrc
13 | .jshintrc
14 | .eslintrc*
15 |
16 | #editor settings
17 | .idea
18 | .editorconfig
19 |
20 | #github settings
21 | .github
22 |
23 | #custom scripts
24 | testMochaVersions.ps1
25 | testMochaVersions.sh
--------------------------------------------------------------------------------
/test/browser/sumTest.js:
--------------------------------------------------------------------------------
1 | /*global chai*/
2 | /*eslint-env browser*/
3 | /*eslint strict: ["error", "never"]*/
4 |
5 |
6 | describe('sum', function () {
7 | it('should return sum of arguments fail', function () {
8 | chai.expect(1).to.equal(3);
9 | });
10 |
11 | it('should return sum of arguments pass', function () {
12 | chai.expect(1).to.equal(1);
13 | });
14 |
15 | });
--------------------------------------------------------------------------------
/test/example/rootHooks.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by dj-glock on 04/06/2021.
3 | */
4 | 'use strict';
5 | const assert = require('assert');
6 |
7 | exports.mochaHooks = () => {
8 | return {
9 | beforeEach: [
10 | function beforeEachRootHookNoReporting() {
11 | assert.strictEqual(1, 1);
12 | }
13 | ],
14 | afterEach: [
15 | function afterEachRoot() {
16 | assert.strictEqual(1, 1);
17 | },
18 | ]
19 | };
20 | };
--------------------------------------------------------------------------------
/test/test_data/simple.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jamie on 12/08/2017.
3 | */
4 | 'use strict';
5 | const assert = require('assert');
6 | describe('Top Describe', function () {
7 | it('Passing Test @pass', function () {
8 | assert.equal(1, 1);
9 | });
10 | it('Failing Test @fail', function () {
11 | assert.equal(2, 1);
12 | });
13 | it.skip('Skipped Test @skip', function () {
14 | assert.equal(2, 1);
15 | });
16 | });
--------------------------------------------------------------------------------
/test/example/exampleSimple.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jamie on 12/08/2017.
3 | */
4 | 'use strict';
5 | const assert = require('assert');
6 | describe('Example Test Top Describe', function () {
7 | it('Example Test Passing Test @pass', function () {
8 | assert.equal(1, 1);
9 | });
10 | it('Example Test Failing Test @fail', function () {
11 | assert.equal(2, 1);
12 | });
13 | it.skip('Example Test Skipped Test @skip', function () {
14 | assert.equal(2, 1);
15 | });
16 | });
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # Test against the latest version of this Node.js version
2 | environment:
3 | matrix:
4 | # node.js
5 | - nodejs_version: "6"
6 | - nodejs_version: "8"
7 | # Install scripts. (runs after repo cloning)
8 | install:
9 | # Get the latest stable version of Node.js or io.js
10 | - ps: Install-Product node $env:nodejs_version
11 | # install modules
12 | - npm install
13 |
14 | # Post-install test scripts.
15 | test_script:
16 | # Output useful info for debugging.
17 | - node --version
18 | - npm --version
19 | # run tests
20 | - npm test
21 |
22 | # Don't actually build.
23 | build: off
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## The problem
2 |
3 | Briefly describe the issue you are experiencing (or the feature you want to add)
4 |
5 | ## Environment
6 |
7 | * What mocha-teamcity-reporter version are you using
8 | * Version of NPM/yarn etc and Node.js
9 | * Version of teamcity (If Applicable)
10 |
11 | ## Details
12 |
13 | * If necessary, describe the problem you have been experiencing in more detail.
14 | * Such as a stacktrace or error message
15 |
16 | ## An example test or code sample
17 |
18 | * Please remember that with sample code it's easier to reproduce the bug and it's much faster to fix it.
19 | * Not needed for feature requests or questions
20 |
--------------------------------------------------------------------------------
/test/browser/mocha.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Mocha Tests
5 |
6 |
7 |
8 | Test results in console
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
27 |
28 |
--------------------------------------------------------------------------------
/test/functional/thisSkipExample.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('something', function () {
4 | let stubA;
5 |
6 | function stubThingA(){
7 | console.log('stubbingThing A');
8 | }
9 | function stubThingB(){
10 | console.log('stubbingThing B');
11 | }
12 |
13 | function reasons(){
14 | return false;
15 | }
16 |
17 | before(function () {
18 | stubA = stubThingA();
19 | if (reasons()) {
20 | this.skip();
21 | }
22 | });
23 |
24 | describe('something else', function () {
25 | let stubB;
26 |
27 | before(function () {
28 | stubB = stubThingB();
29 | });
30 |
31 | after(function () {
32 | // this nested `after` does *all* of the teardown.
33 | stubA.restore();
34 | stubB.restore();
35 | });
36 | });
37 |
38 | // what the author should do instead is create an `after`
39 | // hook here, which calls `stubA.restore()`.
40 | });
--------------------------------------------------------------------------------
/test/example/failingHook.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jamie on 12/08/2017.
3 | */
4 | 'use strict';
5 | const assert = require('assert');
6 | describe('Hook Test Top Describe Fail', function () {
7 |
8 | before(function () {
9 | throw new Error('Before hook error fail');
10 | });
11 |
12 | it('Test Passing Test @pass', function () {
13 | assert.equal(1, 1);
14 | });
15 | it('Test Failing Test @fail', function () {
16 | assert.equal(2, 1);
17 | });
18 | it.skip(' Test Skipped Test @skip', function () {
19 | assert.equal(2, 1);
20 | });
21 | });
22 | describe('Hook Test Top Describe Pass', function () {
23 |
24 | before(function () {
25 | assert.equal(1, 1);
26 | });
27 |
28 | it('Test Failing Test @fail', function () {
29 | assert.equal(2, 1);
30 | });
31 |
32 | it('Test Passing Test @pass', function () {
33 | assert.equal(1, 1);
34 | });
35 | });
--------------------------------------------------------------------------------
/test/testHelpers.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const os = require('os');
4 | const path = require('path');
5 |
6 | function logMochaOutput(stdout, stderr) {
7 | console.log('Observed Reporter Output');
8 | console.log('|#####################|');
9 | console.log(stdout);
10 | console.log('|#####################|');
11 |
12 | if (stderr) {
13 | console.log('|#####################|');
14 | console.log('stderr:');
15 | console.log('|#####################|');
16 | console.log(stderr);
17 | console.log('|#####################|');
18 | }
19 | }
20 |
21 |
22 | function getMochaPath() {
23 | if (os.platform() === 'win32') {
24 | return path.resolve('node_modules', '.bin', 'mocha.cmd');
25 | } else {
26 | return path.resolve('node_modules', '.bin', 'mocha');
27 | }
28 | }
29 |
30 | function getTestDataPath(){
31 | return path.join('test', 'test_data');
32 | }
33 |
34 | module.exports = {
35 | logMochaOutput,
36 | getMochaPath,
37 | getTestDataPath
38 | };
39 |
--------------------------------------------------------------------------------
/test/programmatic/testOutput.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Mocha = require('mocha');
4 | const fs = require('fs');
5 | const path = require('path');
6 | const {getTestDataPath } = require('../testHelpers');
7 | const testDataDir = getTestDataPath();
8 |
9 | const {
10 | EVENT_RUN_END
11 | } = Mocha.Runner.constants;
12 |
13 | //Assumes running from root project dir
14 | describe('Can use reporter programmatically', function () {
15 | let mocha;
16 |
17 | before(function () {
18 | // Instantiate a Mocha instance.
19 | mocha = new Mocha({
20 | reporter: path.join('lib', 'teamcity')
21 | });
22 | fs.readdirSync(testDataDir).filter(function (file){
23 | // Only keep the .js files
24 | return file.substr(-3) === '.js';
25 | }).forEach(function (file){
26 | mocha.addFile(
27 | path.join(testDataDir, file)
28 | );
29 | });
30 | });
31 | it('programmatic reporter can get to exit', function (done) {
32 | // Run the tests.
33 | const mochaRunner = mocha.run();
34 | mochaRunner.on(EVENT_RUN_END, function () {
35 | done();
36 | });
37 | });
38 | });
--------------------------------------------------------------------------------
/test/example/failingIgnoreHook.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by dj-glock on 04/06/2021.
3 | */
4 | 'use strict';
5 | const assert = require('assert');
6 |
7 | describe('Hook Test Top Describe Fail', function () {
8 | before(function () {
9 | throw new Error('Before hook error fail');
10 | });
11 |
12 | it('Test Passing Test @pass', function () {
13 | assert.strictEqual(1, 1);
14 | });
15 | it('Test Failing Test @fail', function () {
16 | assert.strictEqual(2, 1);
17 | });
18 | it.skip(' Test Skipped Test @skip', function () {
19 | assert.strictEqual(2, 1);
20 | });
21 |
22 | after(function afterHookNoReporting() {
23 | throw new Error('After hook error fail');
24 | });
25 | });
26 |
27 | describe('Hook Test Top Describe Pass', function () {
28 | before(function () {
29 | assert.strictEqual(1, 1);
30 | });
31 |
32 | it('Test Failing Test @fail', function () {
33 | assert.strictEqual(2, 1);
34 | });
35 |
36 | it('Test Passing Test @pass', function () {
37 | assert.strictEqual(1, 1);
38 | });
39 |
40 | after(function afterHookNoReporting() {
41 | assert.strictEqual(1, 1);
42 | });
43 | });
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Jamie Sherriff
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Proposed changes
2 |
3 | Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue.
4 |
5 | ## Types of changes
6 |
7 | What types of changes does your code introduce
8 | _Put an `x` in the boxes that apply_
9 |
10 | - [ ] Bugfix (non-breaking change which fixes an issue)
11 | - [ ] New feature (non-breaking change which adds functionality)
12 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
13 |
14 | ## Checklist
15 |
16 | _Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._
17 |
18 | - [ ] Lint and unit tests pass locally with my changes
19 | - [ ] I have added tests that prove my fix is effective or that my feature works
20 | - [ ] I have added necessary documentation (if appropriate)
21 |
22 | ## Further comments
23 |
24 | If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc...
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mocha-teamcity-reporter",
3 | "engines": {
4 | "node": ">=6"
5 | },
6 | "version": "4.2.0",
7 | "description": "teamcity reporter for mocha",
8 | "main": "./lib/teamcity.js",
9 | "directories": {
10 | "lib": "./lib"
11 | },
12 | "scripts": {
13 | "test": "mocha test/functional test/programmatic",
14 | "test-teamcity": "mocha test/functional test/programmatic --reporter lib/teamcity.js",
15 | "test-teamcity-example": "mocha test/example/exampleSimple.js --reporter lib/teamcity.js",
16 | "lint": "eslint lib/*.js test/**/*.js",
17 | "lint-fix": "eslint --fix lib/*.js test/**/*.js"
18 | },
19 | "repository": {
20 | "type": "git",
21 | "url": "https://github.com/travisjeffery/mocha-teamcity-reporter"
22 | },
23 | "keywords": [
24 | "mocha",
25 | "teamcity",
26 | "reporter",
27 | "jetbrains"
28 | ],
29 | "peerDependencies": {
30 | "mocha": ">=6"
31 | },
32 | "author": "travis jeffery",
33 | "maintainers": [
34 | {
35 | "name": "Jamie Sherriff",
36 | "url": "https://github.com/jamie-sherriff"
37 | }
38 | ],
39 | "license": "MIT",
40 | "bugs": {
41 | "url": "https://github.com/travisjeffery/mocha-teamcity-reporter/issues"
42 | },
43 | "devDependencies": {
44 | "chai": "^4.3.4",
45 | "eslint": "^7.25.0",
46 | "mocha": "^8.3.2"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/test/example/failingIgnoreHookNoRoot.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by dj-glock on 04/06/2021.
3 | */
4 | 'use strict';
5 | const assert = require('assert');
6 |
7 | describe('Hook Test Top Describe Fail', function () {
8 | before(function () {
9 | assert.strictEqual(1, 1);
10 | });
11 |
12 | // Name of the function is an additional check for case when ignoreHookWithName is undefined
13 | beforeEach(function undefinedbeforeEachHookNoReporting() {
14 | throw new Error('Before each hook error fail');
15 | });
16 |
17 | it('Test Passing Test @pass', function () {
18 | assert.strictEqual(1, 1);
19 | });
20 |
21 | // Name of the function is an additional check for case when ignoreHookWithName is undefined
22 | afterEach(function undefinedafterEachHook() {
23 | throw new Error('After each hook error fail');
24 | });
25 |
26 | after(function afterHookNoReporting() {
27 | throw new Error('After hook error fail');
28 | });
29 | });
30 |
31 | describe('Hook Test Top Describe Pass', function () {
32 | before(function () {
33 | assert.strictEqual(1, 1);
34 | });
35 |
36 | beforeEach(function beforeEachHookNoReporting() {
37 | assert.strictEqual(1, 1);
38 | });
39 |
40 | it('Test Failing Test @fail', function () {
41 | assert.strictEqual(2, 1);
42 | });
43 |
44 | it('Test Passing Test @pass', function () {
45 | assert.strictEqual(1, 1);
46 | });
47 |
48 | afterEach(function afterEachHookNoReporting() {
49 | assert.strictEqual(1, 1);
50 | });
51 |
52 | after(function afterHook() {
53 | assert.strictEqual(1, 1);
54 | });
55 | });
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "es6": true,
4 | "node": true,
5 | "browser": true,
6 | "mocha": true
7 | },
8 | "extends": "eslint:recommended",
9 | "rules": {
10 | "no-useless-return": "error",
11 | "no-undefined": "error",
12 | "no-undef-init": "error",
13 | "no-eq-null": "error",
14 | "eqeqeq": "error",
15 | "no-alert": "error",
16 | "no-caller": "error",
17 | "no-shadow": "error",
18 | "no-new-func": "error",
19 | "default-case": "error",
20 | "comma-spacing": "error",
21 | "no-shadow-restricted-names": "error",
22 | "no-path-concat": "error",
23 | "no-use-before-define": "error",
24 | "no-duplicate-imports":"error",
25 | "no-useless-rename":"error",
26 | "space-in-parens":"error",
27 | "no-multiple-empty-lines": ["error", {"max":2, "maxEOF": 0, "maxBOF":1}],
28 | "space-before-function-paren": ["error", {
29 | "anonymous": "always",
30 | "named": "never",
31 | "asyncArrow": "always"
32 | }],
33 | "max-params":["error", 5],
34 | "key-spacing":"error",
35 | "strict": ["error", "global"],
36 | "prefer-promise-reject-errors":"error",
37 | "camelcase": ["error", { "properties": "never" }],
38 | "no-unused-vars": ["warn", { "vars": "all", "args": "after-used"}],
39 | "max-len": [
40 | "error",
41 | 160,
42 | {
43 | "ignoreComments": true,
44 | "ignoreTrailingComments": true,
45 | "ignoreRegExpLiterals": true
46 | }
47 | ],
48 | //"no-mixed-spaces-and-tab": ["error", "smart-tabs"],
49 | "no-console": 0,
50 | "quotes": [
51 | "error",
52 | "single",
53 | {
54 | "allowTemplateLiterals": true,
55 | "avoidEscape": true
56 | }
57 | ],
58 | "semi": [
59 | "error",
60 | "always"
61 | ],
62 | //ES6 specific
63 | "arrow-spacing": "error",
64 | "template-curly-spacing": "error",
65 |
66 | //Rules to tighten below
67 | "complexity": ["error", 12], //Want to up this to like 5
68 | "arrow-body-style": ["off", "as-needed", {"requireReturnForObjectLiteral" : true}],
69 | "no-regex-spaces": "off",
70 | "no-var":"off",
71 | "prefer-arrow-callback": "off",
72 | "indent": [
73 | "off",
74 | "tab"
75 | ]
76 | }
77 | }
--------------------------------------------------------------------------------
/lib/teamcityBrowser.js:
--------------------------------------------------------------------------------
1 | /*eslint max-len: ["error", { "code": 220 }]*/
2 |
3 | 'use strict';
4 | /**
5 | * Teamcity doc reference https://confluence.jetbrains.com/display/TCD10/Build+Script+Interaction+with+TeamCity
6 | *
7 | * Module dependencies.
8 | */
9 | var Base = window.Mocha.reporters.Base;
10 | var log;
11 | if(typeof window.customLogFunction === 'function'){
12 | log = window.customLogFunction;
13 | } else{
14 | log = console.log;
15 | }
16 |
17 |
18 | function escape(str) {
19 | if (!str) return '';
20 | return str
21 | .toString()
22 | .replace(/\x1B.*?m/g, '') // eslint-disable-line no-control-regex
23 | .replace(/\|/g, '||')
24 | .replace(/\n/g, '|n')
25 | .replace(/\r/g, '|r')
26 | .replace(/\[/g, '|[')
27 | .replace(/\]/g, '|]')
28 | .replace(/\u0085/g, '|x')
29 | .replace(/\u2028/g, '|l')
30 | .replace(/\u2029/g, '|p')
31 | .replace(/'/g, '|\'');
32 | }
33 |
34 | /**
35 | * Initialize a new `Teamcity` reporter for the browser.
36 | *
37 | * @param {Runner} runner
38 | * @param {options} options
39 | * @api public
40 | */
41 | function teamcity(runner) {
42 | Base.call(this, runner);
43 | var stats = this.stats;
44 | var flowId = document.title || new Date().getTime();
45 |
46 | runner.on('suite', function (suite) {
47 | if (suite.root) return;
48 | suite.startDate = new Date();
49 | log('##teamcity[testSuiteStarted name=\'' + escape(suite.title) + '\' flowId=\'' + flowId + '\']');
50 | });
51 |
52 | runner.on('test', function (test) {
53 | log('##teamcity[testStarted name=\'' + escape(test.title) + '\' flowId=\'' + flowId + '\' captureStandardOutput=\'true\']');
54 | });
55 |
56 | runner.on('fail', function (test, err) {
57 | log('##teamcity[testFailed name=\'' + escape(test.title) + '\' flowId=\'' + flowId + '\' message=\'' + escape(err.message) + '\' captureStandardOutput=\'true\' details=\'' + escape(err.stack) + '\']');
58 | });
59 |
60 | runner.on('pending', function (test) {
61 | log('##teamcity[testIgnored name=\'' + escape(test.title) + '\' flowId=\'' + flowId + '\' message=\'pending\']');
62 | });
63 |
64 | runner.on('test end', function (test) {
65 | log('##teamcity[testFinished name=\'' + escape(test.title) + '\' flowId=\'' + flowId + '\' duration=\'' + test.duration + '\']');
66 | });
67 |
68 | runner.on('suite end', function (suite) {
69 | if (suite.root) return;
70 | log('##teamcity[testSuiteFinished name=\'' + escape(suite.title) + '\' duration=\'' + (new Date() - suite.startDate) + '\' flowId=\'' + flowId + '\']');
71 | });
72 |
73 | runner.on('end', function () {
74 | var duration;
75 | (typeof stats === 'undefined') ? duration = '0' : duration = stats.duration;
76 | log('##teamcity[testSuiteFinished name=\'mocha.suite\' duration=\'' + duration + '\' flowId=\'' + flowId + '\']');
77 | });
78 | }
79 |
80 | window.Mocha.reporters.teamcity = teamcity;
81 |
--------------------------------------------------------------------------------
/test/functional/topLevelSuiteOutput.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const {execFile} = require('child_process');
3 | const {assert} = require('chai');
4 | const {logMochaOutput, getMochaPath} = require('../testHelpers');
5 | const internalMochaPath = getMochaPath();
6 | const path = require('path');
7 |
8 | describe('Check TeamCity Output is correct with outer suite', function () {
9 | let teamCityStdout, teamCityStderr, teamCityOutputArray;
10 |
11 | function verifyResults() {
12 | it('stdout output should exist', function () {
13 | assert.isOk(teamCityStdout, 'has output');
14 | assert.isOk(teamCityOutputArray, 'array of output is populated');
15 | assert.isOk(teamCityOutputArray.length >= 9, 'at least 9 lines of output');
16 | });
17 |
18 | it('stderr output should not exist', function () {
19 | assert.isOk(teamCityStderr.length === 0);
20 | });
21 |
22 | it('Prefix suite start is present', function () {
23 | const rowToCheck = teamCityOutputArray[0];
24 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
25 | assert.isOk(/name='test-outer-suite-name'/.test(rowToCheck));
26 | assert.isOk(/flowId=/.test(rowToCheck));
27 | assert.isOk(/]/.test(rowToCheck));
28 | });
29 |
30 | it('Prefix suite end is present', function () {
31 | const rowToCheck = teamCityOutputArray[9];
32 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
33 | assert.isNotOk(/name='mocha.suite'/.test(rowToCheck));
34 | assert.isOk(/duration=/.test(rowToCheck));
35 | assert.isOk(/flowId=/.test(rowToCheck));
36 | assert.isOk(/]/.test(rowToCheck));
37 | });
38 |
39 | it('Skip Test Finished is ignored', function () {
40 | const rowToCheck = teamCityOutputArray[7];
41 | assert.isOk(/##teamcity\[testIgnored/.test(rowToCheck));
42 | assert.isOk(/name='Skipped Test @skip'/.test(rowToCheck));
43 | assert.isOk(/flowId=/.test(rowToCheck));
44 | assert.isOk(/message='Skipped Test @skip'/.test(rowToCheck));
45 | assert.isNotOk(/duration=/.test(rowToCheck));
46 | assert.isOk(/]/.test(rowToCheck));
47 | });
48 |
49 | it('Suite Root Finished is OK', function () {
50 | const rowToCheck = teamCityOutputArray[9];
51 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
52 | assert.isNotOk(/name='mocha.suite'/.test(rowToCheck));
53 | assert.isOk(/duration=/.test(rowToCheck));
54 | assert.isOk(/flowId=/.test(rowToCheck));
55 | assert.isOk(/]/.test(rowToCheck));
56 | });
57 | }
58 |
59 | describe('specified as an env var', function () {
60 | before(function (done) {
61 | const opts = {
62 | env: Object.assign({
63 | MOCHA_TEAMCITY_TOP_LEVEL_SUITE: 'test-outer-suite-name'
64 | }, process.env)
65 | };
66 |
67 | execFile(internalMochaPath, [
68 | path.join('test', 'test_data', 'simple.js'),
69 | '--reporter',
70 | 'lib/teamcity'
71 | ], opts, (err, stdout, stderr) => {
72 | teamCityStdout = stdout;
73 | teamCityStderr = stderr;
74 | teamCityOutputArray = stdout.split('\n');
75 | logMochaOutput(stdout, stderr);
76 | done();
77 | });
78 | });
79 | verifyResults();
80 | });
81 |
82 | describe('specified with --reporter-options', function () {
83 | before(function (done) {
84 | execFile(internalMochaPath, [
85 | path.join('test', 'test_data', 'simple.js'),
86 | '--reporter',
87 | 'lib/teamcity',
88 | '--reporter-options',
89 | 'topLevelSuite=test-outer-suite-name'
90 | ], (err, stdout, stderr) => {
91 | teamCityStdout = stdout;
92 | teamCityStderr = stderr;
93 | teamCityOutputArray = stdout.split('\n');
94 | logMochaOutput(stdout, stderr);
95 | done();
96 | });
97 | });
98 | verifyResults();
99 | });
100 |
101 | });
102 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | 4.2.0 / 2021-11-21
2 | ==================
3 |
4 | * Solve # Issue 65 "Pending tests are displayed as Passed in teamcity UI" by PR #66 (@fernyb )
5 | * Solved by producing correct output as per teamcity documentation, functionality can be disabled by reporter option `displayIgnoredAsIgnored`
6 |
7 | 4.1.0 / 2021-05-30
8 | ==================
9 |
10 | * Solve # Issue 61 "Failed tests appears as successful in TeamCity" by PR #63 (@DJ-Glock)
11 | * Solved by adding postfix _hook for flowId for hooks. FlowIds will never intersect.
12 |
13 | 4.0.0 / 2021-05-03
14 | ==================
15 |
16 | * Breaking: Only supported on node.js 6 and above
17 | * Breaking: Only Mocha version 6 and above is now supported
18 | * Please remain on `mocha-teamcity-reporter@3` if this is an issue
19 | * New reporter option `ignoreHookWithName` to skip reporting for hooks with title containing some word (@DJ-Glock)
20 | * Implement 'hook end' event (@DJ-GLock)
21 | * General maintenance and tidy up (@DJ-Glock)
22 |
23 | 3.0.0 / 2019-01-21
24 | ==================
25 |
26 | * Change mocha to peer dependency
27 | * Support mocha version 6
28 | * Breaking: focus on only support node.js environments (Please )
29 | * Breaking: Remove phantomJs support only supports environments which have require
30 | * Potential Breaking: Remove Redundant top level mocha.suite
31 | * Drop the duration on messages if mocha returns undefined/null (for example skipped test) TeamCity will then use received timestamps to calculate duration
32 | * Support Show diff between expected and actual values
33 |
34 | TODO
35 | comparisonFailure service message attributes
36 |
37 | 2.5.2 / 2019-01-21
38 | ==================
39 |
40 | * Restrict mocha dependency to less than 6 due to compatibility issues
41 |
42 | 2.5.1 / 2018-09-27
43 | ==================
44 |
45 | * Vuejs/Webpack compatibility, solves #45
46 |
47 | 2.5.0 / 2018-09-18
48 | ==================
49 |
50 | * Add test in hook option, solves #35
51 |
52 | 2.4.0 / 2018-04-18
53 | ==================
54 |
55 | * Add Browser Support back in by use of separate file, solves #41
56 |
57 | 2.3.0 / 2018-04-18
58 | ==================
59 |
60 | * Add use stdError option solves #31
61 |
62 | 2.2.2 / 2018-02-27
63 | ==================
64 |
65 | * Fix issue #39
66 | * Add real teamcity tests
67 |
68 | 2.2.1 / 2018-02-06
69 | ==================
70 |
71 | * Merge pull request #38 reporterOptions are optional from chge/master
72 | * Add a test to catch above PR
73 |
74 | 2.2.0 / 2018-02-05
75 | ==================
76 |
77 | * Maintenance Update, Merged forked branch back into master branch by Travis
78 | * Breaking change, supports node 4+ only
79 | * Support flowId's
80 | * Why use flowIds? Flow tracking is necessary, for example, to distinguish separate processes running in parallel
81 | * This defaults to process.pid, so it works with concurrent task runners (Gulp/Grunt etc)
82 | * Other small bug fixes
83 | * Functional tests
84 |
85 | 2.1.0 / 2017-10-19
86 | ==================
87 |
88 | * add top level suite option (@davidmfoley)
89 |
90 | 2.0.1 / 2017-08-22
91 | ==================
92 |
93 | * Bug Fixes
94 |
95 | 2.0.0 / 2017-08-20
96 | ==================
97 |
98 | * Add FlowId
99 | * Minimum nodejs engine of 4+
100 | * Add some eslint magic
101 |
102 | 1.1.0 / 2016-08-24
103 | ==================
104 |
105 | * Support running in the browser with Mocha without require.js
106 |
107 | 1.0.1 / 2016-07-18
108 | ==================
109 |
110 | * Remove escape sequences from reporting
111 | * Fix NaN duration
112 |
113 | 1.0.0 / 2015-09-30
114 | ==================
115 |
116 | * Merge pull request #14 from debitoor/master
117 | * add err.stack to details of error
118 | * Merge pull request #8 from bdefore/master
119 | * Update teamcity.js
120 | * Merge pull request #6 from pandell/mocha-phantomjs
121 |
--------------------------------------------------------------------------------
/test/functional/testOutput.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jamie on 12/08/2017.
3 | * Must be run from the root project dir
4 | */
5 | 'use strict';
6 |
7 | const {execFile} = require('child_process');
8 | const {assert} = require('chai');
9 | const path = require('path');
10 |
11 | const { logMochaOutput, getMochaPath } = require('../testHelpers');
12 |
13 | const internalMochaPath = getMochaPath();
14 |
15 | describe('Check TeamCity Output is correct', function () {
16 | let teamCityStdout, teamCityStderr, teamCityOutputArray;
17 |
18 | before(function (done) {
19 | execFile(internalMochaPath, [path.join('test', 'test_data', 'simple.js'), '--reporter', 'lib/teamcity'], (err, stdout, stderr) => {
20 | teamCityStdout = stdout;
21 | teamCityStderr = stderr;
22 | teamCityOutputArray = stdout.split('\n');
23 | logMochaOutput(stdout, stderr);
24 | done();
25 | });
26 | });
27 |
28 | it('Output should exist', function () {
29 | assert.isOk(teamCityStdout);
30 | assert.isOk(teamCityOutputArray);
31 | assert.isOk(teamCityStderr.length === 0);
32 | assert.isOk(teamCityOutputArray.length >= 10);
33 | });
34 |
35 | it('Suite started is OK', function () {
36 | const rowToCheck = teamCityOutputArray[0];
37 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
38 | assert.isOk(/name='Top Describe'/.test(rowToCheck));
39 | assert.isOk(/flowId=/.test(rowToCheck));
40 | assert.isOk(/]/.test(rowToCheck));
41 | });
42 |
43 | it('Test started is OK', function () {
44 | const rowToCheck = teamCityOutputArray[1];
45 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
46 | assert.isOk(/name='Passing Test @pass'/.test(rowToCheck));
47 | assert.isOk(/flowId=/.test(rowToCheck));
48 | assert.isOk(/]/.test(rowToCheck));
49 | });
50 |
51 | it('Passing Test Finished is OK', function () {
52 | const rowToCheck = teamCityOutputArray[2];
53 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
54 | assert.isOk(/name='Passing Test @pass'/.test(rowToCheck));
55 | assert.isOk(/flowId=/.test(rowToCheck));
56 | assert.isOk(/duration=/.test(rowToCheck));
57 | assert.isOk(/]/.test(rowToCheck));
58 | });
59 |
60 | it('Test Failed Started is OK', function () {
61 | const rowToCheck = teamCityOutputArray[3];
62 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
63 | assert.isOk(/name='Failing Test @fail'/.test(rowToCheck));
64 | assert.isOk(/flowId=/.test(rowToCheck));
65 | assert.isOk(/duration=/.test(rowToCheck) === false);
66 | assert.isOk(/]/.test(rowToCheck));
67 | });
68 |
69 | it('Test Failed is Failing', function () {
70 | const rowToCheck = teamCityOutputArray[4];
71 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
72 | assert.isOk(/name='Failing Test @fail'/.test(rowToCheck));
73 | assert.isOk(/flowId=/.test(rowToCheck));
74 | assert.isOk(/duration=/.test(rowToCheck) === false);
75 | assert.isOk(/details='/.test(rowToCheck));
76 | assert.isOk(/AssertionError/.test(rowToCheck));
77 | assert.isOk(/|n/.test(rowToCheck));
78 | assert.isOk(/|simple.js:11:11/.test(rowToCheck));
79 | assert.isOk(/captureStandardOutput='true'/.test(rowToCheck));
80 | assert.isOk(/]/.test(rowToCheck));
81 | });
82 |
83 | it('Failing Test Finished is OK', function () {
84 | const rowToCheck = teamCityOutputArray[5];
85 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
86 | assert.isOk(/name='Failing Test @fail'/.test(rowToCheck));
87 | assert.isOk(/flowId=/.test(rowToCheck));
88 | assert.isOk(/duration=/.test(rowToCheck));
89 | assert.isOk(/]/.test(rowToCheck));
90 | });
91 |
92 | it('Skip Test Finished is ignored', function () {
93 | const rowToCheck = teamCityOutputArray[6];
94 | assert.isOk(/##teamcity\[testIgnored/.test(rowToCheck));
95 | assert.isOk(/name='Skipped Test @skip'/.test(rowToCheck));
96 | assert.isOk(/flowId=/.test(rowToCheck));
97 | assert.isOk(/message='Skipped Test @skip'/.test(rowToCheck));
98 | assert.isOk(/duration=/.test(rowToCheck) === false);
99 | assert.isOk(/]/.test(rowToCheck));
100 | });
101 |
102 | it('Skip Test Finished is OK', function () {
103 | const rowToCheck = teamCityOutputArray[7];
104 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
105 | assert.isOk(/name='Skipped Test @skip'/.test(rowToCheck));
106 | assert.isOk(/flowId=/.test(rowToCheck));
107 | assert.isNotOk(/duration=/.test(rowToCheck));
108 | assert.isOk(/]/.test(rowToCheck));
109 | });
110 |
111 | it('Suite Finished is OK', function () {
112 | const rowToCheck = teamCityOutputArray[8];
113 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
114 | assert.isOk(/name='Top Describe'/.test(rowToCheck));
115 | assert.isOk(/duration=/.test(rowToCheck));
116 | assert.isOk(/flowId=/.test(rowToCheck));
117 | assert.isOk(/]/.test(rowToCheck));
118 | });
119 |
120 | it('Suite Root Finished is OK', function () {
121 | const rowToCheck = teamCityOutputArray[8];
122 | assert.isEmpty(teamCityOutputArray[9], 'Last row should be empty');
123 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
124 | assert.isNotOk(/name='mocha.suite'/.test(rowToCheck));
125 | assert.isOk(/duration=/.test(rowToCheck));
126 | assert.isOk(/flowId=/.test(rowToCheck));
127 | assert.isOk(/]/.test(rowToCheck));
128 | });
129 |
130 | });
131 |
--------------------------------------------------------------------------------
/test/functional/useStdError.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const {execFile} = require('child_process');
3 | const {assert} = require('chai');
4 | const { logMochaOutput, getMochaPath } = require('../testHelpers');
5 | const internalMochaPath = getMochaPath();
6 | const path = require('path');
7 |
8 | describe('Check TeamCity Output is correct with stdError option', function () {
9 | let teamCityStdout, teamCityStderr, teamCityOutputArray, teamCityErrorOutputArray;
10 | function verifyResults() {
11 | it('stdout output should exist', function () {
12 | assert.isOk(teamCityStdout, 'has output');
13 | assert.isOk(teamCityOutputArray, 'array of output is populated');
14 | assert.isOk(teamCityOutputArray.length >= 9, 'at least 9 lines of output');
15 | assert.lengthOf(teamCityOutputArray, 9);
16 | });
17 |
18 | it('stderr output should exist', function () {
19 | assert.isOk(teamCityStderr);
20 | assert.isAbove(teamCityStderr.length, 15);
21 | assert.lengthOf(teamCityErrorOutputArray, 2);
22 | });
23 |
24 |
25 | it('stdout output should exist', function () {
26 | assert.isOk(teamCityStdout);
27 | assert.isOk(teamCityOutputArray);
28 | assert.isOk(teamCityOutputArray.length >= 9);
29 | });
30 |
31 | it('Suite started is OK', function () {
32 | const rowToCheck = teamCityOutputArray[0];
33 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
34 | assert.isOk(/name='Top Describe'/.test(rowToCheck));
35 | assert.isOk(/flowId=/.test(rowToCheck));
36 | assert.isOk(/]/.test(rowToCheck));
37 | });
38 |
39 | it('Test started is OK', function () {
40 | const rowToCheck = teamCityOutputArray[1];
41 | assert.match(rowToCheck, /##teamcity\[testStarted/);
42 | assert.match(rowToCheck, /name='Passing Test @pass'/);
43 | assert.match(rowToCheck, /flowId=/);
44 | assert.match(rowToCheck, /]/);
45 | });
46 |
47 | it('Passing Test Finished is OK', function () {
48 | const rowToCheck = teamCityOutputArray[2];
49 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
50 | assert.isOk(/name='Passing Test @pass'/.test(rowToCheck));
51 | assert.isOk(/flowId=/.test(rowToCheck));
52 | assert.isOk(/duration=/.test(rowToCheck));
53 | assert.isOk(/]/.test(rowToCheck));
54 | });
55 |
56 | it('Test Failed Started is OK', function () {
57 | const rowToCheck = teamCityOutputArray[3];
58 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
59 | assert.isOk(/name='Failing Test @fail'/.test(rowToCheck));
60 | assert.isOk(/flowId=/.test(rowToCheck));
61 | assert.isOk(/duration=/.test(rowToCheck) === false);
62 | assert.isOk(/]/.test(rowToCheck));
63 | });
64 |
65 | it('Test Failed is Failing', function () {
66 | const rowToCheck = teamCityErrorOutputArray;
67 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
68 | assert.isOk(/name='Failing Test @fail'/.test(rowToCheck));
69 | assert.isOk(/flowId=/.test(rowToCheck));
70 | assert.isOk(/duration=/.test(rowToCheck) === false);
71 | assert.isOk(/details='/.test(rowToCheck));
72 | assert.isOk(/AssertionError/.test(rowToCheck));
73 | assert.isOk(/|n/.test(rowToCheck));
74 | assert.isOk(/|simple.js:11:11/.test(rowToCheck));
75 | assert.isOk(/captureStandardOutput='true'/.test(rowToCheck));
76 | assert.isOk(/]/.test(rowToCheck));
77 | });
78 |
79 | it('Failing Test Finished is OK', function () {
80 | const rowToCheck = teamCityOutputArray[4];
81 | assert.match(rowToCheck, /##teamcity\[testFinished/);
82 | assert.match(rowToCheck, /name='Failing Test @fail'/);
83 | assert.match(rowToCheck, /flowId=/);
84 | assert.match(rowToCheck, /duration=/);
85 | assert.match(rowToCheck, /]/);
86 | });
87 |
88 | it('Skip Test Finished is ignored', function () {
89 | const rowToCheck = teamCityOutputArray[5];
90 | assert.isOk(/##teamcity\[testIgnored/.test(rowToCheck));
91 | assert.isOk(/name='Skipped Test @skip'/.test(rowToCheck));
92 | assert.isOk(/flowId=/.test(rowToCheck));
93 | assert.isOk(/message='Skipped Test @skip'/.test(rowToCheck));
94 | assert.isOk(/duration=/.test(rowToCheck) === false);
95 | assert.isOk(/]/.test(rowToCheck));
96 | });
97 |
98 | it('Skip Test Finished is OK', function () {
99 | const rowToCheck = teamCityOutputArray[6];
100 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
101 | assert.isOk(/name='Skipped Test @skip'/.test(rowToCheck));
102 | assert.isOk(/flowId=/.test(rowToCheck));
103 | assert.isNotOk(/duration=/.test(rowToCheck));
104 | assert.isOk(/]/.test(rowToCheck));
105 | });
106 |
107 | it('Suite Finished is OK', function () {
108 | const rowToCheck = teamCityOutputArray[7];
109 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
110 | assert.isOk(/name='Top Describe'/.test(rowToCheck));
111 | assert.isOk(/duration=/.test(rowToCheck));
112 | assert.isOk(/flowId=/.test(rowToCheck));
113 | assert.isOk(/]/.test(rowToCheck));
114 | });
115 |
116 | it('Suite Root Finished is OK', function () {
117 | const rowToCheck = teamCityOutputArray[7];
118 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
119 | assert.isNotOk(/name='mocha.suite'/.test(rowToCheck));
120 | assert.isOk(/duration=/.test(rowToCheck));
121 | assert.isOk(/flowId=/.test(rowToCheck));
122 | assert.isOk(/]/.test(rowToCheck));
123 | });
124 | }
125 |
126 | describe('specified as an env var', function () {
127 | before(function (done) {
128 | const opts = {
129 | env: Object.assign({
130 | ['USE_STD_ERROR']: 'true'
131 | }, process.env)
132 | };
133 |
134 | execFile(internalMochaPath, [
135 | 'test/test_data',
136 | '--reporter',
137 | 'lib/teamcity'
138 | ], opts, (err, stdout, stderr) => {
139 | teamCityStdout = stdout;
140 | teamCityStderr = stderr;
141 | teamCityOutputArray = stdout.split('\n');
142 | teamCityErrorOutputArray = stderr.split('\n');
143 | logMochaOutput(stdout, stderr);
144 | done();
145 | });
146 | });
147 | verifyResults();
148 | });
149 |
150 | describe('specified with --reporter-options', function () {
151 | before(function (done) {
152 | execFile(internalMochaPath, [
153 | path.join('test', 'test_data', 'simple.js'),
154 | '--reporter',
155 | 'lib/teamcity',
156 | '--reporter-options',
157 | 'useStdError=true'
158 | ], (err, stdout, stderr) => {
159 | teamCityStdout = stdout;
160 | teamCityStderr = stderr;
161 | teamCityOutputArray = stdout.split('\n');
162 | teamCityErrorOutputArray = stderr.split('\n');
163 | logMochaOutput(stdout, stderr);
164 | done();
165 | });
166 | });
167 | verifyResults();
168 | });
169 |
170 | });
171 |
--------------------------------------------------------------------------------
/test/functional/recordHookFailuresDisabled.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const {execFile} = require('child_process');
3 | const {assert} = require('chai');
4 | const { logMochaOutput, getMochaPath } = require('../testHelpers');
5 | const internalMochaPath = getMochaPath();
6 | const path = require('path');
7 |
8 | describe('Check TeamCity Output is correct with recordHookFailures option disabled', function () {
9 | let teamCityStdout, teamCityStderr, teamCityOutputArray;
10 | function verifyResults() {
11 | it('1 stdout output should exist', function () {
12 | assert.isOk(teamCityStdout, 'has output');
13 | assert.isOk(teamCityOutputArray, 'array of output is populated');
14 | assert.lengthOf(teamCityOutputArray, 11);
15 | assert.isEmpty(teamCityOutputArray[10]);
16 | });
17 |
18 | it('2 stderr output should not exist', function () {
19 | assert.isEmpty(teamCityStderr);
20 | });
21 |
22 | it('3 testSuiteStarted for Suite1', function () {
23 | const rowToCheck = teamCityOutputArray[0];
24 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
25 | assert.isOk(/name='Hook Test Top Describe Fail'/.test(rowToCheck));
26 | assert.isOk(/flowId=/.test(rowToCheck));
27 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
28 | assert.isOk(/]/.test(rowToCheck));
29 | });
30 |
31 | it('4 testFailed for before all hook', function () {
32 | const rowToCheck = teamCityOutputArray[1];
33 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
34 | assert.isOk(/name='"before all" hook/.test(rowToCheck));
35 | assert.isOk(/details='/.test(rowToCheck));
36 | assert.isOk(/Error: Before hook error fail/.test(rowToCheck));
37 | assert.isOk(/|n/.test(rowToCheck));
38 | assert.isOk(/|failingHook.js:29:12/.test(rowToCheck));
39 | assert.isOk(/captureStandardOutput='true'/.test(rowToCheck));
40 | assert.match(rowToCheck, /flowId=.*_hook/);
41 | assert.isOk(/duration=/.test(rowToCheck) === false);
42 | assert.isOk(/]/.test(rowToCheck));
43 | });
44 |
45 | it('5 testSuiteFinished for Suite1', function () {
46 | const rowToCheck = teamCityOutputArray[2];
47 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
48 | assert.isOk(/name='Hook Test Top Describe Fail'/.test(rowToCheck));
49 | assert.isOk(/duration=/.test(rowToCheck));
50 | assert.isOk(/flowId=/.test(rowToCheck));
51 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
52 | assert.isOk(/]/.test(rowToCheck));
53 | });
54 |
55 | it('6 testSuiteStarted for Suite2', function () {
56 | const rowToCheck = teamCityOutputArray[3];
57 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
58 | assert.isOk(/name='Hook Test Top Describe Pass'/.test(rowToCheck));
59 | assert.isOk(/flowId=/.test(rowToCheck));
60 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
61 | assert.isOk(/]/.test(rowToCheck));
62 | });
63 |
64 | it('7 testStarted for Failing Test', function () {
65 | const rowToCheck = teamCityOutputArray[4];
66 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
67 | assert.isOk(/name='Test Failing Test @fail'/.test(rowToCheck));
68 | assert.isOk(/flowId=/.test(rowToCheck));
69 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
70 | assert.isOk(/]/.test(rowToCheck));
71 | });
72 |
73 | it('8 testFailed for Failing Test', function () {
74 | const rowToCheck = teamCityOutputArray[5];
75 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
76 | assert.isOk(/name='Test Failing Test @fail'/.test(rowToCheck));
77 | assert.isOk(/flowId=/.test(rowToCheck));
78 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
79 | assert.isOk(/duration=/.test(rowToCheck) === false);
80 | assert.isOk(/details='/.test(rowToCheck));
81 | assert.isOk(/AssertionError/.test(rowToCheck));
82 | assert.isOk(/|n/.test(rowToCheck));
83 | assert.isOk(/|failingHook.js:29:12/.test(rowToCheck));
84 | assert.isOk(/captureStandardOutput='true'/.test(rowToCheck));
85 | assert.isOk(/]/.test(rowToCheck));
86 | });
87 |
88 | it('9 testFinished for Failing Test', function () {
89 | const rowToCheck = teamCityOutputArray[6];
90 | assert.match(rowToCheck, /##teamcity\[testFinished/);
91 | assert.match(rowToCheck, /name='Test Failing Test @fail'/);
92 | assert.match(rowToCheck, /flowId=/);
93 | assert.match(rowToCheck, /duration=/);
94 | assert.match(rowToCheck, /]/);
95 | });
96 |
97 | it('10 testStarted for Passing Test', function () {
98 | const rowToCheck = teamCityOutputArray[7];
99 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
100 | assert.isOk(/name='Test Passing Test @pass'/.test(rowToCheck));
101 | assert.isOk(/flowId=/.test(rowToCheck));
102 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
103 | assert.isOk(/]/.test(rowToCheck));
104 | });
105 |
106 |
107 | it('11 testFinished for Passing Test', function () {
108 | const rowToCheck = teamCityOutputArray[8];
109 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
110 | assert.isOk(/name='Test Passing Test @pass'/.test(rowToCheck));
111 | assert.isOk(/flowId=/.test(rowToCheck));
112 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
113 | assert.isOk(/duration=/.test(rowToCheck));
114 | assert.isOk(/]/.test(rowToCheck));
115 | });
116 |
117 | it('12 testSuiteFinished for Suite2', function () {
118 | const rowToCheck = teamCityOutputArray[9];
119 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
120 | assert.isOk(/name='Hook Test Top Describe Pass'/.test(rowToCheck));
121 | assert.isOk(/duration=/.test(rowToCheck));
122 | assert.isOk(/flowId=/.test(rowToCheck));
123 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
124 | assert.isOk(/]/.test(rowToCheck));
125 | });
126 | }
127 |
128 | describe('specified as an env var', function () {
129 | before(function (done) {
130 | const opts = {};
131 |
132 | execFile(internalMochaPath, [
133 | 'test/example/failingHook.js',
134 | '--reporter',
135 | 'lib/teamcity'
136 | ], opts, (err, stdout, stderr) => {
137 | teamCityStdout = stdout;
138 | teamCityStderr = stderr;
139 | teamCityOutputArray = stdout.split('\n');
140 | logMochaOutput(stdout, stderr);
141 | done();
142 | });
143 | });
144 | verifyResults();
145 | });
146 |
147 | describe('specified with --reporter-options', function () {
148 | before(function (done) {
149 | execFile(internalMochaPath, [
150 | path.join('test', 'example', 'failingHook.js'),
151 | '--reporter',
152 | 'lib/teamcity'
153 | ], (err, stdout, stderr) => {
154 | teamCityStdout = stdout;
155 | teamCityStderr = stderr;
156 | teamCityOutputArray = stdout.split('\n');
157 | logMochaOutput(stdout, stderr);
158 | done();
159 | });
160 | });
161 | verifyResults();
162 | });
163 | });
164 |
--------------------------------------------------------------------------------
/test/functional/actualVsExpected.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const {execFile} = require('child_process');
3 | const {assert} = require('chai');
4 | const { logMochaOutput, getMochaPath } = require('../testHelpers');
5 | const internalMochaPath = getMochaPath();
6 | const path = require('path');
7 |
8 | describe('Check TeamCity Output is correct with actualVsExpected option', function () {
9 | let teamCityStdout, teamCityStderr, teamCityOutputArray, teamCityErrorOutputArray;
10 | function verifyResults() {
11 | it('stdout output should exist', function () {
12 | assert.isOk(teamCityStdout, 'has output');
13 | assert.isOk(teamCityOutputArray, 'array of output is populated');
14 | assert.isOk(teamCityOutputArray.length >= 10, 'at least 10 lines of output');
15 | assert.lengthOf(teamCityOutputArray, 10);
16 | });
17 |
18 | it('stderr output should exist', function () {
19 | assert.isNotOk(teamCityStderr);
20 | assert.isOk(teamCityStderr.length === 0);
21 | assert.lengthOf(teamCityErrorOutputArray, 1);
22 | });
23 |
24 |
25 | it('stdout output should exist', function () {
26 | assert.isOk(teamCityStdout);
27 | assert.isOk(teamCityOutputArray);
28 | assert.isOk(teamCityOutputArray.length >= 9);
29 | });
30 |
31 | it('Suite started is OK', function () {
32 | const rowToCheck = teamCityOutputArray[0];
33 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
34 | assert.isOk(/name='Top Describe'/.test(rowToCheck));
35 | assert.isOk(/flowId=/.test(rowToCheck));
36 | assert.isOk(/]/.test(rowToCheck));
37 | });
38 |
39 | it('Test started is OK', function () {
40 | const rowToCheck = teamCityOutputArray[1];
41 | assert.match(rowToCheck, /##teamcity\[testStarted/);
42 | assert.match(rowToCheck, /name='Passing Test @pass'/);
43 | assert.match(rowToCheck, /flowId=/);
44 | assert.match(rowToCheck, /]/);
45 | });
46 |
47 | it('Passing Test Finished is OK', function () {
48 | const rowToCheck = teamCityOutputArray[2];
49 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
50 | assert.isOk(/name='Passing Test @pass'/.test(rowToCheck));
51 | assert.isOk(/flowId=/.test(rowToCheck));
52 | assert.isOk(/duration=/.test(rowToCheck));
53 | assert.isOk(/]/.test(rowToCheck));
54 | });
55 |
56 | it('Test Failed Started is OK', function () {
57 | const rowToCheck = teamCityOutputArray[3];
58 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
59 | assert.isOk(/name='Failing Test @fail'/.test(rowToCheck));
60 | assert.isOk(/flowId=/.test(rowToCheck));
61 | assert.isOk(/duration=/.test(rowToCheck) === false);
62 | assert.isOk(/]/.test(rowToCheck));
63 | });
64 |
65 | it('Test Failed is Failing', function () {
66 | const rowToCheck = teamCityOutputArray[4];
67 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
68 | assert.isOk(/name='Failing Test @fail'/.test(rowToCheck));
69 | assert.isOk(/flowId=/.test(rowToCheck));
70 | assert.isOk(/duration=/.test(rowToCheck) === false);
71 | assert.isOk(/details='/.test(rowToCheck));
72 | assert.isOk(/AssertionError/.test(rowToCheck));
73 | assert.isOk(/|n/.test(rowToCheck));
74 | assert.isOk(/|simple.js:11:11/.test(rowToCheck));
75 | assert.isOk(/captureStandardOutput='true'/.test(rowToCheck));
76 | assert.isOk(/]/.test(rowToCheck));
77 | //check keys
78 | assert.match(rowToCheck, /actual=/);
79 | assert.match(rowToCheck, /expected=/);
80 | //check both key and value
81 | assert.match(rowToCheck, /actual='2'/);
82 | assert.match(rowToCheck, /type='comparisonFailure'/);
83 | assert.match(rowToCheck, /expected='1'/);
84 | });
85 |
86 | it('Failing Test Finished is OK', function () {
87 | const rowToCheck = teamCityOutputArray[5];
88 | assert.match(rowToCheck, /##teamcity\[testFinished/);
89 | assert.match(rowToCheck, /name='Failing Test @fail'/);
90 | assert.match(rowToCheck, /flowId=/);
91 | assert.match(rowToCheck, /duration=/);
92 | assert.match(rowToCheck, /]/);
93 | });
94 |
95 | it('Skip Test Finished is ignored', function () {
96 | const rowToCheck = teamCityOutputArray[6];
97 | assert.isOk(/##teamcity\[testIgnored/.test(rowToCheck));
98 | assert.isOk(/name='Skipped Test @skip'/.test(rowToCheck));
99 | assert.isOk(/flowId=/.test(rowToCheck));
100 | assert.isOk(/message='Skipped Test @skip'/.test(rowToCheck));
101 | assert.isOk(/duration=/.test(rowToCheck) === false);
102 | assert.isOk(/]/.test(rowToCheck));
103 | });
104 |
105 | it('Skip Test Finished is OK', function () {
106 | const rowToCheck = teamCityOutputArray[7];
107 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
108 | assert.isOk(/name='Skipped Test @skip'/.test(rowToCheck));
109 | assert.isOk(/flowId=/.test(rowToCheck));
110 | assert.isNotOk(/duration=/.test(rowToCheck));
111 | assert.isOk(/]/.test(rowToCheck));
112 | });
113 |
114 | it('Suite Finished is OK', function () {
115 | const rowToCheck = teamCityOutputArray[8];
116 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
117 | assert.isOk(/name='Top Describe'/.test(rowToCheck));
118 | assert.isOk(/duration=/.test(rowToCheck));
119 | assert.isOk(/flowId=/.test(rowToCheck));
120 | assert.isOk(/]/.test(rowToCheck));
121 | });
122 |
123 | it('Suite Root Finished is OK', function () {
124 | const rowToCheck = teamCityOutputArray[8];
125 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
126 | assert.isNotOk(/name='mocha.suite'/.test(rowToCheck));
127 | assert.isOk(/duration=/.test(rowToCheck));
128 | assert.isOk(/flowId=/.test(rowToCheck));
129 | assert.isOk(/]/.test(rowToCheck));
130 | });
131 | }
132 |
133 | describe('specified as an env var', function () {
134 | before(function (done) {
135 | const opts = {
136 | env: Object.assign({
137 | ['ACTUAL_VS_EXPECTED']: 'true'
138 | }, process.env)
139 | };
140 |
141 | execFile(internalMochaPath, [
142 | 'test/test_data',
143 | '--reporter',
144 | 'lib/teamcity'
145 | ], opts, (err, stdout, stderr) => {
146 | teamCityStdout = stdout;
147 | teamCityStderr = stderr;
148 | teamCityOutputArray = stdout.split('\n');
149 | teamCityErrorOutputArray = stderr.split('\n');
150 | logMochaOutput(stdout, stderr);
151 | done();
152 | });
153 | });
154 | verifyResults();
155 | });
156 |
157 | describe('specified with --reporter-options', function () {
158 | before(function (done) {
159 | execFile(internalMochaPath, [
160 | path.join('test', 'test_data', 'simple.js'),
161 | '--reporter',
162 | 'lib/teamcity',
163 | '--reporter-options',
164 | 'actualVsExpected=true'
165 | ], (err, stdout, stderr) => {
166 | teamCityStdout = stdout;
167 | teamCityStderr = stderr;
168 | teamCityOutputArray = stdout.split('\n');
169 | teamCityErrorOutputArray = stderr.split('\n');
170 | logMochaOutput(stdout, stderr);
171 | done();
172 | });
173 | });
174 | verifyResults();
175 | });
176 |
177 | });
178 |
--------------------------------------------------------------------------------
/test/functional/testMultipleOptions.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const {execFile} = require('child_process');
3 | const {assert} = require('chai');
4 | const { logMochaOutput, getMochaPath } = require('../testHelpers');
5 | const internalMochaPath = getMochaPath();
6 | const path = require('path');
7 |
8 | describe('Check TeamCity Output is correct with stdError and actualVsExpected options', function () {
9 | let teamCityStdout, teamCityStderr, teamCityOutputArray, teamCityErrorOutputArray;
10 | function verifyResults() {
11 |
12 | it('stdout output should exist', function () {
13 | assert.isOk(teamCityStdout, 'has output');
14 | assert.isOk(teamCityOutputArray, 'array of output is populated');
15 | assert.isOk(teamCityOutputArray.length >= 9, 'at least 9 lines of output');
16 | assert.lengthOf(teamCityOutputArray, 9);
17 | });
18 |
19 | it('stderr output should exist', function () {
20 | assert.isOk(teamCityStderr);
21 | assert.isAbove(teamCityStderr.length, 15);
22 | assert.lengthOf(teamCityErrorOutputArray, 2);
23 | });
24 |
25 |
26 | it('stdout output should exist', function () {
27 | assert.isOk(teamCityStdout);
28 | assert.isOk(teamCityOutputArray);
29 | assert.isOk(teamCityOutputArray.length >= 9);
30 | });
31 |
32 | it('Suite started is OK', function () {
33 | const rowToCheck = teamCityOutputArray[0];
34 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
35 | assert.isOk(/name='Top Describe'/.test(rowToCheck));
36 | assert.isOk(/flowId=/.test(rowToCheck));
37 | assert.isOk(/]/.test(rowToCheck));
38 | });
39 |
40 | it('Test started is OK', function () {
41 | const rowToCheck = teamCityOutputArray[1];
42 | assert.match(rowToCheck, /##teamcity\[testStarted/);
43 | assert.match(rowToCheck, /name='Passing Test @pass'/);
44 | assert.match(rowToCheck, /flowId=/);
45 | assert.match(rowToCheck, /]/);
46 | });
47 |
48 | it('Passing Test Finished is OK', function () {
49 | const rowToCheck = teamCityOutputArray[2];
50 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
51 | assert.isOk(/name='Passing Test @pass'/.test(rowToCheck));
52 | assert.isOk(/flowId=/.test(rowToCheck));
53 | assert.isOk(/duration=/.test(rowToCheck));
54 | assert.isOk(/]/.test(rowToCheck));
55 | });
56 |
57 | it('Test Failed Started is OK', function () {
58 | const rowToCheck = teamCityOutputArray[3];
59 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
60 | assert.isOk(/name='Failing Test @fail'/.test(rowToCheck));
61 | assert.isOk(/flowId=/.test(rowToCheck));
62 | assert.isOk(/duration=/.test(rowToCheck) === false);
63 | assert.isOk(/]/.test(rowToCheck));
64 | });
65 |
66 | it('Test Failed is Failing', function () {
67 | const rowToCheck = teamCityErrorOutputArray;
68 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
69 | assert.isOk(/name='Failing Test @fail'/.test(rowToCheck));
70 | assert.isOk(/flowId=/.test(rowToCheck));
71 | assert.isOk(/duration=/.test(rowToCheck) === false);
72 | assert.isOk(/details='/.test(rowToCheck));
73 | assert.isOk(/AssertionError/.test(rowToCheck));
74 | assert.isOk(/|n/.test(rowToCheck));
75 | assert.isOk(/|simple.js:11:11/.test(rowToCheck));
76 | assert.isOk(/captureStandardOutput='true'/.test(rowToCheck));
77 | assert.isOk(/]/.test(rowToCheck));
78 | //check keys
79 | assert.match(rowToCheck, /actual=/);
80 | assert.match(rowToCheck, /expected=/);
81 | //check both key and value
82 | assert.match(rowToCheck, /actual='2'/);
83 | assert.match(rowToCheck, /expected='1'/);
84 | });
85 |
86 | it('Failing Test Finished is OK', function () {
87 | const rowToCheck = teamCityOutputArray[4];
88 | assert.match(rowToCheck, /##teamcity\[testFinished/);
89 | assert.match(rowToCheck, /name='Failing Test @fail'/);
90 | assert.match(rowToCheck, /flowId=/);
91 | assert.match(rowToCheck, /duration=/);
92 | assert.match(rowToCheck, /]/);
93 | });
94 |
95 | it('Skip Test Finished is ignored', function () {
96 | const rowToCheck = teamCityOutputArray[5];
97 | assert.isOk(/##teamcity\[testIgnored/.test(rowToCheck));
98 | assert.isOk(/name='Skipped Test @skip'/.test(rowToCheck));
99 | assert.isOk(/flowId=/.test(rowToCheck));
100 | assert.isOk(/message='Skipped Test @skip'/.test(rowToCheck));
101 | assert.isOk(/duration=/.test(rowToCheck) === false);
102 | assert.isOk(/]/.test(rowToCheck));
103 | });
104 |
105 | it('Skip Test Finished is OK', function () {
106 | const rowToCheck = teamCityOutputArray[6];
107 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
108 | assert.isOk(/name='Skipped Test @skip'/.test(rowToCheck));
109 | assert.isOk(/flowId=/.test(rowToCheck));
110 | assert.isNotOk(/duration=/.test(rowToCheck));
111 | assert.isOk(/]/.test(rowToCheck));
112 | });
113 |
114 | it('Suite Finished is OK', function () {
115 | const rowToCheck = teamCityOutputArray[7];
116 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
117 | assert.isOk(/name='Top Describe'/.test(rowToCheck));
118 | assert.isOk(/duration=/.test(rowToCheck));
119 | assert.isOk(/flowId=/.test(rowToCheck));
120 | assert.isOk(/]/.test(rowToCheck));
121 | });
122 |
123 | it('Suite Root Finished is OK', function () {
124 | const rowToCheck = teamCityOutputArray[7];
125 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
126 | assert.isNotOk(/name='mocha.suite'/.test(rowToCheck));
127 | assert.isOk(/duration=/.test(rowToCheck));
128 | assert.isOk(/flowId=/.test(rowToCheck));
129 | assert.isOk(/]/.test(rowToCheck));
130 | });
131 | }
132 |
133 | describe('specified as an env var', function () {
134 | before(function (done) {
135 | const opts = {
136 | env: Object.assign({
137 | ['ACTUAL_VS_EXPECTED']: 'true',
138 | ['USE_STD_ERROR']: 'true'
139 | }, process.env)
140 | };
141 |
142 | execFile(internalMochaPath, [
143 | 'test/test_data',
144 | '--reporter',
145 | 'lib/teamcity'
146 | ], opts, (err, stdout, stderr) => {
147 | teamCityStdout = stdout;
148 | teamCityStderr = stderr;
149 | teamCityOutputArray = stdout.split('\n');
150 | teamCityErrorOutputArray = stderr.split('\n');
151 | logMochaOutput(stdout, stderr);
152 | done();
153 | });
154 | });
155 | verifyResults();
156 | });
157 |
158 | describe('specified with --reporter-options', function () {
159 | before(function (done) {
160 | execFile(internalMochaPath, [
161 | path.join('test', 'test_data', 'simple.js'),
162 | '--reporter',
163 | 'lib/teamcity',
164 | '--reporter-options',
165 | 'actualVsExpected=true,useStdError=true'
166 | ], (err, stdout, stderr) => {
167 | teamCityStdout = stdout;
168 | teamCityStderr = stderr;
169 | teamCityOutputArray = stdout.split('\n');
170 | teamCityErrorOutputArray = stderr.split('\n');
171 | logMochaOutput(stdout, stderr);
172 | done();
173 | });
174 | });
175 | verifyResults();
176 | });
177 |
178 | });
179 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](http://badge.fury.io/js/mocha-teamcity-reporter)
2 | [/statusIcon.svg)](https://teamcity.jetbrains.com/viewType.html?buildTypeId=TeamCityThirdPartyPlugins_MochaTeamcityReporter_Build&branch_TeamCityThirdPartyPlugins_MochaTeamcityReporter=%3Cdefault%3E&tab=buildTypeStatusDiv)
3 | [](https://npmjs.org/package/mocha-teamcity-reporter)
4 |
5 | # mocha-teamcity-reporter #
6 |
7 | `mocha-teamcity-reporter` Teamcity reporter which makes it possible to display test results in real-time, makes test information
8 | available on the Tests tab of the Build Results page.
9 |
10 | ## Version 4.x changes
11 |
12 | * Breaking: Only supported on node.js 6 and above
13 | * Breaking: Only Mocha version 6 and above is now supported
14 | * Please remain on `mocha-teamcity-reporter@3` if this is an issue
15 | * New reporter option `ignoreHookWithName` to skip reporting for hooks with title containing some word (@DJ-Glock)
16 | * Added postfix _hook for flowId for hooks to ensure flowIds will never intersect.
17 | * Implement 'hook end' event (@DJ-GLock)
18 | * General maintenance and tidy up (@DJ-Glock)
19 |
20 | ## Mocha@6 notes
21 |
22 | * recordHookFailures option may not work as intended as mocha6 is now doing this itself
23 |
24 | ## Requirements
25 |
26 | * NodeJs 6+
27 | * Mocha 6+
28 | * Web Browser supporting ES5
29 |
30 | ## To Install
31 |
32 | In your project run a npm install command:
33 |
34 | ``` npm install mocha-teamcity-reporter --save-dev ```
35 |
36 | Basically, have your project's package.json be like:
37 |
38 | ``` js
39 | {
40 | "devDependencies": {
41 | "mocha-teamcity-reporter": ">=2.0.0"
42 | }
43 | }
44 | ```
45 |
46 | ## Usage
47 |
48 | describes using third party reporters in mocha.
49 |
50 | Then call mocha with:
51 |
52 | `mocha --reporter mocha-teamcity-reporter test`
53 |
54 | ## Running In Browser
55 |
56 | * Use `lib/teamcityBrowser`
57 | * Has option parsing stripped out for the moment
58 | * Example use can be found in `test\browser`
59 | * Custom log function can be set with window.customLogFunction
60 |
61 | ## Customisation
62 |
63 | ### TeamCity flowId
64 |
65 | Can set flowId like:
66 | `mocha test --reporter mocha-teamcity-reporter --reporter-options flowId=gobbledygook`
67 |
68 | ### Top-level suite name
69 |
70 | Can set a top-level suite name, which will wrap all other suites.
71 | This is useful for reading test output when running multiple suites in a single build
72 |
73 | * Environment variable: MOCHA_TEAMCITY_TOP_LEVEL_SUITE=
74 | * Reporter option: topLevelSuite=
75 |
76 | ### log test failures with std error
77 |
78 | To enable this please
79 | Please note this will probaly be made default in the next major version
80 |
81 | * Environment variable: USE_STD_ERROR=true
82 | * Reporter option: useStdError=true
83 |
84 | ### Record hook failures
85 |
86 | Record failures for hooks such as before/after etc
87 | Please note this will probably be made default in the next major version
88 |
89 | * Environment variable: RECORD_HOOK_FAILURES=true
90 | * Reporter option: recordHookFailures=true
91 |
92 | ### Display Ignored tests as ignored
93 |
94 | Display skip tests as ignored
95 |
96 | * Environment variable: DISPLAY_IGNORED_AS_IGNORED=true
97 | * Reporter option: displayIgnoredAsIgnored=true
98 |
99 |
100 | ### Ignore hooks with title contains some text
101 |
102 | This option should be used in pair with recordHookFailures. It allows you to skip reporting of hooks containing some word. Including root hooks.
103 |
104 | * Environment variable: IGNORE_HOOK_WITH_NAME=HookNoReporting
105 | * Reporter option: ignoreHookWithName=HookNoReporting
106 |
107 | Example:
108 | `mocha test --reporter mocha-teamcity-reporter --reporter-options recordHookFailures --reporter-options ignoreHookWithName=HookNoReporting`
109 |
110 | For root hooks defined the following way:
111 |
112 | ```
113 | exports.mochaHooks = () => {
114 | return {
115 | beforeEach: [
116 | function beforeEachRootHookNoReporting() {
117 | assert.strictEqual(1, 1);
118 | }
119 | ],
120 | afterEach: [
121 | function afterEachRoot() {
122 | assert.strictEqual(1, 1);
123 | },
124 | ]
125 | };
126 | };
127 | ```
128 |
129 | beforeEach hook beforeEachRootHookNoReporting() will not be reported as testStarted. But hook afterEachRoot() will be reported:
130 |
131 | ### Show diff between expected and actual values
132 |
133 | This will allow a hyperlink to appear to compare actual vs expected
134 | Please note this requires the error thrown in mocha to have the properties actual and expected. For example an assertionError has this
135 |
136 | * Environment variable: ACTUAL_VS_EXPECTED=true
137 | * Reporter option: actualVsExpected=true
138 |
139 | This will be shown in teamcity like this:
140 |
141 | ```
142 | AssertionError [ERR_ASSERTION]: 2 == 1
143 | at Context. (test/test_data/simple.js:11:11)
144 | ======= Failed test run #10 ==========
145 | Show diff between expected and actual values
146 | ```
147 |
148 | ### Setting options
149 |
150 | * Set with reporter-options:
151 |
152 | `mocha test --reporter mocha-teamcity-reporter --reporter-options topLevelSuite=top-level-suite-name`
153 | `mocha test --reporter mocha-teamcity-reporter --reporter-options useStdError=true`
154 | `mocha test --reporter mocha-teamcity-reporter --reporter-options useStdError=true`
155 |
156 | * Set with environment variable
157 |
158 | `MOCHA_TEAMCITY_TOP_LEVEL_SUITE='top-level-suite-name' mocha test --reporter mocha-teamcity-reporter`
159 |
160 | ### Multiple reporters
161 |
162 | This is not supported out of the box by this plugin but have a look at the following:
163 |
164 | * Using
165 | *
166 | * Or view for more details
167 |
168 | ## View on live Teamcity
169 |
170 | * Project can be viewed at
171 | [Pubic Teamcity at Jetbrains mocha reporter](https://teamcity.jetbrains.com/project.html?projectId=TeamCityThirdPartyPlugins_MochaTeamcityReporter)
172 | * Thanks to JetBrains for hosting
173 |
174 | ## Contributions
175 |
176 | * Always Welcome
177 | * Would prefer if customisation is added it is controlled via mocha options or environment variables
178 | * Only requirement is for code to pass linting and functional tests
179 |
180 | ## Run example test in project
181 |
182 | `mocha test/test_data/simple.js --reporter mocha-teamcity-reporter` or `npm run test-teamcity-example`
183 |
184 | ## Reference Information
185 |
186 |
187 |
--------------------------------------------------------------------------------
/test/functional/recordHookFailuresEnabled.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const {execFile} = require('child_process');
3 | const {assert} = require('chai');
4 | const { logMochaOutput, getMochaPath } = require('../testHelpers');
5 | const internalMochaPath = getMochaPath();
6 | const path = require('path');
7 |
8 | describe('Check TeamCity Output is correct with recordHookFailures option', function () {
9 | let teamCityStdout, teamCityStderr, teamCityOutputArray;
10 | function verifyResults() {
11 | it('1 stdout output should exist', function () {
12 | assert.isOk(teamCityStdout, 'has output');
13 | assert.isOk(teamCityOutputArray, 'array of output is populated');
14 | assert.lengthOf(teamCityOutputArray, 15);
15 | assert.isEmpty(teamCityOutputArray[14]);
16 | });
17 |
18 | it('2 stderr output should not exist', function () {
19 | assert.isEmpty(teamCityStderr);
20 | });
21 |
22 | it('3 testSuiteStarted for Suite1', function () {
23 | const rowToCheck = teamCityOutputArray[0];
24 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
25 | assert.isOk(/name='Hook Test Top Describe Fail'/.test(rowToCheck));
26 | assert.isOk(/flowId=/.test(rowToCheck));
27 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
28 | assert.isOk(/]/.test(rowToCheck));
29 | });
30 |
31 | it('4 testStarted for before all hook', function () {
32 | const rowToCheck = teamCityOutputArray[1];
33 | assert.match(rowToCheck, /##teamcity\[testStarted/);
34 | assert.match(rowToCheck, /name='"before all" hook/);
35 | assert.match(rowToCheck, /flowId=.*_hook/);
36 | assert.match(rowToCheck, /]/);
37 | });
38 |
39 | it('5 testFailed for before all hook', function () {
40 | const rowToCheck = teamCityOutputArray[2];
41 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
42 | assert.isOk(/name='"before all" hook/.test(rowToCheck));
43 | assert.isOk(/details='/.test(rowToCheck));
44 | assert.isOk(/Error: Before hook error fail/.test(rowToCheck));
45 | assert.isOk(/|n/.test(rowToCheck));
46 | assert.isOk(/|failingHook.js:29:12/.test(rowToCheck));
47 | assert.isOk(/captureStandardOutput='true'/.test(rowToCheck));
48 | assert.match(rowToCheck, /flowId=.*_hook/);
49 | assert.isOk(/duration=/.test(rowToCheck) === false);
50 | assert.isOk(/]/.test(rowToCheck));
51 | });
52 |
53 | it('6 Hook testFinished for before all hook', function () {
54 | const rowToCheck = teamCityOutputArray[3];
55 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
56 | assert.isOk(/name='"before all" hook/.test(rowToCheck));
57 | assert.match(rowToCheck, /flowId=.*_hook/);
58 | assert.isOk(/duration=/.test(rowToCheck));
59 | assert.isOk(/]/.test(rowToCheck));
60 | });
61 |
62 | it('7 testSuiteFinished for Suite1', function () {
63 | const rowToCheck = teamCityOutputArray[4];
64 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
65 | assert.isOk(/name='Hook Test Top Describe Fail'/.test(rowToCheck));
66 | assert.isOk(/duration=/.test(rowToCheck));
67 | assert.isOk(/flowId=/.test(rowToCheck));
68 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
69 | assert.isOk(/]/.test(rowToCheck));
70 | });
71 |
72 | it('8 testSuiteStarted for Suite2', function () {
73 | const rowToCheck = teamCityOutputArray[5];
74 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
75 | assert.isOk(/name='Hook Test Top Describe Pass'/.test(rowToCheck));
76 | assert.isOk(/flowId=/.test(rowToCheck));
77 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
78 | assert.isOk(/]/.test(rowToCheck));
79 | });
80 |
81 | it('9 testStarted for before all hook', function () {
82 | const rowToCheck = teamCityOutputArray[6];
83 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
84 | assert.isOk(/name='"before all" hook/.test(rowToCheck));
85 | assert.match(rowToCheck, /flowId=.*_hook/);
86 | assert.isOk(/]/.test(rowToCheck));
87 | });
88 |
89 | it('10 Hook testFinished for before all hook', function () {
90 | const rowToCheck = teamCityOutputArray[7];
91 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
92 | assert.isOk(/name='"before all" hook/.test(rowToCheck));
93 | assert.match(rowToCheck, /flowId=.*_hook/);
94 | assert.isOk(/duration=/.test(rowToCheck));
95 | assert.isOk(/]/.test(rowToCheck));
96 | });
97 |
98 | it('11 testStarted for Failing Test', function () {
99 | const rowToCheck = teamCityOutputArray[8];
100 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
101 | assert.isOk(/name='Test Failing Test @fail'/.test(rowToCheck));
102 | assert.isOk(/flowId=/.test(rowToCheck));
103 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
104 | assert.isOk(/]/.test(rowToCheck));
105 | });
106 |
107 | it('12 testFailed for Failing Test', function () {
108 | const rowToCheck = teamCityOutputArray[9];
109 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
110 | assert.isOk(/name='Test Failing Test @fail'/.test(rowToCheck));
111 | assert.isOk(/flowId=/.test(rowToCheck));
112 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
113 | assert.isOk(/duration=/.test(rowToCheck) === false);
114 | assert.isOk(/details='/.test(rowToCheck));
115 | assert.isOk(/AssertionError/.test(rowToCheck));
116 | assert.isOk(/|n/.test(rowToCheck));
117 | assert.isOk(/|failingHook.js:29:12/.test(rowToCheck));
118 | assert.isOk(/captureStandardOutput='true'/.test(rowToCheck));
119 | assert.isOk(/]/.test(rowToCheck));
120 | });
121 |
122 | it('13 testFinished for Failing Test', function () {
123 | const rowToCheck = teamCityOutputArray[10];
124 | assert.match(rowToCheck, /##teamcity\[testFinished/);
125 | assert.match(rowToCheck, /name='Test Failing Test @fail'/);
126 | assert.match(rowToCheck, /flowId=/);
127 | assert.match(rowToCheck, /duration=/);
128 | assert.match(rowToCheck, /]/);
129 | });
130 |
131 | it('14 testStarted for Passing Test', function () {
132 | const rowToCheck = teamCityOutputArray[11];
133 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
134 | assert.isOk(/name='Test Passing Test @pass'/.test(rowToCheck));
135 | assert.isOk(/flowId=/.test(rowToCheck));
136 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
137 | assert.isOk(/]/.test(rowToCheck));
138 | });
139 |
140 |
141 | it('15 testFinished for Passing Test', function () {
142 | const rowToCheck = teamCityOutputArray[12];
143 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
144 | assert.isOk(/name='Test Passing Test @pass'/.test(rowToCheck));
145 | assert.isOk(/flowId=/.test(rowToCheck));
146 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
147 | assert.isOk(/duration=/.test(rowToCheck));
148 | assert.isOk(/]/.test(rowToCheck));
149 | });
150 |
151 | it('16 testSuiteFinished for Suite2', function () {
152 | const rowToCheck = teamCityOutputArray[13];
153 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
154 | assert.isOk(/name='Hook Test Top Describe Pass'/.test(rowToCheck));
155 | assert.isOk(/duration=/.test(rowToCheck));
156 | assert.isOk(/flowId=/.test(rowToCheck));
157 | assert.notMatch(rowToCheck, /flowId=.*_hook/);
158 | assert.isOk(/]/.test(rowToCheck));
159 | });
160 | }
161 |
162 | describe('specified as an env var', function () {
163 | before(function (done) {
164 | const opts = {
165 | env: Object.assign({
166 | ['RECORD_HOOK_FAILURES']: 'true'
167 | }, process.env)
168 | };
169 |
170 | execFile(internalMochaPath, [
171 | 'test/example/failingHook.js',
172 | '--reporter',
173 | 'lib/teamcity'
174 | ], opts, (err, stdout, stderr) => {
175 | teamCityStdout = stdout;
176 | teamCityStderr = stderr;
177 | teamCityOutputArray = stdout.split('\n');
178 | logMochaOutput(stdout, stderr);
179 | done();
180 | });
181 | });
182 | verifyResults();
183 | });
184 |
185 | describe('specified with --reporter-options', function () {
186 | before(function (done) {
187 | execFile(internalMochaPath, [
188 | path.join('test', 'example', 'failingHook.js'),
189 | '--reporter',
190 | 'lib/teamcity',
191 | '--reporter-options',
192 | 'recordHookFailures=true'
193 | ], (err, stdout, stderr) => {
194 | teamCityStdout = stdout;
195 | teamCityStderr = stderr;
196 | teamCityOutputArray = stdout.split('\n');
197 | logMochaOutput(stdout, stderr);
198 | done();
199 | });
200 | });
201 | verifyResults();
202 | });
203 | });
204 |
--------------------------------------------------------------------------------
/test/excluded tests/ignoreHookWithNameEnabledRoot.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const {execFile} = require('child_process');
3 | const {assert} = require('chai');
4 | const { logMochaOutput, getMochaPath } = require('../testHelpers');
5 | const internalMochaPath = getMochaPath();
6 | const path = require('path');
7 |
8 | // Skipped because this suite should be run only for mocha 8 or higher
9 | describe.skip('Check TeamCity Output is correct with ignoreHookWithName and root hooks option', function () {
10 | let teamCityStdout, teamCityStderr, teamCityOutputArray;
11 | function verifyResults() {
12 | it('stdout output should exist', function () {
13 | assert.isOk(teamCityStdout, 'has output');
14 | assert.isOk(teamCityOutputArray, 'array of output is populated');
15 | assert.lengthOf(teamCityOutputArray, 16);
16 | assert.isEmpty(teamCityOutputArray[15]);
17 | });
18 |
19 | it('stderr output should not exist', function () {
20 | assert.isEmpty(teamCityStderr);
21 | });
22 |
23 |
24 | it('stdout output should exist', function () {
25 | assert.isOk(teamCityStdout);
26 | assert.isOk(teamCityOutputArray);
27 | assert.isOk(teamCityOutputArray.length >= 12);
28 | });
29 |
30 | it('Suite1 started is OK', function () {
31 | const rowToCheck = teamCityOutputArray[0];
32 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
33 | assert.isOk(/name='Hook Test Top Describe Fail'/.test(rowToCheck));
34 | assert.isOk(/flowId=/.test(rowToCheck));
35 | assert.isOk(/]/.test(rowToCheck));
36 | });
37 |
38 | it('Hook Test started is OK', function () {
39 | const rowToCheck = teamCityOutputArray[1];
40 | assert.match(rowToCheck, /##teamcity\[testStarted/);
41 | assert.match(rowToCheck, /name='"before all" hook/);
42 | assert.match(rowToCheck, /flowId=/);
43 | assert.match(rowToCheck, /]/);
44 | });
45 |
46 | it('Hook Test Failed is OK', function () {
47 | const rowToCheck = teamCityOutputArray[2];
48 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
49 | assert.isOk(/name='"before all" hook/.test(rowToCheck));
50 | assert.isOk(/details='/.test(rowToCheck));
51 | assert.isOk(/Error: Before hook error fail/.test(rowToCheck));
52 | assert.isOk(/|n/.test(rowToCheck));
53 | assert.isOk(/|failingHook.js:29:12/.test(rowToCheck));
54 | assert.isOk(/captureStandardOutput='true'/.test(rowToCheck));
55 | assert.isOk(/flowId=/.test(rowToCheck));
56 | assert.isOk(/duration=/.test(rowToCheck) === false);
57 | assert.isOk(/]/.test(rowToCheck));
58 | });
59 |
60 | it('Suite1 Finished is OK', function () {
61 | const rowToCheck = teamCityOutputArray[4];
62 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
63 | assert.isOk(/name='Hook Test Top Describe Fail'/.test(rowToCheck));
64 | assert.isOk(/duration=/.test(rowToCheck));
65 | assert.isOk(/flowId=/.test(rowToCheck));
66 | assert.isOk(/]/.test(rowToCheck));
67 | });
68 |
69 | it('Suite2 started is OK', function () {
70 | const rowToCheck = teamCityOutputArray[5];
71 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
72 | assert.isOk(/name='Hook Test Top Describe Pass'/.test(rowToCheck));
73 | assert.isOk(/flowId=/.test(rowToCheck));
74 | assert.isOk(/]/.test(rowToCheck));
75 | });
76 |
77 |
78 | it('Test started is OK', function () {
79 | const rowToCheck = teamCityOutputArray[11];
80 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
81 | assert.isOk(/name='Test Passing Test @pass'/.test(rowToCheck));
82 | assert.isOk(/flowId=/.test(rowToCheck));
83 | assert.isOk(/]/.test(rowToCheck));
84 | });
85 |
86 |
87 | it('Passing Test Finished is OK', function () {
88 | const rowToCheck = teamCityOutputArray[12];
89 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
90 | assert.isOk(/name='Test Passing Test @pass'/.test(rowToCheck));
91 | assert.isOk(/flowId=/.test(rowToCheck));
92 | assert.isOk(/duration=/.test(rowToCheck));
93 | assert.isOk(/]/.test(rowToCheck));
94 | });
95 |
96 | it('Test Failed is Failing', function () {
97 | const rowToCheck = teamCityOutputArray[8];
98 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
99 | assert.isOk(/name='Test Failing Test @fail'/.test(rowToCheck));
100 | assert.isOk(/flowId=/.test(rowToCheck));
101 | assert.isOk(/duration=/.test(rowToCheck) === false);
102 | assert.isOk(/details='/.test(rowToCheck));
103 | assert.isOk(/AssertionError/.test(rowToCheck));
104 | assert.isOk(/|n/.test(rowToCheck));
105 | assert.isOk(/|failingHook.js:29:12/.test(rowToCheck));
106 | assert.isOk(/captureStandardOutput='true'/.test(rowToCheck));
107 | assert.isOk(/]/.test(rowToCheck));
108 | });
109 |
110 | it('Failing Test Finished is OK', function () {
111 | const rowToCheck = teamCityOutputArray[9];
112 | assert.match(rowToCheck, /##teamcity\[testFinished/);
113 | assert.match(rowToCheck, /name='Test Failing Test @fail'/);
114 | assert.match(rowToCheck, /flowId=/);
115 | assert.match(rowToCheck, /duration=/);
116 | assert.match(rowToCheck, /]/);
117 | });
118 |
119 | it('Suite2 Finished is OK', function () {
120 | const rowToCheck = teamCityOutputArray[14];
121 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
122 | assert.isOk(/name='Hook Test Top Describe Pass'/.test(rowToCheck));
123 | assert.isOk(/duration=/.test(rowToCheck));
124 | assert.isOk(/flowId=/.test(rowToCheck));
125 | assert.isOk(/]/.test(rowToCheck));
126 | });
127 |
128 | it('Suite Root Finished is OK', function () {
129 | const rowToCheck = teamCityOutputArray[14];
130 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
131 | assert.isNotOk(/name='mocha.suite'/.test(rowToCheck));
132 | assert.isOk(/duration=/.test(rowToCheck));
133 | assert.isOk(/flowId=/.test(rowToCheck));
134 | assert.isOk(/]/.test(rowToCheck));
135 | });
136 |
137 | it('After hook failed test is OK', function () {
138 | const rowToCheck = teamCityOutputArray[3];
139 | assert.match(rowToCheck, /##teamcity\[testFailed/);
140 | assert.match(rowToCheck, /"after all" hook: afterHookNoReporting for/);
141 | assert.match(rowToCheck, /flowId=/);
142 | assert.match(rowToCheck, /]/);
143 | });
144 |
145 | it('After each root hook for failed test is OK', function () {
146 | const rowToCheck = teamCityOutputArray[10];
147 | assert.match(rowToCheck, /##teamcity\[testStarted/);
148 | assert.match(rowToCheck, /"after each" hook: afterEachRoot for "Test Failing Test/);
149 | assert.match(rowToCheck, /flowId=/);
150 | assert.match(rowToCheck, /]/);
151 | });
152 |
153 | it('After each root hook for passed test is OK', function () {
154 | const rowToCheck = teamCityOutputArray[13];
155 | assert.match(rowToCheck, /##teamcity\[testStarted/);
156 | assert.match(rowToCheck, /"after each" hook: afterEachRoot for "Test Passing Test/);
157 | assert.match(rowToCheck, /flowId=/);
158 | assert.match(rowToCheck, /]/);
159 | });
160 | }
161 |
162 | describe('specified as an env var', function () {
163 | before(function (done) {
164 | const opts = {
165 | env: Object.assign({
166 | ['RECORD_HOOK_FAILURES']: 'true',
167 | ['IGNORE_HOOK_WITH_NAME']: 'HookNoReporting'
168 | }, process.env)
169 | };
170 |
171 | execFile(internalMochaPath, [
172 | path.join('test', 'example', 'failingIgnoreHook.js'),
173 | '--reporter',
174 | 'lib/teamcity',
175 | `--require=${path.join('test', 'example', 'rootHooks.js')}`
176 | ], opts, (err, stdout, stderr) => {
177 | teamCityStdout = stdout;
178 | teamCityStderr = stderr;
179 | teamCityOutputArray = stdout.split('\n');
180 | logMochaOutput(stdout, stderr);
181 | done();
182 | });
183 | });
184 | verifyResults();
185 | });
186 |
187 | describe('specified with --reporter-options', function () {
188 | before(function (done) {
189 | execFile(internalMochaPath, [
190 | path.join('test', 'example', 'failingIgnoreHook.js'),
191 | '--reporter',
192 | 'lib/teamcity',
193 | '--reporter-options',
194 | 'recordHookFailures=true',
195 | '--reporter-options',
196 | 'ignoreHookWithName=HookNoReporting',
197 | `--require=${path.join('test', 'example', 'rootHooks.js')}`
198 | ], (err, stdout, stderr) => {
199 | teamCityStdout = stdout;
200 | teamCityStderr = stderr;
201 | teamCityOutputArray = stdout.split('\n');
202 | logMochaOutput(stdout, stderr);
203 | done();
204 | });
205 | });
206 | verifyResults();
207 | });
208 | });
209 |
--------------------------------------------------------------------------------
/test/functional/displayIgnoredAsIgnored.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const {execFile} = require('child_process');
3 | const {assert} = require('chai');
4 | const { logMochaOutput, getMochaPath } = require('../testHelpers');
5 | const internalMochaPath = getMochaPath();
6 | const path = require('path');
7 |
8 | describe('Check TeamCity Output is correct with displayIgnoredAsIgnored option', function () {
9 | let teamCityStdout, teamCityStderr, teamCityOutputArray;
10 | function verifyResults(displayIgnoredAsIgnored) {
11 | it('Output should exist', function () {
12 | assert.isOk(teamCityStdout);
13 | assert.isOk(teamCityOutputArray);
14 | assert.isOk(teamCityStderr.length === 0);
15 | assert.isOk(teamCityOutputArray.length >= 9);
16 |
17 | if (displayIgnoredAsIgnored) {
18 | assert.isOk(teamCityOutputArray.length === 9);
19 | } else {
20 | assert.isOk(teamCityOutputArray.length === 10);
21 | }
22 | });
23 |
24 | it('Suite started is OK', function () {
25 | const rowToCheck = teamCityOutputArray[0];
26 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
27 | assert.isOk(/name='Top Describe'/.test(rowToCheck));
28 | assert.isOk(/flowId=/.test(rowToCheck));
29 | assert.isOk(/]/.test(rowToCheck));
30 | });
31 |
32 | it('Test started is OK', function () {
33 | const rowToCheck = teamCityOutputArray[1];
34 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
35 | assert.isOk(/name='Passing Test @pass'/.test(rowToCheck));
36 | assert.isOk(/flowId=/.test(rowToCheck));
37 | assert.isOk(/]/.test(rowToCheck));
38 | });
39 |
40 | it('Passing Test Finished is OK', function () {
41 | const rowToCheck = teamCityOutputArray[2];
42 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
43 | assert.isOk(/name='Passing Test @pass'/.test(rowToCheck));
44 | assert.isOk(/flowId=/.test(rowToCheck));
45 | assert.isOk(/duration=/.test(rowToCheck));
46 | assert.isOk(/]/.test(rowToCheck));
47 | });
48 |
49 | it('Test Failed Started is OK', function () {
50 | const rowToCheck = teamCityOutputArray[3];
51 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
52 | assert.isOk(/name='Failing Test @fail'/.test(rowToCheck));
53 | assert.isOk(/flowId=/.test(rowToCheck));
54 | assert.isOk(/duration=/.test(rowToCheck) === false);
55 | assert.isOk(/]/.test(rowToCheck));
56 | });
57 |
58 | it('Test Failed is Failing', function () {
59 | const rowToCheck = teamCityOutputArray[4];
60 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
61 | assert.isOk(/name='Failing Test @fail'/.test(rowToCheck));
62 | assert.isOk(/flowId=/.test(rowToCheck));
63 | assert.isOk(/duration=/.test(rowToCheck) === false);
64 | assert.isOk(/details='/.test(rowToCheck));
65 | assert.isOk(/AssertionError/.test(rowToCheck));
66 | assert.isOk(/|n/.test(rowToCheck));
67 | assert.isOk(/|simple.js:11:11/.test(rowToCheck));
68 | assert.isOk(/captureStandardOutput='true'/.test(rowToCheck));
69 | assert.isOk(/]/.test(rowToCheck));
70 | });
71 |
72 | it('Failing Test Finished is OK', function () {
73 | const rowToCheck = teamCityOutputArray[5];
74 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
75 | assert.isOk(/name='Failing Test @fail'/.test(rowToCheck));
76 | assert.isOk(/flowId=/.test(rowToCheck));
77 | assert.isOk(/duration=/.test(rowToCheck));
78 | assert.isOk(/]/.test(rowToCheck));
79 | });
80 |
81 | it('Skip Test Finished is ignored', function () {
82 | const rowToCheck = teamCityOutputArray[6];
83 | const report = teamCityOutputArray.join('\n');
84 |
85 | assert.isOk(/##teamcity\[testIgnored/.test(rowToCheck));
86 | assert.isOk(/name='Skipped Test @skip'/.test(rowToCheck));
87 | assert.isOk(/flowId=/.test(rowToCheck));
88 | assert.isOk(/message='Skipped Test @skip'/.test(rowToCheck));
89 | assert.isOk(/duration=/.test(rowToCheck) === false);
90 | assert.isOk(/]/.test(rowToCheck));
91 |
92 | if (displayIgnoredAsIgnored) {
93 | assert.isOk(new RegExp("##teamcity\\[testIgnored name='Skipped Test @skip' message='Skipped Test @skip' flowId='\\d+']").test(report), 'testIgnored');
94 | assert.isNotOk(new RegExp("##teamcity\\[testFinished name='Skipped Test @skip'").test(report), 'testFinished');
95 | } else {
96 | assert.isOk(new RegExp("##teamcity\\[testIgnored name='Skipped Test @skip' message='Skipped Test @skip' flowId='\\d+']").test(report), 'testIgnored');
97 | assert.isOk(new RegExp("##teamcity\\[testFinished name='Skipped Test @skip'").test(report), 'testFinished');
98 | }
99 | });
100 |
101 | it('Skip Test Finished is OK', function () {
102 | const report = teamCityOutputArray.join('\n');
103 | if (displayIgnoredAsIgnored) {
104 | assert.isNotOk(/##teamcity\[testFinished name='Skipped Test @skip/.test(report));
105 | } else {
106 | assert.isOk(/##teamcity\[testFinished name='Skipped Test @skip/.test(report));
107 | }
108 | });
109 |
110 | it('Suite Finished is OK', function () {
111 | const rowToCheck = displayIgnoredAsIgnored ? teamCityOutputArray[7] : teamCityOutputArray[8];
112 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
113 | assert.isOk(/name='Top Describe'/.test(rowToCheck));
114 | assert.isOk(/duration=/.test(rowToCheck));
115 | assert.isOk(/flowId=/.test(rowToCheck));
116 | assert.isOk(/]/.test(rowToCheck));
117 | });
118 |
119 | it('Suite Root Finished is OK', function () {
120 | const rowToCheck = displayIgnoredAsIgnored ? teamCityOutputArray[7] : teamCityOutputArray[8];
121 | if (displayIgnoredAsIgnored) {
122 | assert.isEmpty(teamCityOutputArray[8], 'Last row should be empty');
123 | } else {
124 | assert.isEmpty(teamCityOutputArray[9], 'Last row should be empty');
125 | }
126 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
127 | assert.isNotOk(/name='mocha.suite'/.test(rowToCheck));
128 | assert.isOk(/duration=/.test(rowToCheck));
129 | assert.isOk(/flowId=/.test(rowToCheck));
130 | assert.isOk(/]/.test(rowToCheck));
131 | });
132 | }
133 |
134 | describe('specified as an env var', function () {
135 | before(function (done) {
136 | const opts = {
137 | env: Object.assign({
138 | ['DISPLAY_IGNORED_AS_IGNORED']: 'true'
139 | }, process.env)
140 | };
141 |
142 | execFile(internalMochaPath, [
143 | 'test/test_data',
144 | '--reporter',
145 | 'lib/teamcity'
146 | ], opts, (err, stdout, stderr) => {
147 | teamCityStdout = stdout;
148 | teamCityStderr = stderr;
149 | teamCityOutputArray = stdout.split('\n');
150 | logMochaOutput(stdout, stderr);
151 | done();
152 | });
153 | });
154 | verifyResults(true);
155 | });
156 |
157 | describe('specified with --reporter-options', function () {
158 | before(function (done) {
159 | execFile(internalMochaPath, [
160 | path.join('test', 'test_data', 'simple.js'),
161 | '--reporter',
162 | 'lib/teamcity',
163 | '--reporter-options',
164 | 'displayIgnoredAsIgnored=true'
165 | ], (err, stdout, stderr) => {
166 | teamCityStdout = stdout;
167 | teamCityStderr = stderr;
168 | teamCityOutputArray = stdout.split('\n');
169 | logMochaOutput(stdout, stderr);
170 | done();
171 | });
172 | });
173 | verifyResults(true);
174 | });
175 |
176 | describe('specified as an env var as false', function () {
177 | before(function (done) {
178 | const opts = {
179 | env: Object.assign({
180 | ['DISPLAY_IGNORED_AS_IGNORED']: 'false'
181 | }, process.env)
182 | };
183 |
184 | execFile(internalMochaPath, [
185 | 'test/test_data',
186 | '--reporter',
187 | 'lib/teamcity'
188 | ], opts, (err, stdout, stderr) => {
189 | teamCityStdout = stdout;
190 | teamCityStderr = stderr;
191 | teamCityOutputArray = stdout.split('\n');
192 | logMochaOutput(stdout, stderr);
193 | done();
194 | });
195 | });
196 | verifyResults(false);
197 | });
198 |
199 | describe('specified with --reporter-options as false', function () {
200 | before(function (done) {
201 | execFile(internalMochaPath, [
202 | path.join('test', 'test_data', 'simple.js'),
203 | '--reporter',
204 | 'lib/teamcity',
205 | '--reporter-options',
206 | 'displayIgnoredAsIgnored=false'
207 | ], (err, stdout, stderr) => {
208 | teamCityStdout = stdout;
209 | teamCityStderr = stderr;
210 | teamCityOutputArray = stdout.split('\n');
211 | logMochaOutput(stdout, stderr);
212 | done();
213 | });
214 | });
215 | verifyResults(false);
216 | });
217 |
218 | });
219 |
--------------------------------------------------------------------------------
/lib/teamcity.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable complexity */
2 | /**
3 | * Teamcity doc reference https://confluence.jetbrains.com/display/TCD10/Build+Script+Interaction+with+TeamCity
4 | *
5 | * Module dependencies.
6 | */
7 | 'use strict';
8 |
9 | const processPID = process.pid.toString();
10 | const TEST_IGNORED = `##teamcity[testIgnored name='%s' message='%s' flowId='%s']`;
11 | const SUITE_START = `##teamcity[testSuiteStarted name='%s' flowId='%s']`;
12 | const SUITE_END = `##teamcity[testSuiteFinished name='%s' duration='%s' flowId='%s']`;
13 | const SUITE_END_NO_DURATION = `##teamcity[testSuiteFinished name='%s' flowId='%s']`;
14 | const TEST_START = `##teamcity[testStarted name='%s' captureStandardOutput='true' flowId='%s']`;
15 | const TEST_FAILED = `##teamcity[testFailed name='%s' message='%s' details='%s' captureStandardOutput='true' flowId='%s']`;
16 | const TEST_FAILED_COMPARISON = `##teamcity[testFailed type='comparisonFailure' name='%s' message='%s' \
17 | details='%s' captureStandardOutput='true' actual='%s' expected='%s' flowId='%s']`;
18 | const TEST_END = `##teamcity[testFinished name='%s' duration='%s' flowId='%s']`;
19 | const TEST_END_NO_DURATION = `##teamcity[testFinished name='%s' flowId='%s']`;
20 |
21 | const Mocha = require('mocha');
22 | const {
23 | EVENT_SUITE_BEGIN,
24 | EVENT_TEST_BEGIN,
25 | EVENT_TEST_FAIL,
26 | EVENT_TEST_PENDING,
27 | EVENT_TEST_END,
28 | EVENT_HOOK_BEGIN,
29 | EVENT_HOOK_END,
30 | EVENT_SUITE_END,
31 | EVENT_RUN_END
32 | } = Mocha.Runner.constants;
33 |
34 | const util = require('util');
35 |
36 | let Base, log, logError;
37 |
38 | Base = require('mocha').reporters.Base;
39 | log = console.log;
40 | logError = console.error;
41 |
42 | /**
43 | * Escape the given `str`.
44 | */
45 |
46 | function escape(str) {
47 | if (!str) return '';
48 | return str
49 | .toString()
50 | .replace(/\x1B.*?m/g, '') // eslint-disable-line no-control-regex
51 | .replace(/\|/g, '||')
52 | .replace(/\n/g, '|n')
53 | .replace(/\r/g, '|r')
54 | .replace(/\[/g, '|[')
55 | .replace(/\]/g, '|]')
56 | .replace(/\u0085/g, '|x')
57 | .replace(/\u2028/g, '|l')
58 | .replace(/\u2029/g, '|p')
59 | .replace(/'/g, '|\'');
60 | }
61 |
62 | function isNil(value) {
63 | return value == null; // eslint-disable-line
64 | }
65 |
66 | function formatString() {
67 | let formattedArguments = [];
68 | const args = Array.prototype.slice.call(arguments, 0);
69 | // Format all arguments for TC display (it escapes using the pipe char).
70 | let tcMessage = args.shift();
71 | args.forEach((param) => {
72 | formattedArguments.push(escape(param));
73 | });
74 | formattedArguments.unshift(tcMessage);
75 | return util.format.apply(util, formattedArguments);
76 | }
77 |
78 |
79 | /**
80 | * Initialize a new `Teamcity` reporter.
81 | *
82 | * @param {Runner} runner
83 | * @param {options} options
84 | * @api public
85 | */
86 |
87 | function Teamcity(runner, options) {
88 | options = options || {};
89 | const reporterOptions = options.reporterOptions || {};
90 | let flowId, useStdError, recordHookFailures, actualVsExpected, ignoreHookWithName, displayIgnoredAsIgnored;
91 | (reporterOptions.flowId) ? flowId = reporterOptions.flowId : flowId = process.env['MOCHA_TEAMCITY_FLOWID'] || processPID;
92 | (reporterOptions.useStdError) ? useStdError = reporterOptions.useStdError : useStdError = process.env['USE_STD_ERROR'];
93 | (reporterOptions.recordHookFailures) ? recordHookFailures = reporterOptions.recordHookFailures : recordHookFailures = process.env['RECORD_HOOK_FAILURES'];
94 | (reporterOptions.actualVsExpected) ? actualVsExpected = reporterOptions.actualVsExpected : actualVsExpected = process.env['ACTUAL_VS_EXPECTED'];
95 | (reporterOptions.ignoreHookWithName) ? ignoreHookWithName = reporterOptions.ignoreHookWithName : ignoreHookWithName = process.env['IGNORE_HOOK_WITH_NAME'];
96 | (reporterOptions.displayIgnoredAsIgnored) ? displayIgnoredAsIgnored = reporterOptions.displayIgnoredAsIgnored : displayIgnoredAsIgnored = process.env['DISPLAY_IGNORED_AS_IGNORED'];
97 | (useStdError) ? useStdError = (useStdError.toLowerCase() === 'true') : useStdError = false;
98 | (recordHookFailures) ? recordHookFailures = (recordHookFailures.toLowerCase() === 'true') : recordHookFailures = false;
99 | (displayIgnoredAsIgnored) ? displayIgnoredAsIgnored = (displayIgnoredAsIgnored.toLowerCase() === 'true') : displayIgnoredAsIgnored = false;
100 | (ignoreHookWithName) ? ignoreHookWithName : null;
101 | actualVsExpected ? actualVsExpected = (actualVsExpected.toLowerCase() === 'true') : actualVsExpected = false;
102 | Base.call(this, runner);
103 | let stats = this.stats;
104 | const topLevelSuite = reporterOptions.topLevelSuite || process.env['MOCHA_TEAMCITY_TOP_LEVEL_SUITE'];
105 |
106 | const hookFlowId = `${flowId}_hook`;
107 | const ignoredTests = {};
108 | const testState = { pending: 0 };
109 |
110 | runner.on(EVENT_SUITE_BEGIN, function (suite) {
111 | if (suite.root) {
112 | if (topLevelSuite) {
113 | log(formatString(SUITE_START, topLevelSuite, flowId));
114 | }
115 | return;
116 | }
117 | suite.startDate = new Date();
118 | log(formatString(SUITE_START, suite.title, flowId));
119 | });
120 |
121 | runner.on(EVENT_TEST_BEGIN, function (test) {
122 | if (displayIgnoredAsIgnored && ignoredTests[`${test.title}-${flowId}`] === testState.pending) {
123 | return;
124 | }
125 | log(formatString(TEST_START, test.title, flowId));
126 | });
127 |
128 | runner.on(EVENT_TEST_FAIL, function (test, err) {
129 | let isHook = false;
130 | if (test.title.includes(`"before all" hook`) ||
131 | test.title.includes(`"before each" hook`) ||
132 | test.title.includes(`"after all" hook`) ||
133 | test.title.includes(`"after each" hook`)
134 | ) {
135 | isHook = true;
136 | }
137 |
138 | const testFlowId = (isHook) ? hookFlowId : flowId;
139 | if(actualVsExpected && (err.actual && err.expected)){
140 | if (useStdError) {
141 | logError(formatString(TEST_FAILED_COMPARISON, test.title, err.message, err.stack, err.actual, err.expected, testFlowId));
142 | } else {
143 | log(formatString(TEST_FAILED_COMPARISON, test.title, err.message, err.stack, err.actual, err.expected, testFlowId));
144 | }
145 | } else{
146 | if (useStdError) {
147 | logError(formatString(TEST_FAILED, test.title, err.message, err.stack, testFlowId));
148 | } else {
149 | log(formatString(TEST_FAILED, test.title, err.message, err.stack, testFlowId));
150 | }
151 | }
152 | // Log testFinished for failed hook (hook end event is not fired for failed hook)
153 | if (recordHookFailures && !ignoreHookWithName || recordHookFailures && ignoreHookWithName && !test.title.includes(ignoreHookWithName)) {
154 | if (isHook) {
155 | if(isNil(test.duration)){
156 | log(formatString(TEST_END_NO_DURATION, test.title, hookFlowId));
157 | } else {
158 | log(formatString(TEST_END, test.title, test.duration.toString(), hookFlowId));
159 | }
160 | }
161 | }
162 | });
163 |
164 | runner.on(EVENT_TEST_PENDING, function (test) {
165 | log(formatString(TEST_IGNORED, test.title, test.title, flowId));
166 | if (displayIgnoredAsIgnored) ignoredTests[`${test.title}-${flowId}`] = testState.pending;
167 | });
168 |
169 | runner.on(EVENT_TEST_END, function (test) {
170 | if (displayIgnoredAsIgnored && ignoredTests[`${test.title}-${flowId}`] === testState.pending) {
171 | delete ignoredTests[`${test.title}-${flowId}`];
172 | return;
173 | }
174 | if(isNil(test.duration)){
175 | log(formatString(TEST_END_NO_DURATION, test.title, flowId));
176 | } else {
177 | log(formatString(TEST_END, test.title, test.duration.toString(), flowId));
178 | }
179 | });
180 |
181 | runner.on(EVENT_HOOK_BEGIN, function (test) {
182 | if (recordHookFailures && !ignoreHookWithName || recordHookFailures && ignoreHookWithName && !test.title.includes(ignoreHookWithName)) {
183 | log(formatString(TEST_START, test.title, hookFlowId));
184 | }
185 | });
186 |
187 | runner.on(EVENT_HOOK_END, function (test) {
188 | if (recordHookFailures && !ignoreHookWithName || recordHookFailures && ignoreHookWithName && !test.title.includes(ignoreHookWithName)) {
189 | if(isNil(test.duration)){
190 | log(formatString(TEST_END_NO_DURATION, test.title, hookFlowId));
191 | } else {
192 | log(formatString(TEST_END, test.title, test.duration.toString(), hookFlowId));
193 | }
194 | }
195 | });
196 |
197 | runner.on(EVENT_SUITE_END, function (suite) {
198 | if (suite.root) return;
199 | log(formatString(SUITE_END, suite.title, new Date() - suite.startDate, flowId));
200 | });
201 |
202 | runner.on(EVENT_RUN_END, function () {
203 | let duration;
204 | (typeof stats === 'undefined') ? duration = null : duration = stats.duration;
205 | if (topLevelSuite) {
206 | isNil(duration) ? log(formatString(SUITE_END_NO_DURATION, topLevelSuite, flowId)) : log(formatString(SUITE_END, topLevelSuite, duration, flowId));
207 | }
208 | });
209 | }
210 |
211 |
212 | /**
213 | * Expose `Teamcity`.
214 | */
215 |
216 | exports = module.exports = Teamcity;
217 |
--------------------------------------------------------------------------------
/test/excluded tests/ignoreHookWithNameDisabledRoot.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const {execFile} = require('child_process');
3 | const {assert} = require('chai');
4 | const { logMochaOutput, getMochaPath } = require('../testHelpers');
5 | const internalMochaPath = getMochaPath();
6 | const path = require('path');
7 |
8 | // Skipped because this suite should be run only for mocha 8 or higher
9 | describe.skip('Check TeamCity Output is correct with recordHookFailures and root hooks but with no ignoreHookWithName option', function () {
10 | let teamCityStdout, teamCityStderr, teamCityOutputArray;
11 | function verifyResults() {
12 | it('stdout output should exist', function () {
13 | assert.isOk(teamCityStdout, 'has output');
14 | assert.isOk(teamCityOutputArray, 'array of output is populated');
15 | assert.lengthOf(teamCityOutputArray, 20);
16 | assert.isEmpty(teamCityOutputArray[19]);
17 | });
18 |
19 | it('stderr output should not exist', function () {
20 | assert.isEmpty(teamCityStderr);
21 | });
22 |
23 |
24 | it('stdout output should exist', function () {
25 | assert.isOk(teamCityStdout);
26 | assert.isOk(teamCityOutputArray);
27 | assert.isOk(teamCityOutputArray.length >= 12);
28 | });
29 |
30 | it('Suite1 started is OK', function () {
31 | const rowToCheck = teamCityOutputArray[0];
32 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
33 | assert.isOk(/name='Hook Test Top Describe Fail'/.test(rowToCheck));
34 | assert.isOk(/flowId=/.test(rowToCheck));
35 | assert.isOk(/]/.test(rowToCheck));
36 | });
37 |
38 | it('Hook Test started is OK', function () {
39 | const rowToCheck = teamCityOutputArray[1];
40 | assert.match(rowToCheck, /##teamcity\[testStarted/);
41 | assert.match(rowToCheck, /name='"before all" hook/);
42 | assert.match(rowToCheck, /flowId=/);
43 | assert.match(rowToCheck, /]/);
44 | });
45 |
46 | it('Hook Test Failed is OK', function () {
47 | const rowToCheck = teamCityOutputArray[2];
48 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
49 | assert.isOk(/name='"before all" hook/.test(rowToCheck));
50 | assert.isOk(/details='/.test(rowToCheck));
51 | assert.isOk(/Error: Before hook error fail/.test(rowToCheck));
52 | assert.isOk(/|n/.test(rowToCheck));
53 | assert.isOk(/|failingHook.js:29:12/.test(rowToCheck));
54 | assert.isOk(/captureStandardOutput='true'/.test(rowToCheck));
55 | assert.isOk(/flowId=/.test(rowToCheck));
56 | assert.isOk(/duration=/.test(rowToCheck) === false);
57 | assert.isOk(/]/.test(rowToCheck));
58 | });
59 |
60 | it('Suite1 Finished is OK', function () {
61 | const rowToCheck = teamCityOutputArray[5];
62 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
63 | assert.isOk(/name='Hook Test Top Describe Fail'/.test(rowToCheck));
64 | assert.isOk(/duration=/.test(rowToCheck));
65 | assert.isOk(/flowId=/.test(rowToCheck));
66 | assert.isOk(/]/.test(rowToCheck));
67 | });
68 |
69 | it('Suite2 started is OK', function () {
70 | const rowToCheck = teamCityOutputArray[6];
71 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
72 | assert.isOk(/name='Hook Test Top Describe Pass'/.test(rowToCheck));
73 | assert.isOk(/flowId=/.test(rowToCheck));
74 | assert.isOk(/]/.test(rowToCheck));
75 | });
76 |
77 |
78 | it('Test started is OK', function () {
79 | const rowToCheck = teamCityOutputArray[13];
80 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
81 | assert.isOk(/name='Test Passing Test @pass'/.test(rowToCheck));
82 | assert.isOk(/flowId=/.test(rowToCheck));
83 | assert.isOk(/]/.test(rowToCheck));
84 | });
85 |
86 |
87 | it('Passing Test Finished is OK', function () {
88 | const rowToCheck = teamCityOutputArray[15];
89 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
90 | assert.isOk(/name='Test Passing Test @pass'/.test(rowToCheck));
91 | assert.isOk(/flowId=/.test(rowToCheck));
92 | assert.isOk(/duration=/.test(rowToCheck));
93 | assert.isOk(/]/.test(rowToCheck));
94 | });
95 |
96 | it('Test Failed is Failing', function () {
97 | const rowToCheck = teamCityOutputArray[10];
98 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
99 | assert.isOk(/name='Test Failing Test @fail'/.test(rowToCheck));
100 | assert.isOk(/flowId=/.test(rowToCheck));
101 | assert.isOk(/duration=/.test(rowToCheck) === false);
102 | assert.isOk(/details='/.test(rowToCheck));
103 | assert.isOk(/AssertionError/.test(rowToCheck));
104 | assert.isOk(/|n/.test(rowToCheck));
105 | assert.isOk(/|failingHook.js:29:12/.test(rowToCheck));
106 | assert.isOk(/captureStandardOutput='true'/.test(rowToCheck));
107 | assert.isOk(/]/.test(rowToCheck));
108 | });
109 |
110 | it('Failing Test Finished is OK', function () {
111 | const rowToCheck = teamCityOutputArray[11];
112 | assert.match(rowToCheck, /##teamcity\[testFinished/);
113 | assert.match(rowToCheck, /name='Test Failing Test @fail'/);
114 | assert.match(rowToCheck, /flowId=/);
115 | assert.match(rowToCheck, /duration=/);
116 | assert.match(rowToCheck, /]/);
117 | });
118 |
119 | it('Suite2 Finished is OK', function () {
120 | const rowToCheck = teamCityOutputArray[18];
121 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
122 | assert.isOk(/name='Hook Test Top Describe Pass'/.test(rowToCheck));
123 | assert.isOk(/duration=/.test(rowToCheck));
124 | assert.isOk(/flowId=/.test(rowToCheck));
125 | assert.isOk(/]/.test(rowToCheck));
126 | });
127 |
128 | it('Suite Root Finished is OK', function () {
129 | const rowToCheck = teamCityOutputArray[18];
130 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
131 | assert.isNotOk(/name='mocha.suite'/.test(rowToCheck));
132 | assert.isOk(/duration=/.test(rowToCheck));
133 | assert.isOk(/flowId=/.test(rowToCheck));
134 | assert.isOk(/]/.test(rowToCheck));
135 | });
136 |
137 | it('After hook failed - started test is OK', function () {
138 | const rowToCheck = teamCityOutputArray[3];
139 | assert.match(rowToCheck, /##teamcity\[testStarted/);
140 | assert.match(rowToCheck, /"after all" hook: afterHookNoReporting for " Test Skipped Test/);
141 | assert.match(rowToCheck, /flowId=/);
142 | assert.match(rowToCheck, /]/);
143 | });
144 |
145 | it('After hook failed - failed test is OK', function () {
146 | const rowToCheck = teamCityOutputArray[4];
147 | assert.match(rowToCheck, /##teamcity\[testFailed/);
148 | assert.match(rowToCheck, /"after all" hook: afterHookNoReporting for " Test Skipped Test/);
149 | assert.match(rowToCheck, /flowId=/);
150 | assert.match(rowToCheck, /]/);
151 | });
152 |
153 | it('Before each root hook for failed test is OK', function () {
154 | const rowToCheck = teamCityOutputArray[9];
155 | assert.match(rowToCheck, /##teamcity\[testStarted/);
156 | assert.match(rowToCheck, /"before each" hook: beforeEachRootHookNoReporting for "Test Failing Test/);
157 | assert.match(rowToCheck, /flowId=/);
158 | assert.match(rowToCheck, /]/);
159 | });
160 |
161 | it('Before each root hook for passed test is OK', function () {
162 | const rowToCheck = teamCityOutputArray[14];
163 | assert.match(rowToCheck, /##teamcity\[testStarted/);
164 | assert.match(rowToCheck, /"before each" hook: beforeEachRootHookNoReporting for "Test Passing Test/);
165 | assert.match(rowToCheck, /flowId=/);
166 | assert.match(rowToCheck, /]/);
167 | });
168 |
169 | it('After each root hook for failed test is OK', function () {
170 | const rowToCheck = teamCityOutputArray[12];
171 | assert.match(rowToCheck, /##teamcity\[testStarted/);
172 | assert.match(rowToCheck, /"after each" hook: afterEachRoot for "Test Failing Test/);
173 | assert.match(rowToCheck, /flowId=/);
174 | assert.match(rowToCheck, /]/);
175 | });
176 |
177 | it('After each root hook for passed test is OK', function () {
178 | const rowToCheck = teamCityOutputArray[16];
179 | assert.match(rowToCheck, /##teamcity\[testStarted/);
180 | assert.match(rowToCheck, /"after each" hook: afterEachRoot for "Test Passing Test/);
181 | assert.match(rowToCheck, /flowId=/);
182 | assert.match(rowToCheck, /]/);
183 | });
184 |
185 | it('After hook started test is OK', function () {
186 | const rowToCheck = teamCityOutputArray[17];
187 | assert.match(rowToCheck, /##teamcity\[testStarted/);
188 | assert.match(rowToCheck, /"after all" hook: afterHookNoReporting for "Test Passing Test/);
189 | assert.match(rowToCheck, /flowId=/);
190 | assert.match(rowToCheck, /]/);
191 | });
192 | }
193 |
194 | describe('specified as an env var', function () {
195 | before(function (done) {
196 | const opts = {
197 | env: Object.assign({
198 | ['RECORD_HOOK_FAILURES']: 'true'
199 | }, process.env)
200 | };
201 |
202 | execFile(internalMochaPath, [
203 | path.join('test', 'example', 'failingIgnoreHook.js'),
204 | '--reporter',
205 | 'lib/teamcity',
206 | `--require=${path.join('test', 'example', 'rootHooks.js')}`
207 | ], opts, (err, stdout, stderr) => {
208 | teamCityStdout = stdout;
209 | teamCityStderr = stderr;
210 | teamCityOutputArray = stdout.split('\n');
211 | logMochaOutput(stdout, stderr);
212 | done();
213 | });
214 | });
215 | verifyResults();
216 | });
217 |
218 | describe('specified with --reporter-options', function () {
219 | before(function (done) {
220 | execFile(internalMochaPath, [
221 | path.join('test', 'example', 'failingIgnoreHook.js'),
222 | '--reporter',
223 | 'lib/teamcity',
224 | '--reporter-options',
225 | 'recordHookFailures=true',
226 | `--require=${path.join('test', 'example', 'rootHooks.js')}`
227 | ], (err, stdout, stderr) => {
228 | teamCityStdout = stdout;
229 | teamCityStderr = stderr;
230 | teamCityOutputArray = stdout.split('\n');
231 | logMochaOutput(stdout, stderr);
232 | done();
233 | });
234 | });
235 | verifyResults();
236 | });
237 | });
238 |
--------------------------------------------------------------------------------
/test/functional/ignoreHookWithNameEnabled.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const {execFile} = require('child_process');
3 | const {assert} = require('chai');
4 | const { logMochaOutput, getMochaPath } = require('../testHelpers');
5 | const internalMochaPath = getMochaPath();
6 | const path = require('path');
7 |
8 | describe('Check TeamCity Output is correct with ignoreHookWithName option', function () {
9 | let teamCityStdout, teamCityStderr, teamCityOutputArray;
10 | function verifyResults() {
11 | it('1 stdout output should exist', function () {
12 | assert.isOk(teamCityStdout, 'has output');
13 | assert.isOk(teamCityOutputArray, 'array of output is populated');
14 | assert.lengthOf(teamCityOutputArray, 22);
15 | assert.isEmpty(teamCityOutputArray[21]);
16 | });
17 |
18 | it('2 stderr output should not exist', function () {
19 | assert.isEmpty(teamCityStderr);
20 | });
21 |
22 | it('3 Suite1 testSuiteStarted', function () {
23 | const rowToCheck = teamCityOutputArray[0];
24 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
25 | assert.isOk(/name='Hook Test Top Describe Fail'/.test(rowToCheck));
26 | assert.isOk(/flowId=/.test(rowToCheck));
27 | assert.isOk(/]/.test(rowToCheck));
28 | });
29 |
30 | it('4 Before all testStarted', function () {
31 | const rowToCheck = teamCityOutputArray[1];
32 | assert.match(rowToCheck, /##teamcity\[testStarted/);
33 | assert.match(rowToCheck, /name='"before all" hook/);
34 | assert.match(rowToCheck, /flowId=/);
35 | assert.match(rowToCheck, /]/);
36 | });
37 |
38 | it('5 Before all testFinished', function () {
39 | const rowToCheck = teamCityOutputArray[2];
40 | assert.match(rowToCheck, /##teamcity\[testFinished/);
41 | assert.match(rowToCheck, /name='"before all" hook/);
42 | assert.match(rowToCheck, /flowId=/);
43 | assert.match(rowToCheck, /duration=/);
44 | assert.match(rowToCheck, /]/);
45 | });
46 |
47 | it('6 Passing test testStarted', function () {
48 | const rowToCheck = teamCityOutputArray[3];
49 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
50 | assert.isOk(/name='Test Passing Test @pass'/.test(rowToCheck));
51 | assert.isOk(/flowId=/.test(rowToCheck));
52 | assert.isOk(/]/.test(rowToCheck));
53 | });
54 |
55 | it('7 Before each hook testFailed', function () {
56 | const rowToCheck = teamCityOutputArray[4];
57 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
58 | assert.isOk(/"before each" hook: undefinedbeforeEachHookNoReporting for "Test Passing Test @pass"'/.test(rowToCheck));
59 | assert.isOk(/message='Before each hook error fail'/.test(rowToCheck));
60 | assert.isOk(/flowId=/.test(rowToCheck));
61 | assert.isOk(/]/.test(rowToCheck));
62 | });
63 |
64 | it('8 After each hook testStarted', function () {
65 | const rowToCheck = teamCityOutputArray[5];
66 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
67 | assert.isOk(/"after each" hook: undefinedafterEachHook/.test(rowToCheck));
68 | assert.isOk(/flowId=/.test(rowToCheck));
69 | assert.isOk(/]/.test(rowToCheck));
70 | });
71 |
72 | it('8 After each hook testFailed', function () {
73 | const rowToCheck = teamCityOutputArray[6];
74 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
75 | assert.isOk(/"after each" hook: undefinedafterEachHook for "Test Passing Test @pass"'/.test(rowToCheck));
76 | assert.isOk(/message='After each hook error fail'/.test(rowToCheck));
77 | assert.isOk(/flowId=/.test(rowToCheck));
78 | assert.isOk(/]/.test(rowToCheck));
79 | });
80 |
81 | it('10 After each hook testFinished', function () {
82 | const rowToCheck = teamCityOutputArray[7];
83 | assert.match(rowToCheck, /##teamcity\[testFinished/);
84 | assert.match(rowToCheck, /"after each" hook: undefinedafterEachHook/);
85 | assert.match(rowToCheck, /flowId=/);
86 | assert.match(rowToCheck, /duration=/);
87 | assert.match(rowToCheck, /]/);
88 | });
89 |
90 | it('11 After hook testFailed', function () {
91 | const rowToCheck = teamCityOutputArray[8];
92 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
93 | assert.isOk(/"after all" hook: afterHookNoReporting for "Test Passing Test @pass"/.test(rowToCheck));
94 | assert.isOk(/message='After hook error fail'/.test(rowToCheck));
95 | assert.isOk(/flowId=/.test(rowToCheck));
96 | assert.isOk(/]/.test(rowToCheck));
97 | });
98 |
99 | it('12 Suite1 testSuiteFinished', function () {
100 | const rowToCheck = teamCityOutputArray[9];
101 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
102 | assert.isOk(/name='Hook Test Top Describe Fail'/.test(rowToCheck));
103 | assert.isOk(/duration=/.test(rowToCheck));
104 | assert.isOk(/flowId=/.test(rowToCheck));
105 | assert.isOk(/]/.test(rowToCheck));
106 | });
107 |
108 | it('13 Suite2 testSuiteStarted', function () {
109 | const rowToCheck = teamCityOutputArray[10];
110 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
111 | assert.isOk(/name='Hook Test Top Describe Pass'/.test(rowToCheck));
112 | assert.isOk(/flowId=/.test(rowToCheck));
113 | assert.isOk(/]/.test(rowToCheck));
114 | });
115 |
116 | it('14 Before hook testStarted', function () {
117 | const rowToCheck = teamCityOutputArray[11];
118 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
119 | assert.isOk(/name='"before all" hook/.test(rowToCheck));
120 | assert.isOk(/flowId=/.test(rowToCheck));
121 | assert.isOk(/]/.test(rowToCheck));
122 | });
123 |
124 | it('15 Before hook testFinished', function () {
125 | const rowToCheck = teamCityOutputArray[12];
126 | assert.match(rowToCheck, /##teamcity\[testFinished/);
127 | assert.match(rowToCheck, /name='"before all" hook/);
128 | assert.match(rowToCheck, /flowId=/);
129 | assert.match(rowToCheck, /duration=/);
130 | assert.match(rowToCheck, /]/);
131 | });
132 |
133 | it('16 Failing test testStarted', function () {
134 | const rowToCheck = teamCityOutputArray[13];
135 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
136 | assert.isOk(/name='Test Failing Test @fail'/.test(rowToCheck));
137 | assert.isOk(/flowId=/.test(rowToCheck));
138 | assert.isOk(/]/.test(rowToCheck));
139 | });
140 |
141 | it('17 Failing test testFailed', function () {
142 | const rowToCheck = teamCityOutputArray[14];
143 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
144 | assert.isOk(/name='Test Failing Test @fail'/.test(rowToCheck));
145 | assert.isOk(/flowId=/.test(rowToCheck));
146 | assert.isOk(/duration=/.test(rowToCheck) === false);
147 | assert.isOk(/details='/.test(rowToCheck));
148 | assert.isOk(/AssertionError/.test(rowToCheck));
149 | assert.isOk(/|n/.test(rowToCheck));
150 | assert.isOk(/|failingHook.js:29:12/.test(rowToCheck));
151 | assert.isOk(/captureStandardOutput='true'/.test(rowToCheck));
152 | assert.isOk(/]/.test(rowToCheck));
153 | });
154 |
155 | it('18 Failing Test testFinished', function () {
156 | const rowToCheck = teamCityOutputArray[15];
157 | assert.match(rowToCheck, /##teamcity\[testFinished/);
158 | assert.match(rowToCheck, /name='Test Failing Test @fail'/);
159 | assert.match(rowToCheck, /flowId=/);
160 | assert.match(rowToCheck, /duration=/);
161 | assert.match(rowToCheck, /]/);
162 | });
163 |
164 | it('19 Passing test testStarted', function () {
165 | const rowToCheck = teamCityOutputArray[16];
166 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
167 | assert.isOk(/name='Test Passing Test @pass'/.test(rowToCheck));
168 | assert.isOk(/flowId=/.test(rowToCheck));
169 | assert.isOk(/]/.test(rowToCheck));
170 | });
171 |
172 | it('20 Passing test testFinished', function () {
173 | const rowToCheck = teamCityOutputArray[17];
174 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
175 | assert.isOk(/name='Test Passing Test @pass'/.test(rowToCheck));
176 | assert.isOk(/duration=/.test(rowToCheck));
177 | assert.isOk(/flowId=/.test(rowToCheck));
178 | assert.isOk(/]/.test(rowToCheck));
179 | });
180 |
181 | it('21 After hook testStarted', function () {
182 | const rowToCheck = teamCityOutputArray[18];
183 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
184 | assert.isOk(/name='"after all" hook: afterHook/.test(rowToCheck));
185 | assert.isOk(/flowId=/.test(rowToCheck));
186 | assert.isOk(/]/.test(rowToCheck));
187 | });
188 |
189 | it('22 After hook testFinished', function () {
190 | const rowToCheck = teamCityOutputArray[19];
191 | assert.match(rowToCheck, /##teamcity\[testFinished/);
192 | assert.match(rowToCheck, /name='"after all" hook: afterHook/);
193 | assert.match(rowToCheck, /flowId=/);
194 | assert.match(rowToCheck, /duration=/);
195 | assert.match(rowToCheck, /]/);
196 | });
197 |
198 | it('19 Suite2 Finished is OK', function () {
199 | const rowToCheck = teamCityOutputArray[20];
200 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
201 | assert.isOk(/name='Hook Test Top Describe Pass'/.test(rowToCheck));
202 | assert.isOk(/duration=/.test(rowToCheck));
203 | assert.isOk(/flowId=/.test(rowToCheck));
204 | assert.isOk(/]/.test(rowToCheck));
205 | });
206 | }
207 |
208 | describe('specified as an env var', function () {
209 | before(function (done) {
210 | const opts = {
211 | env: Object.assign({
212 | ['RECORD_HOOK_FAILURES']: 'true',
213 | ['IGNORE_HOOK_WITH_NAME']: 'HookNoReporting'
214 | }, process.env)
215 | };
216 |
217 | execFile(internalMochaPath, [
218 | path.join('test', 'example', 'failingIgnoreHookNoRoot.js'),
219 | '--reporter',
220 | 'lib/teamcity'
221 | ], opts, (err, stdout, stderr) => {
222 | teamCityStdout = stdout;
223 | teamCityStderr = stderr;
224 | teamCityOutputArray = stdout.split('\n');
225 | logMochaOutput(stdout, stderr);
226 | done();
227 | });
228 | });
229 | verifyResults();
230 | });
231 |
232 | describe('specified with --reporter-options', function () {
233 | before(function (done) {
234 | execFile(internalMochaPath, [
235 | path.join('test', 'example', 'failingIgnoreHookNoRoot.js'),
236 | '--reporter',
237 | 'lib/teamcity',
238 | '--reporter-options',
239 | 'recordHookFailures=true',
240 | '--reporter-options',
241 | 'ignoreHookWithName=HookNoReporting'
242 | ], (err, stdout, stderr) => {
243 | teamCityStdout = stdout;
244 | teamCityStderr = stderr;
245 | teamCityOutputArray = stdout.split('\n');
246 | logMochaOutput(stdout, stderr);
247 | done();
248 | });
249 | });
250 | verifyResults();
251 | });
252 | });
253 |
--------------------------------------------------------------------------------
/test/functional/ignoreHookWithNameDisabled.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const {execFile} = require('child_process');
3 | const {assert} = require('chai');
4 | const { logMochaOutput, getMochaPath } = require('../testHelpers');
5 | const internalMochaPath = getMochaPath();
6 | const path = require('path');
7 |
8 | describe('Check TeamCity Output is correct with recordHookFailures but with no ignoreHookWithName option', function () {
9 | let teamCityStdout, teamCityStderr, teamCityOutputArray;
10 | function verifyResults() {
11 | it('1 stdout output should exist', function () {
12 | assert.isOk(teamCityStdout, 'has output');
13 | assert.isOk(teamCityOutputArray, 'array of output is populated');
14 | assert.lengthOf(teamCityOutputArray, 34);
15 | assert.isEmpty(teamCityOutputArray[33]);
16 | });
17 |
18 | it('2 stderr output should not exist', function () {
19 | assert.isEmpty(teamCityStderr);
20 | });
21 |
22 | it('3 Suite1 testSuiteStarted', function () {
23 | const rowToCheck = teamCityOutputArray[0];
24 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
25 | assert.isOk(/name='Hook Test Top Describe Fail'/.test(rowToCheck));
26 | assert.isOk(/flowId=/.test(rowToCheck));
27 | assert.isOk(/]/.test(rowToCheck));
28 | });
29 |
30 | it('4 Before all testStarted', function () {
31 | const rowToCheck = teamCityOutputArray[1];
32 | assert.match(rowToCheck, /##teamcity\[testStarted/);
33 | assert.match(rowToCheck, /name='"before all" hook/);
34 | assert.match(rowToCheck, /flowId=/);
35 | assert.match(rowToCheck, /]/);
36 | });
37 |
38 | it('5 Before all testFinished', function () {
39 | const rowToCheck = teamCityOutputArray[2];
40 | assert.match(rowToCheck, /##teamcity\[testFinished/);
41 | assert.match(rowToCheck, /name='"before all" hook/);
42 | assert.match(rowToCheck, /flowId=/);
43 | assert.match(rowToCheck, /duration=/);
44 | assert.match(rowToCheck, /]/);
45 | });
46 |
47 | it('6 Passing test testStarted', function () {
48 | const rowToCheck = teamCityOutputArray[3];
49 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
50 | assert.isOk(/name='Test Passing Test @pass'/.test(rowToCheck));
51 | assert.isOk(/flowId=/.test(rowToCheck));
52 | assert.isOk(/]/.test(rowToCheck));
53 | });
54 |
55 | it('7 Before each hook testStarted', function () {
56 | const rowToCheck = teamCityOutputArray[4];
57 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
58 | assert.isOk(/name='"before each" hook: undefinedbeforeEachHookNoReporting/.test(rowToCheck));
59 | assert.isOk(/flowId=/.test(rowToCheck));
60 | assert.isOk(/]/.test(rowToCheck));
61 | });
62 |
63 | it('8 Before each hook testFailed', function () {
64 | const rowToCheck = teamCityOutputArray[5];
65 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
66 | assert.isOk(/"before each" hook: undefinedbeforeEachHookNoReporting/.test(rowToCheck));
67 | assert.isOk(/message='Before each hook error fail'/.test(rowToCheck));
68 | assert.isOk(/flowId=/.test(rowToCheck));
69 | assert.isOk(/]/.test(rowToCheck));
70 | });
71 |
72 | it('9 Before all testFinished', function () {
73 | const rowToCheck = teamCityOutputArray[6];
74 | assert.match(rowToCheck, /##teamcity\[testFinished/);
75 | assert.match(rowToCheck, /"before each" hook: undefinedbeforeEachHookNoReporting/);
76 | assert.match(rowToCheck, /flowId=/);
77 | assert.match(rowToCheck, /duration=/);
78 | assert.match(rowToCheck, /]/);
79 | });
80 |
81 | it('8 After each hook testStarted', function () {
82 | const rowToCheck = teamCityOutputArray[7];
83 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
84 | assert.isOk(/"after each" hook: undefinedafterEachHook/.test(rowToCheck));
85 | assert.isOk(/flowId=/.test(rowToCheck));
86 | assert.isOk(/]/.test(rowToCheck));
87 | });
88 |
89 | it('9 After each hook testFailed', function () {
90 | const rowToCheck = teamCityOutputArray[8];
91 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
92 | assert.isOk(/"after each" hook: undefinedafterEachHook for "Test Passing Test @pass"'/.test(rowToCheck));
93 | assert.isOk(/message='After each hook error fail'/.test(rowToCheck));
94 | assert.isOk(/flowId=/.test(rowToCheck));
95 | assert.isOk(/]/.test(rowToCheck));
96 | });
97 |
98 | it('10 After each hook testFinished', function () {
99 | const rowToCheck = teamCityOutputArray[9];
100 | assert.match(rowToCheck, /##teamcity\[testFinished/);
101 | assert.match(rowToCheck, /"after each" hook: undefinedafterEachHook/);
102 | assert.match(rowToCheck, /flowId=/);
103 | assert.match(rowToCheck, /duration=/);
104 | assert.match(rowToCheck, /]/);
105 | });
106 |
107 | it('11 After hook testStarted', function () {
108 | const rowToCheck = teamCityOutputArray[10];
109 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
110 | assert.isOk(/name='"after all" hook/.test(rowToCheck));
111 | assert.isOk(/flowId=/.test(rowToCheck));
112 | assert.isOk(/]/.test(rowToCheck));
113 | });
114 |
115 | it('12 After hook testFailed', function () {
116 | const rowToCheck = teamCityOutputArray[11];
117 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
118 | assert.isOk(/"after all" hook: afterHookNoReporting for "Test Passing Test @pass"/.test(rowToCheck));
119 | assert.isOk(/message='After hook error fail'/.test(rowToCheck));
120 | assert.isOk(/flowId=/.test(rowToCheck));
121 | assert.isOk(/]/.test(rowToCheck));
122 | });
123 |
124 | it('13 After hook testFinished', function () {
125 | const rowToCheck = teamCityOutputArray[12];
126 | assert.match(rowToCheck, /##teamcity\[testFinished/);
127 | assert.match(rowToCheck, /"after all" hook: afterHookNoReporting/);
128 | assert.match(rowToCheck, /flowId=/);
129 | assert.match(rowToCheck, /duration=/);
130 | assert.match(rowToCheck, /]/);
131 | });
132 |
133 | it('14 Suite1 testSuiteFinished', function () {
134 | const rowToCheck = teamCityOutputArray[13];
135 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
136 | assert.isOk(/name='Hook Test Top Describe Fail'/.test(rowToCheck));
137 | assert.isOk(/duration=/.test(rowToCheck));
138 | assert.isOk(/flowId=/.test(rowToCheck));
139 | assert.isOk(/]/.test(rowToCheck));
140 | });
141 |
142 | it('15 Suite2 testSuiteStarted', function () {
143 | const rowToCheck = teamCityOutputArray[14];
144 | assert.isOk(/##teamcity\[testSuiteStarted/.test(rowToCheck));
145 | assert.isOk(/name='Hook Test Top Describe Pass'/.test(rowToCheck));
146 | assert.isOk(/flowId=/.test(rowToCheck));
147 | assert.isOk(/]/.test(rowToCheck));
148 | });
149 |
150 | it('16 Before hook testStarted', function () {
151 | const rowToCheck = teamCityOutputArray[15];
152 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
153 | assert.isOk(/name='"before all" hook/.test(rowToCheck));
154 | assert.isOk(/flowId=/.test(rowToCheck));
155 | assert.isOk(/]/.test(rowToCheck));
156 | });
157 |
158 | it('17 Before hook testFinished', function () {
159 | const rowToCheck = teamCityOutputArray[16];
160 | assert.match(rowToCheck, /##teamcity\[testFinished/);
161 | assert.match(rowToCheck, /name='"before all" hook/);
162 | assert.match(rowToCheck, /flowId=/);
163 | assert.match(rowToCheck, /duration=/);
164 | assert.match(rowToCheck, /]/);
165 | });
166 |
167 | it('18 Failing test testStarted', function () {
168 | const rowToCheck = teamCityOutputArray[17];
169 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
170 | assert.isOk(/name='Test Failing Test @fail'/.test(rowToCheck));
171 | assert.isOk(/flowId=/.test(rowToCheck));
172 | assert.isOk(/]/.test(rowToCheck));
173 | });
174 |
175 | it('19 Before each hook testStarted', function () {
176 | const rowToCheck = teamCityOutputArray[18];
177 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
178 | assert.isOk(/name='"before each" hook: beforeEachHookNoReporting/.test(rowToCheck));
179 | assert.isOk(/flowId=/.test(rowToCheck));
180 | assert.isOk(/]/.test(rowToCheck));
181 | });
182 |
183 | it('20 Before each hook testFinished', function () {
184 | const rowToCheck = teamCityOutputArray[19];
185 | assert.match(rowToCheck, /##teamcity\[testFinished/);
186 | assert.match(rowToCheck, /name='"before each" hook: beforeEachHookNoReporting/);
187 | assert.match(rowToCheck, /flowId=/);
188 | assert.match(rowToCheck, /duration=/);
189 | assert.match(rowToCheck, /]/);
190 | });
191 |
192 | it('21 Failing test testFailed', function () {
193 | const rowToCheck = teamCityOutputArray[20];
194 | assert.isOk(/##teamcity\[testFailed/.test(rowToCheck));
195 | assert.isOk(/name='Test Failing Test @fail'/.test(rowToCheck));
196 | assert.isOk(/flowId=/.test(rowToCheck));
197 | assert.isOk(/duration=/.test(rowToCheck) === false);
198 | assert.isOk(/details='/.test(rowToCheck));
199 | assert.isOk(/AssertionError/.test(rowToCheck));
200 | assert.isOk(/|n/.test(rowToCheck));
201 | assert.isOk(/|failingHook.js:29:12/.test(rowToCheck));
202 | assert.isOk(/captureStandardOutput='true'/.test(rowToCheck));
203 | assert.isOk(/]/.test(rowToCheck));
204 | });
205 |
206 | it('22 Failing Test testFinished', function () {
207 | const rowToCheck = teamCityOutputArray[21];
208 | assert.match(rowToCheck, /##teamcity\[testFinished/);
209 | assert.match(rowToCheck, /name='Test Failing Test @fail'/);
210 | assert.match(rowToCheck, /flowId=/);
211 | assert.match(rowToCheck, /duration=/);
212 | assert.match(rowToCheck, /]/);
213 | });
214 |
215 | it('23 After each hook testStarted', function () {
216 | const rowToCheck = teamCityOutputArray[22];
217 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
218 | assert.isOk(/name='"after each" hook: afterEachHookNoReporting/.test(rowToCheck));
219 | assert.isOk(/flowId=/.test(rowToCheck));
220 | assert.isOk(/]/.test(rowToCheck));
221 | });
222 |
223 | it('24 After each hook testFinished', function () {
224 | const rowToCheck = teamCityOutputArray[23];
225 | assert.match(rowToCheck, /##teamcity\[testFinished/);
226 | assert.match(rowToCheck, /name='"after each" hook: afterEachHookNoReporting/);
227 | assert.match(rowToCheck, /flowId=/);
228 | assert.match(rowToCheck, /duration=/);
229 | assert.match(rowToCheck, /]/);
230 | });
231 |
232 | it('25 Passing test testStarted', function () {
233 | const rowToCheck = teamCityOutputArray[24];
234 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
235 | assert.isOk(/name='Test Passing Test @pass'/.test(rowToCheck));
236 | assert.isOk(/flowId=/.test(rowToCheck));
237 | assert.isOk(/]/.test(rowToCheck));
238 | });
239 |
240 | it('26 Before each hook testStarted', function () {
241 | const rowToCheck = teamCityOutputArray[25];
242 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
243 | assert.isOk(/name='"before each" hook: beforeEachHookNoReporting/.test(rowToCheck));
244 | assert.isOk(/flowId=/.test(rowToCheck));
245 | assert.isOk(/]/.test(rowToCheck));
246 | });
247 |
248 | it('27 Before each hook testFinished', function () {
249 | const rowToCheck = teamCityOutputArray[26];
250 | assert.match(rowToCheck, /##teamcity\[testFinished/);
251 | assert.match(rowToCheck, /"before each" hook: beforeEachHookNoReporting/);
252 | assert.match(rowToCheck, /flowId=/);
253 | assert.match(rowToCheck, /duration=/);
254 | assert.match(rowToCheck, /]/);
255 | });
256 |
257 | it('28 Passing test testFinished', function () {
258 | const rowToCheck = teamCityOutputArray[27];
259 | assert.isOk(/##teamcity\[testFinished/.test(rowToCheck));
260 | assert.isOk(/name='Test Passing Test @pass'/.test(rowToCheck));
261 | assert.isOk(/duration=/.test(rowToCheck));
262 | assert.isOk(/flowId=/.test(rowToCheck));
263 | assert.isOk(/]/.test(rowToCheck));
264 | });
265 |
266 | it('29 After each hook testStarted', function () {
267 | const rowToCheck = teamCityOutputArray[28];
268 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
269 | assert.isOk(/name='"after each" hook: afterEachHookNoReporting/.test(rowToCheck));
270 | assert.isOk(/flowId=/.test(rowToCheck));
271 | assert.isOk(/]/.test(rowToCheck));
272 | });
273 |
274 | it('30 After each hook testFinished', function () {
275 | const rowToCheck = teamCityOutputArray[29];
276 | assert.match(rowToCheck, /##teamcity\[testFinished/);
277 | assert.match(rowToCheck, /name='"after each" hook: afterEachHookNoReporting/);
278 | assert.match(rowToCheck, /flowId=/);
279 | assert.match(rowToCheck, /duration=/);
280 | assert.match(rowToCheck, /]/);
281 | });
282 |
283 | it('31 After hook testStarted', function () {
284 | const rowToCheck = teamCityOutputArray[30];
285 | assert.isOk(/##teamcity\[testStarted/.test(rowToCheck));
286 | assert.isOk(/name='"after all" hook: afterHook/.test(rowToCheck));
287 | assert.isOk(/flowId=/.test(rowToCheck));
288 | assert.isOk(/]/.test(rowToCheck));
289 | });
290 |
291 | it('32 After hook testFinished', function () {
292 | const rowToCheck = teamCityOutputArray[31];
293 | assert.match(rowToCheck, /##teamcity\[testFinished/);
294 | assert.match(rowToCheck, /name='"after all" hook: afterHook/);
295 | assert.match(rowToCheck, /flowId=/);
296 | assert.match(rowToCheck, /duration=/);
297 | assert.match(rowToCheck, /]/);
298 | });
299 |
300 | it('33 Suite2 Finished', function () {
301 | const rowToCheck = teamCityOutputArray[32];
302 | assert.isOk(/##teamcity\[testSuiteFinished/.test(rowToCheck));
303 | assert.isOk(/name='Hook Test Top Describe Pass'/.test(rowToCheck));
304 | assert.isOk(/duration=/.test(rowToCheck));
305 | assert.isOk(/flowId=/.test(rowToCheck));
306 | assert.isOk(/]/.test(rowToCheck));
307 | });
308 | }
309 |
310 | describe('specified as an env var', function () {
311 | before(function (done) {
312 | const opts = {
313 | env: Object.assign({
314 | ['RECORD_HOOK_FAILURES']: 'true'
315 | }, process.env)
316 | };
317 |
318 | execFile(internalMochaPath, [
319 | path.join('test', 'example', 'failingIgnoreHookNoRoot.js'),
320 | '--reporter',
321 | 'lib/teamcity'
322 | ], opts, (err, stdout, stderr) => {
323 | teamCityStdout = stdout;
324 | teamCityStderr = stderr;
325 | teamCityOutputArray = stdout.split('\n');
326 | logMochaOutput(stdout, stderr);
327 | done();
328 | });
329 | });
330 | verifyResults();
331 | });
332 |
333 | describe('specified with --reporter-options', function () {
334 | before(function (done) {
335 | execFile(internalMochaPath, [
336 | path.join('test', 'example', 'failingIgnoreHookNoRoot.js'),
337 | '--reporter',
338 | 'lib/teamcity',
339 | '--reporter-options',
340 | 'recordHookFailures=true'
341 | ], (err, stdout, stderr) => {
342 | teamCityStdout = stdout;
343 | teamCityStderr = stderr;
344 | teamCityOutputArray = stdout.split('\n');
345 | logMochaOutput(stdout, stderr);
346 | done();
347 | });
348 | });
349 | verifyResults();
350 | });
351 | });
352 |
--------------------------------------------------------------------------------