Skip to content

Commit e2c1c74

Browse files
committed
feat: added stderr matcher
Closes #9
1 parent 0f717df commit e2c1c74

File tree

7 files changed

+119
-4
lines changed

7 files changed

+119
-4
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"jest-matcher-utils": "^27.4.2",
4444
"lz-string": "^1.4.4",
4545
"pretty-format": "^27.0.2",
46+
"redent": "^3.0.0",
4647
"strip-ansi": "^6.0.1",
4748
"strip-final-newline": "^2.0.0",
4849
"tree-kill": "^1.2.2"

src/__tests__/matchers.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const {resolve} = require('path')
22
const {render} = require('../pure')
3+
const {toHaveErrorMessage} = require("../matchers/to-have-errormessage");
34

45
test('toBeInTheConsole should pass when something is in console', async () => {
56
const {findByText} = await render('node', [
@@ -20,3 +21,41 @@ test('toBeInTheConsole should fail when something is not console', async () => {
2021

2122
expect(() => expect(queryByText('NotHere')).toBeInTheConsole()).toThrow(/value must be a TestInstance/)
2223
})
24+
25+
test('toHaveErrorMessage should pass during stderr when no string passed', async () => {
26+
const instance = await render('node', [
27+
resolve(__dirname, './execute-scripts/throw.js'),
28+
])
29+
30+
await expect(
31+
(async () => expect(instance).toHaveErrorMessage())()
32+
).resolves.not.toThrow()
33+
})
34+
35+
test('toHaveErrorMessage should pass during stderr when string passed', async () => {
36+
const instance = await render('node', [
37+
resolve(__dirname, './execute-scripts/throw.js'),
38+
])
39+
40+
await expect(
41+
(async () => expect(instance).toHaveErrorMessage(/Search for this error in stderr/))()
42+
).resolves.not.toThrow()
43+
})
44+
45+
test('toHaveErrorMessage should fail when something is not in stderr', async () => {
46+
const {queryByText} = await render('node', [
47+
resolve(__dirname, './execute-scripts/list-args.js'),
48+
'--version',
49+
])
50+
51+
expect(() => expect(queryByText('--version')).toHaveErrorMessage("Error isn't here")).toThrow(/Expected the element to have error message/)
52+
})
53+
54+
test('toHaveErrorMessage should fail when null is passed', async () => {
55+
const {queryByText} = await render('node', [
56+
resolve(__dirname, './execute-scripts/list-args.js'),
57+
'--version',
58+
])
59+
60+
expect(() => expect(queryByText('NotHere')).toHaveErrorMessage()).toThrow(/value must be a TestInstance/)
61+
})

src/matchers/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import {toBeInTheConsole} from './to-be-in-the-console'
2+
import {toHaveErrorMessage} from './to-have-errormessage'
23

34
export {
4-
toBeInTheConsole
5+
toBeInTheConsole,
6+
toHaveErrorMessage
57
}

src/matchers/to-be-in-the-console.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1+
/* eslint-disable @babel/no-invalid-this */
12
import {checkCliInstance} from "./utils";
23

34
export function toBeInTheConsole(instance) {
4-
// eslint-disable-next-line @babel/no-invalid-this
55
if (instance !== null || !this.isNot) {
6-
// eslint-disable-next-line @babel/no-invalid-this
76
checkCliInstance(instance, toBeInTheConsole, this)
87
}
98

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/* eslint-disable @babel/no-invalid-this */
2+
import {getDefaultNormalizer} from "../matches";
3+
import {checkCliInstance, getMessage} from './utils'
4+
5+
/**
6+
* @param {TestInstance} testInstance
7+
* @param checkWith
8+
*/
9+
export function toHaveErrorMessage(testInstance, checkWith) {
10+
checkCliInstance(testInstance, toHaveErrorMessage, this)
11+
12+
const expectsErrorMessage = checkWith !== undefined
13+
14+
const errormessage = getDefaultNormalizer()(testInstance.stderrArr.join('\n'))
15+
16+
return {
17+
pass: expectsErrorMessage
18+
? checkWith instanceof RegExp
19+
? checkWith.test(errormessage)
20+
: this.equals(errormessage, checkWith)
21+
: Boolean(testInstance.stderrArr.length),
22+
message: () => {
23+
const to = this.isNot ? 'not to' : 'to'
24+
return getMessage(
25+
this,
26+
this.utils.matcherHint(
27+
`${this.isNot ? '.not' : ''}.toHaveErrorMessage`,
28+
'element',
29+
'',
30+
),
31+
`Expected the element ${to} have error message`,
32+
this.utils.printExpected(checkWith),
33+
'Received',
34+
this.utils.printReceived(errormessage),
35+
)
36+
},
37+
}
38+
39+
}

src/matchers/utils.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import redent from 'redent'
2+
13
class GenericTypeError extends Error {
24
constructor(expectedString, received, matcherFn, context) {
35
super()
@@ -51,7 +53,33 @@ function checkCliInstance(cliInstance, ...args) {
5153
}
5254
}
5355

56+
function display(context, value) {
57+
return typeof value === 'string' ? value : context.utils.stringify(value)
58+
}
59+
60+
function getMessage(
61+
context,
62+
matcher,
63+
expectedLabel,
64+
expectedValue,
65+
receivedLabel,
66+
receivedValue,
67+
) {
68+
return [
69+
`${matcher}\n`,
70+
// eslint-disable-next-line @babel/new-cap
71+
`${expectedLabel}:\n${context.utils.EXPECTED_COLOR(
72+
redent(display(context, expectedValue), 2),
73+
)}`,
74+
// eslint-disable-next-line @babel/new-cap
75+
`${receivedLabel}:\n${context.utils.RECEIVED_COLOR(
76+
redent(display(context, receivedValue), 2),
77+
)}`,
78+
].join('\n')
79+
}
80+
5481
export {
5582
CliInstanceTypeError,
5683
checkCliInstance,
84+
getMessage
5785
}

types/extend-expect.d.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,17 @@ declare namespace jest {
66
interface Matchers<R, ignored> {
77
/**
88
* @description
9-
* Assert whether an element is present in the console or not.
9+
* Assert whether a query is present in the console or not.
1010
* @example
1111
* expect(queryByText('Hello world')).toBeInTheDocument()
1212
*/
1313
toBeInTheConsole(): R;
14+
/**
15+
* @description
16+
* Check whether the given instance has an stderr message or not.
17+
* @example
18+
* expect(instance).toHaveErrorMessage(/command could not be found/i) // to partially match
19+
*/
20+
toHaveErrorMessage(): R;
1421
}
1522
}

0 commit comments

Comments
 (0)