Skip to content

Commit 973bcf2

Browse files
ortamacklinu
authored andcommitted
feat: Use jest-editor-support to show messages etc (#23)
* feat: Use jest-editor-support to show messages etc * feat: Add some failing tests
1 parent e6ccb2e commit 973bcf2

File tree

13 files changed

+1729
-1191
lines changed

13 files changed

+1729
-1191
lines changed

README.md

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,10 @@
1111

1212
### Setup Jest
1313

14-
This Danger plugin relies on modifying your Jest configuration.
14+
This Danger plugin relies on modifying your Jest configuration slightly on CI to also output a JSON file of the results.
1515

16-
Install [jest-json-reporter](https://github.com/Vall3y/jest-json-reporter):
17-
18-
```sh
19-
yarn add jest-json-reporter --dev
20-
```
21-
22-
Modify your `package.json` to process test results with jest-json-reporter. You may optionally set the output path of the JSON test results using the `jestJsonReporter.outputFile` path (which otherwise defaults to `./test-results.json`):
23-
24-
```json
25-
{
26-
"jest": {
27-
"testResultsProcessor": "jest-json-reporter"
28-
},
29-
"jestJsonReporter": {
30-
"outputFile": "tests/results.json"
31-
}
32-
}
33-
```
16+
You need to make the `yarn jest` command include: `--outputFile test-results.json --json`. This will run your tests
17+
like normal, but will also create a file with the full test results after.
3418

3519
> You may also want to add the JSON output file to your `.gitignore`, since it doesn't need to be checked into source control.
3620
@@ -42,25 +26,17 @@ Install this Danger plugin:
4226
yarn add danger-plugin-jest --dev
4327
```
4428

45-
If you set `jestJsonReporter.outputFile` in your `package.json`, make sure that `testResultsJsonPath` matches that path:
29+
By default, this package will assume you've set the filename as `test-results.json`, but you can use any path.
4630

4731
```js
4832
// dangerfile.js
4933
import path from 'path'
5034
import jest from 'danger-plugin-jest'
5135

52-
jest({
53-
testResultsJsonPath: path.resolve(__dirname, 'tests/results.json'),
54-
})
55-
```
56-
57-
If you _did not_ change the `jestJsonReporter.outputFile` path in your `package.json`, you can just do the following:
58-
59-
```js
60-
// dangerfile.js
61-
import jest from 'danger-plugin-jest'
62-
36+
// Default
6337
jest()
38+
// Custom path
39+
jest({ testResultsJsonPath: path.resolve(__dirname, 'tests/results.json') })
6440
```
6541

6642
See [`src/index.ts`](https://github.com/macklinu/danger-plugin-jest/blob/master/src/index.ts) for more details.

dangerfile.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
import jest from "./dist";
1+
import jest from './dist'
22

3-
jest();
3+
jest()

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
"url": "https://github.com/macklinu/danger-plugin-jest/issues"
3737
},
3838
"homepage": "https://github.com/macklinu/danger-plugin-jest#readme",
39+
"dependencies": {
40+
"strip-ansi": "^4.0.0"
41+
},
3942
"devDependencies": {
4043
"@types/jest": "^19.2.3",
4144
"@types/node": "^7.0.22",

src/TestFailureFormatter.ts

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/__tests__/__fixtures__/failed-tests-j20.json

Lines changed: 337 additions & 0 deletions
Large diffs are not rendered by default.

src/__tests__/__fixtures__/failing-tests.json

Lines changed: 1118 additions & 1120 deletions
Large diffs are not rendered by default.

src/__tests__/fails.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
it.skip('Fails 1', () => {
2+
expect(1).toEqual(2)
3+
})
4+
5+
it.skip('Fails 2', () => {
6+
expect(' asdasd').toBeLessThanOrEqual(2)
7+
})
8+
9+
it.skip('Fails 4', () => {
10+
expect({ a: 'asda'}).toBeFalsy()
11+
})

src/__tests__/index.test.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,53 @@ beforeEach(() => {
88
global['message'] = jest.fn()
99
global['fail'] = jest.fn()
1010
global['warn'] = jest.fn()
11+
global['danger'] = {
12+
github: {
13+
pr: {
14+
head: {
15+
ref: 'branch',
16+
repo: {
17+
full_name: 'repo/slug',
18+
},
19+
},
20+
},
21+
utils: {
22+
fileLinks: (a) => a,
23+
},
24+
},
25+
}
1126
})
1227

1328
test('messages with passing test results', () => {
1429
jestResults({
1530
testResultsJsonPath: fixture('passing-tests.json'),
1631
})
17-
expect(global['message']).toHaveBeenCalled()
32+
expect(global['fail']).not.toHaveBeenCalled()
1833
})
1934

2035
test('fails with failing test results', () => {
2136
jestResults({
2237
testResultsJsonPath: fixture('failing-tests.json'),
2338
})
24-
expect(global['fail']).toHaveBeenCalledWith(expect.stringMatching(/Jest tests failed/))
39+
expect(global['fail']).toHaveBeenCalledWith(expect.stringMatching(/FAIL/))
40+
})
41+
42+
test('fails with failing test results from jest 20', () => {
43+
jestResults({
44+
testResultsJsonPath: fixture('failed-tests-j20.json'),
45+
})
46+
expect(global['fail']).toHaveBeenCalledWith(expect.stringMatching(/FAIL/))
2547
})
2648

2749
test('warns when test results JSON file cannot be read', () => {
2850
jestResults({
2951
testResultsJsonPath: fixture('nonexistent.json'),
3052
})
31-
expect(global['warn']).toHaveBeenCalled()
53+
expect(global['fail']).toHaveBeenCalled()
54+
})
55+
56+
test.skip('Fails 6', () => {
57+
expect({ v: 'asda'}).toContain('s')
3258
})
3359

3460
const fixture = (filename: string) => path.resolve(__dirname, '__fixtures__', filename)

src/ambient.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
declare function warn(message: string): void
33
declare function fail(message: string): void
44
declare function message(message: string): void
5+
6+
declare module 'strip-ansi'

src/index.ts

Lines changed: 104 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,119 @@
11
import * as fs from 'fs'
2+
import * as path from 'path'
23

3-
import { TestFailureFormatter } from './TestFailureFormatter'
4+
import * as stripANSI from 'strip-ansi'
45

5-
export interface IPluginConfig {
6-
testResultsJsonPath?: string
7-
}
6+
import { DangerDSLType } from '../node_modules/danger/distribution/dsl/DangerDSL'
7+
import { IInsideFileTestResults, IJestTestOldResults, IJestTestResults } from './types'
8+
declare var danger: DangerDSLType
89

9-
interface IJestTestResults {
10-
success: boolean
10+
export interface IPluginConfig {
11+
testResultsJsonPath: string
1112
}
1213

13-
export default function jest(config: IPluginConfig = {}) {
14-
const {
15-
testResultsJsonPath = 'test-results.json',
16-
} = config
17-
14+
export default function jest(config: Partial<IPluginConfig> = {}) {
15+
const { testResultsJsonPath = 'test-results.json' } = config
1816
try {
1917
const jsonFileContents = fs.readFileSync(testResultsJsonPath, 'utf8')
20-
const testResults: IJestTestResults = JSON.parse(jsonFileContents)
21-
if (testResults.success) {
22-
message(':white_check_mark: Jest tests passed')
23-
} else {
24-
const formattedFailures = new TestFailureFormatter(testResults).format()
25-
fail(`:no_good_man: Jest tests failed:
18+
const jsonResults: IJestTestResults = JSON.parse(jsonFileContents)
19+
// console.log(jsonResults)
20+
if (jsonResults.success) {
21+
// tslint:disable-next-line:no-console
22+
console.log('Jest tests passed :+1:')
23+
return
24+
}
25+
// console.log(1)
2626

27-
\`\`\`
28-
${formattedFailures}
29-
\`\`\``)
27+
const isModernFormatResults = jsonResults.testResults[0].testResults
28+
if (isModernFormatResults) {
29+
presentErrorsForNewStyleResults(jsonResults)
30+
} else {
31+
presentErrorsForOldStyleResults(jsonResults as any)
3032
}
3133
} catch (e) {
3234
// tslint:disable-next-line:no-console
3335
console.error(e)
34-
warn('Could not read test results. Danger cannot pass or fail the build.')
36+
fail('[danger-plugin-jest] Could not read test results. Danger cannot pass or fail the build.')
3537
}
3638
}
39+
40+
const presentErrorsForOldStyleResults = (jsonResults: IJestTestOldResults) => {
41+
const failing = jsonResults.testResults.filter((tr) => tr.status === 'failed')
42+
43+
failing.forEach((results) => {
44+
const relativeFilePath = path.relative(process.cwd(), results.name)
45+
const failedAssertions = results.assertionResults.filter((r) => r.status === 'failed')
46+
const failMessage = fileToFailString(relativeFilePath, failedAssertions as any)
47+
fail(failMessage)
48+
})
49+
}
50+
51+
const presentErrorsForNewStyleResults = (jsonResults: IJestTestResults) => {
52+
const failing = jsonResults.testResults.filter((tr) => tr.numFailingTests > 0)
53+
54+
failing.forEach((results) => {
55+
const relativeFilePath = path.relative(process.cwd(), results.testFilePath)
56+
const failedAssertions = results.testResults.filter((r) => r.status === 'failed')
57+
const failMessage = fileToFailString(relativeFilePath, failedAssertions)
58+
fail(failMessage)
59+
})
60+
}
61+
62+
// e.g. https://github.com/orta/danger-plugin-jest/blob/master/src/__tests__/fails.test.ts
63+
const linkToTest = (file: string, msg: string, title: string) => {
64+
const line = lineOfError(msg, file)
65+
const repo = danger.github.pr.head.repo
66+
const urlParts = [
67+
'https://github.com',
68+
repo.full_name,
69+
'blob',
70+
danger.github.pr.head.ref,
71+
`${file}${'line' ? '#L' + line : ''}`,
72+
]
73+
return `<a href='${urlParts.join('/')}'>${title}</a>`
74+
}
75+
76+
const assertionFailString = (file: string, status: IInsideFileTestResults): string => `
77+
<li>
78+
${linkToTest(file, status.failureMessages && status.failureMessages[0], status.title)}
79+
<br/>
80+
${sanitizeShortErrorMessage(status.failureMessages && stripANSI(status.failureMessages[0]))}
81+
82+
<details>
83+
<summary>Full message</summary>
84+
<pre><code>
85+
${status.failureMessages && stripANSI(status.failureMessages.join('\n'))}
86+
</code></pre>
87+
</details>
88+
</li>
89+
<br/>
90+
`
91+
92+
const fileToFailString = (path: string, failedAssertions: IInsideFileTestResults[]): string => `
93+
<b>🃏 FAIL</b> in ${danger.github.utils.fileLinks([path])}
94+
95+
${failedAssertions.map((a) => assertionFailString(path, a)).join('\n\n')}
96+
`
97+
98+
const lineOfError = (msg: string, filePath: string): number | null => {
99+
const filename = path.basename(filePath)
100+
const restOfTrace = msg.split(filename, 2)[1]
101+
return restOfTrace ? parseInt(restOfTrace.split(':')[1], 10) : null
102+
}
103+
104+
const sanitizeShortErrorMessage = (msg: string): string => {
105+
if (msg.includes('does not match stored snapshot')) {
106+
return 'Snapshot has changed'
107+
}
108+
109+
return msg
110+
.split(' at', 1)[0]
111+
.trim()
112+
.split('\n')
113+
.splice(2)
114+
.join('')
115+
.replace(/\s\s+/g, ' ')
116+
.replace('Received:', ', received:')
117+
.replace('., received', ', received')
118+
.split('Difference:')[0]
119+
}

0 commit comments

Comments
 (0)