@plugjs/expect5 0.4.6 → 0.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/cli.mjs +6 -1
  2. package/dist/cli.mjs.map +1 -1
  3. package/dist/execution/executable.mjs +6 -0
  4. package/dist/execution/executable.mjs.map +1 -1
  5. package/dist/execution/executor.mjs +6 -0
  6. package/dist/execution/executor.mjs.map +1 -1
  7. package/dist/execution/setup.mjs +6 -0
  8. package/dist/execution/setup.mjs.map +1 -1
  9. package/dist/expectation/async.cjs +14 -22
  10. package/dist/expectation/async.cjs.map +1 -1
  11. package/dist/expectation/async.d.ts +39 -13
  12. package/dist/expectation/async.mjs +20 -22
  13. package/dist/expectation/async.mjs.map +1 -1
  14. package/dist/expectation/diff.mjs +6 -0
  15. package/dist/expectation/diff.mjs.map +1 -1
  16. package/dist/expectation/expect.cjs +3 -3
  17. package/dist/expectation/expect.cjs.map +1 -1
  18. package/dist/expectation/expect.d.ts +3 -3
  19. package/dist/expectation/expect.mjs +10 -4
  20. package/dist/expectation/expect.mjs.map +1 -1
  21. package/dist/expectation/expectations.cjs +27 -44
  22. package/dist/expectation/expectations.cjs.map +1 -1
  23. package/dist/expectation/expectations.d.ts +72 -14
  24. package/dist/expectation/expectations.mjs +33 -44
  25. package/dist/expectation/expectations.mjs.map +1 -1
  26. package/dist/expectation/include.mjs +6 -0
  27. package/dist/expectation/include.mjs.map +1 -1
  28. package/dist/expectation/matchers.cjs +24 -47
  29. package/dist/expectation/matchers.cjs.map +1 -1
  30. package/dist/expectation/matchers.d.ts +136 -93
  31. package/dist/expectation/matchers.mjs +29 -46
  32. package/dist/expectation/matchers.mjs.map +1 -1
  33. package/dist/expectation/print.cjs +4 -0
  34. package/dist/expectation/print.cjs.map +1 -1
  35. package/dist/expectation/print.mjs +11 -1
  36. package/dist/expectation/print.mjs.map +1 -1
  37. package/dist/expectation/types.cjs.map +1 -1
  38. package/dist/expectation/types.d.ts +2 -2
  39. package/dist/expectation/types.mjs +6 -0
  40. package/dist/expectation/types.mjs.map +1 -1
  41. package/dist/globals.mjs +5 -0
  42. package/dist/index.mjs +6 -0
  43. package/dist/index.mjs.map +1 -1
  44. package/dist/test.cjs +17 -7
  45. package/dist/test.cjs.map +1 -1
  46. package/dist/test.mjs +25 -9
  47. package/dist/test.mjs.map +1 -1
  48. package/package.json +3 -3
  49. package/src/expectation/async.ts +69 -17
  50. package/src/expectation/expect.ts +6 -6
  51. package/src/expectation/expectations.ts +152 -27
  52. package/src/expectation/matchers.ts +207 -125
  53. package/src/expectation/print.ts +7 -1
  54. package/src/expectation/types.ts +2 -2
  55. package/src/test.ts +29 -8
package/dist/test.mjs CHANGED
@@ -1,15 +1,21 @@
1
+ ;const __$$_esm_paths_helper = await (async() => {
2
+ const __filename = (await import("node:url")).fileURLToPath(import.meta.url);
3
+ const __dirname = (await import("node:path")).dirname(__filename);
4
+ return { __filename, __dirname };
5
+ })();
6
+
1
7
  // test.ts
2
8
  import { AssertionError } from "node:assert";
3
9
  import { BuildFailure } from "@plugjs/plug";
4
10
  import { assert } from "@plugjs/plug/asserts";
5
- import { $blu, $grn, $gry, $ms, $red, $wht, $ylw, ERROR, NOTICE, WARN, log } from "@plugjs/plug/logging";
11
+ import { $blu, $grn, $gry, $ms, $red, $wht, $ylw, ERROR, NOTICE, WARN, log, $p, githubAnnotation } from "@plugjs/plug/logging";
6
12
  import * as setup from "./execution/setup.mjs";
7
13
  import { Suite, skip } from "./execution/executable.mjs";
8
14
  import { runSuite } from "./execution/executor.mjs";
9
15
  import { diff } from "./expectation/diff.mjs";
10
16
  import { expect } from "./expectation/expect.mjs";
11
17
  import { printDiff } from "./expectation/print.mjs";
12
- import { ExpectationError, stringifyObjectType, stringifyValue } from "./expectation/types.mjs";
18
+ import { ExpectationError, stringifyValue } from "./expectation/types.mjs";
13
19
  var _pending = "\u22EF";
14
20
  var _success = "\u2714";
15
21
  var _failure = "\u2718";
@@ -46,8 +52,11 @@ var Test = class {
46
52
  anyGlobal["log"] = log;
47
53
  }
48
54
  const suite = new Suite(void 0, "", async () => {
49
- for (const file of files.absolutePaths())
55
+ let count = 0;
56
+ for (const file of files.absolutePaths()) {
57
+ log.debug("Importing", $p(file), "in suite", $gry(`(${++count}/${files.length})`));
50
58
  await import(file);
59
+ }
51
60
  });
52
61
  await suite.setup();
53
62
  const snum = suite.specs;
@@ -80,10 +89,14 @@ var Test = class {
80
89
  execution.on("spec:skip", (spec, ms) => {
81
90
  if (suite.flag === "only")
82
91
  return context.log.leave();
83
- context.log.leave(WARN, `${$ylw(_pending)} ${spec.name} ${$ms(ms)} ${$gry("[")}${$ylw("skipped")}${$gry("]")}`);
92
+ context.log.leave(WARN, `${$ylw(_pending)} ${spec.name} ${$ms(ms, $ylw("skipped"))}`);
84
93
  });
85
94
  execution.on("spec:pass", (spec, ms) => {
86
- context.log.leave(NOTICE, `${$grn(_success)} ${spec.name} ${$ms(ms)}`);
95
+ if (ms >= spec.timeout * 0.75) {
96
+ context.log.leave(WARN, `${$ylw(_success)} ${spec.name} ${$ms(ms, $ylw("slow"))}`);
97
+ } else {
98
+ context.log.leave(NOTICE, `${$grn(_success)} ${spec.name} ${$ms(ms)}`);
99
+ }
87
100
  });
88
101
  execution.on("spec:fail", (spec, ms, { number }) => {
89
102
  context.log.leave(
@@ -138,6 +151,7 @@ var Test = class {
138
151
  function dumpError(log2, error, genericErrorDiffs) {
139
152
  if (error instanceof ExpectationError) {
140
153
  log2.enter(ERROR, `${$gry("Expectation Error:")} ${$red(error.message)}`);
154
+ githubAnnotation({ type: "error", title: "Expectation Error" }, error.message);
141
155
  try {
142
156
  dumpProps(log2, 17, error);
143
157
  dumpStack(log2, error);
@@ -150,6 +164,7 @@ function dumpError(log2, error, genericErrorDiffs) {
150
164
  } else if (error instanceof AssertionError) {
151
165
  const [message = "Unknown Error", ...lines] = error.message.split("\n");
152
166
  log2.enter(ERROR, `${$gry("Assertion Error:")} ${$red(message)}`);
167
+ githubAnnotation({ type: "error", title: "Assertion Error" }, message);
153
168
  try {
154
169
  dumpProps(log2, 15, error);
155
170
  dumpStack(log2, error);
@@ -170,9 +185,10 @@ function dumpError(log2, error, genericErrorDiffs) {
170
185
  }
171
186
  } else if (error instanceof Error) {
172
187
  const message = error.message || "Unknown Error";
173
- const string = stringifyObjectType(error);
174
- const type = string === "[AssertionError]" ? "Assertion Error" : string;
175
- log2.enter(ERROR, `${$gry(type)}: ${$red(message)}`);
188
+ const string = Object.getPrototypeOf(error)?.constructor?.name || "Error";
189
+ const type = string === "AssertionError" ? `${$gry("Assertion Error")}: ` : string === "Error" ? "" : `${$gry(string)}: `;
190
+ log2.enter(ERROR, `${type}${$red(message)}`);
191
+ githubAnnotation({ type: "error", title: string }, message);
176
192
  try {
177
193
  dumpProps(log2, type.length, error);
178
194
  dumpStack(log2, error);
@@ -203,7 +219,7 @@ function dumpProps(log2, pad, error) {
203
219
  // chai
204
220
  "stack"
205
221
  // error
206
- ].includes(k)).forEach((k) => {
222
+ ].includes(k)).filter((k) => !(error[k] === null)).filter((k) => !(error[k] === void 0)).forEach((k) => {
207
223
  const value = error[k];
208
224
  if (k === "code" && value === "ERR_ASSERTION")
209
225
  return;
package/dist/test.mjs.map CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/test.ts"],
4
- "mappings": "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",
4
+ "mappings": "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",
5
5
  "names": ["log"]
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plugjs/expect5",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -43,11 +43,11 @@
43
43
  "author": "Juit Developers <developers@juit.com>",
44
44
  "license": "Apache-2.0",
45
45
  "devDependencies": {
46
- "@types/chai": "^4.3.4",
46
+ "@types/chai": "^4.3.5",
47
47
  "chai": "^4.3.7"
48
48
  },
49
49
  "peerDependencies": {
50
- "@plugjs/plug": "0.4.6"
50
+ "@plugjs/plug": "0.4.8"
51
51
  },
52
52
  "files": [
53
53
  "*.md",
@@ -2,10 +2,13 @@ import {
2
2
  Expectations,
3
3
  type AssertionFunction,
4
4
  type AssertedType,
5
- type InferMatchers,
5
+ type InferToEqual,
6
+ type InferMatcher,
6
7
  } from './expectations'
8
+ import { isMatcher, type Constructor } from './types'
9
+
10
+ import type { Matcher } from './matchers'
7
11
 
8
- import type { Constructor } from './types'
9
12
 
10
13
  /**
11
14
  * Extension to {@link Expectations} adding support for {@link Promise}s.
@@ -26,15 +29,35 @@ export class AsyncExpectations<T = unknown> extends Expectations<T> {
26
29
  /* ------------------------------------------------------------------------ */
27
30
 
28
31
  /**
29
- * Expects the value to be a _rejected_ {@link PromiseLike}, and (if
30
- * specified) further asserts the rejection reason with an
31
- * {@link AssertionFunction}.
32
+ * Expects the value to be a _rejected_ {@link PromiseLike}.
33
+ *
34
+ * Negation: {@link Expectations.toBeResolved `toBeResolved(...)`}
35
+ */
36
+ toBeRejected(): Promise<Expectations<PromiseLike<Awaited<T>>>>
37
+
38
+ /**
39
+ * Expects the value to be a _rejected_ {@link PromiseLike}, and further
40
+ * validates the rejection with a {@link Matcher}.
32
41
  *
33
42
  * Negation: {@link Expectations.toBeResolved `toBeResolved(...)`}
34
43
  */
35
44
  toBeRejected(
36
- assertion?: AssertionFunction,
37
- ): Promise<Expectations<PromiseLike<Awaited<T>>>> {
45
+ matcher: Matcher,
46
+ ): Promise<Expectations<PromiseLike<Awaited<T>>>>
47
+
48
+ /**
49
+ * Expects the value to be a _rejected_ {@link PromiseLike}, and further
50
+ * asserts the rejection reason with an {@link AssertionFunction}.
51
+ *
52
+ * Negation: {@link Expectations.toBeResolved `toBeResolved(...)`}
53
+ */
54
+ toBeRejected(
55
+ assertion: AssertionFunction,
56
+ ): Promise<Expectations<PromiseLike<Awaited<T>>>>
57
+
58
+ toBeRejected(
59
+ assertionOrMatcher?: AssertionFunction | Matcher,
60
+ ): Promise<Expectations> {
38
61
  return Promise.resolve()
39
62
  .then(() => {
40
63
  this.toHaveProperty('then', (assert) => assert.toBeA('function'))
@@ -42,7 +65,11 @@ export class AsyncExpectations<T = unknown> extends Expectations<T> {
42
65
  })
43
66
  .then(([ settlement ]) => {
44
67
  if (settlement.status === 'rejected') {
45
- if (assertion) assertion(new Expectations(settlement.reason, this.remarks))
68
+ if (isMatcher(assertionOrMatcher)) {
69
+ assertionOrMatcher.expect(settlement.reason)
70
+ } else if (assertionOrMatcher) {
71
+ assertionOrMatcher(new Expectations(settlement.reason, this.remarks))
72
+ }
46
73
  return this as Expectations<any>
47
74
  }
48
75
 
@@ -54,7 +81,8 @@ export class AsyncExpectations<T = unknown> extends Expectations<T> {
54
81
 
55
82
  /**
56
83
  * Expects the value to be a {@link PromiseLike} _rejected_ with an
57
- * {@link Error} _strictly equal_ to the one specified.
84
+ * {@link Error} {@link Expectations.toStrictlyEqual _strictly equal_}
85
+ * to the one specified.
58
86
  *
59
87
  * Negation: {@link Expectations.toBeResolved `toBeResolved(...)`}
60
88
  */
@@ -111,15 +139,35 @@ export class AsyncExpectations<T = unknown> extends Expectations<T> {
111
139
  /* ------------------------------------------------------------------------ */
112
140
 
113
141
  /**
114
- * Expects the value to be a _resolved_ {@link PromiseLike}, and (if
115
- * specified) further asserts the resolved result with an
116
- * {@link AssertionFunction}.
142
+ * Expects the value to be a _resolved_ {@link PromiseLike}.
143
+ *
144
+ * Negation: {@link Expectations.toBeRejected `toBeRejected(...)`}
145
+ */
146
+ toBeResolved(): Promise<Expectations<PromiseLike<Awaited<T>>>>
147
+
148
+ /**
149
+ * Expects the value to be a _resolved_ {@link PromiseLike}, and further
150
+ * validates the resolved result with a {@link Matcher}.
151
+ *
152
+ * Negation: {@link Expectations.toBeRejected `toBeRejected(...)`}
153
+ */
154
+ toBeResolved<Match extends Matcher>(
155
+ matcher: Match,
156
+ ): Promise<Expectations<PromiseLike<InferMatcher<unknown, Match>>>>
157
+
158
+ /**
159
+ * Expects the value to be a _resolved_ {@link PromiseLike}, and further
160
+ * asserts the resolved result with an {@link AssertionFunction}.
117
161
  *
118
162
  * Negation: {@link Expectations.toBeRejected `toBeRejected(...)`}
119
163
  */
120
164
  toBeResolved<Assert extends AssertionFunction<Awaited<T>>>(
121
- assertion?: Assert,
122
- ): Promise<Expectations<PromiseLike<AssertedType<Awaited<T>, Assert>>>> {
165
+ assertion: Assert,
166
+ ): Promise<Expectations<PromiseLike<AssertedType<Awaited<T>, Assert>>>>
167
+
168
+ toBeResolved(
169
+ assertion?: AssertionFunction | Matcher,
170
+ ): Promise<Expectations> {
123
171
  return Promise.resolve()
124
172
  .then(() => {
125
173
  this.toHaveProperty('then', (assert) => assert.toBeA('function'))
@@ -127,7 +175,11 @@ export class AsyncExpectations<T = unknown> extends Expectations<T> {
127
175
  })
128
176
  .then(([ settlement ]) => {
129
177
  if (settlement.status === 'fulfilled') {
130
- if (assertion) assertion(new Expectations(settlement.value, this.remarks))
178
+ if (isMatcher(assertion)) {
179
+ assertion.expect(settlement.value)
180
+ } else if (assertion) {
181
+ assertion(new Expectations(settlement.value, this.remarks))
182
+ }
131
183
  return this as Expectations<any>
132
184
  }
133
185
 
@@ -139,13 +191,13 @@ export class AsyncExpectations<T = unknown> extends Expectations<T> {
139
191
 
140
192
  /**
141
193
  * Expects the value to be a {@link PromiseLike} _resolved_ with a value
142
- * _deeply equal_ to the one specified.
194
+ * {@link Expectations.toEqual _deeply equal_} to the one specified.
143
195
  *
144
196
  * Negation: {@link Expectations.toBeRejected `toBeRejected(...)`}
145
197
  */
146
198
  toBeResolvedWith<Type>(
147
199
  expected: Type,
148
- ): Promise<Expectations<PromiseLike<InferMatchers<Type>>>> {
200
+ ): Promise<Expectations<PromiseLike<InferToEqual<Type>>>> {
149
201
  return this.toBeResolved((assert) => assert.toEqual(expected)) as any
150
202
  }
151
203
  }
@@ -1,9 +1,9 @@
1
1
  import { AsyncExpectations } from './async'
2
- import { Matchers } from './matchers'
2
+ import { Matcher } from './matchers'
3
3
 
4
4
  export type { AsyncExpectations } from './async'
5
5
  export type { Expectations, NegativeExpectations } from './expectations'
6
- export type { Matchers, NegativeMatchers } from './matchers'
6
+ export type { Matcher as Matchers, NegativeMatchers } from './matchers'
7
7
 
8
8
  /* ========================================================================== *
9
9
  * EXPECT FUNCTION *
@@ -12,7 +12,7 @@ export type { Matchers, NegativeMatchers } from './matchers'
12
12
  /** The `expect` function exposing expectations and matchers */
13
13
  export type Expect = {
14
14
  <T = unknown>(value: T, remarks?: string): AsyncExpectations<T>
15
- } & Omit<Matchers, 'expect'>
15
+ } & Omit<Matcher, 'expect'>
16
16
 
17
17
  /** The `expect` function exposing expectations and matchers */
18
18
  export const expect: Expect = ((value: any, remarks?: string) => {
@@ -20,13 +20,13 @@ export const expect: Expect = ((value: any, remarks?: string) => {
20
20
  }) as Expect
21
21
 
22
22
  /* Inject all our matchers constructors in the `expect` function */
23
- for (const key of Object.getOwnPropertyNames(Matchers.prototype)) {
23
+ for (const key of Object.getOwnPropertyNames(Matcher.prototype)) {
24
24
  if (! key.startsWith('to')) continue
25
25
 
26
- const matcher = (...args: any[]): any => ((new Matchers() as any)[key](...args))
26
+ const matcher = (...args: any[]): any => ((new Matcher() as any)[key](...args))
27
27
  Object.defineProperty(matcher, 'name', { value: key })
28
28
  Object.defineProperty(expect, key, { value: matcher })
29
29
  }
30
30
 
31
31
  /* Inject the negative matcher constructor in the `expect` function */
32
- Object.defineProperty(expect, 'not', { get: () => new Matchers().not })
32
+ Object.defineProperty(expect, 'not', { get: () => new Matcher().not })
@@ -1,6 +1,6 @@
1
1
  import { diff, type Diff } from './diff'
2
2
  import { toInclude, toMatchContents } from './include'
3
- import { type Matchers } from './matchers'
3
+ import { type Matcher } from './matchers'
4
4
  import {
5
5
  ExpectationError,
6
6
  isMatcher,
@@ -28,13 +28,20 @@ export type AssertedType<T, F extends AssertionFunction<any>, R = ReturnType<F>>
28
28
  I : // returns Expectations<something>, use "something"
29
29
  T // returns something else (void), use T
30
30
 
31
- export type InferMatchers<T> =
32
- T extends Matchers<infer V> ? V :
33
- T extends Record<any, any> ? { [ k in keyof T ] : InferMatchers<T[k]> } :
31
+ /** Infer the type of a {@link Matcher} */
32
+ export type InferMatcher<T, M extends Matcher> =
33
+ M extends Matcher<infer I> ?
34
+ unknown extends I ? T : T & I :
35
+ never
36
+
37
+ /** Recursively infer the type of a {@link Matcher} in a `Record` */
38
+ export type InferToEqual<T> =
39
+ T extends Matcher<infer V> ? V :
40
+ T extends Record<any, any> ? { [ k in keyof T ] : InferToEqual<T[k]> } :
34
41
  T
35
42
 
36
43
  /** Simple wrapper defining the _parent_ instance of an {@link Expectations}. */
37
- type ExpectationsParent = {
44
+ export type ExpectationsParent = {
38
45
  /** Parent {@link Expectations} instance */
39
46
  expectations: Expectations,
40
47
  /** Property associating _this_ to the parent */
@@ -79,9 +86,31 @@ export class Expectations<T = unknown> {
79
86
  * BASIC *
80
87
  * ------------------------------------------------------------------------ */
81
88
 
89
+ /**
90
+ * Expects the value to be of the specified _extended_ {@link TypeName type}.
91
+ *
92
+ * Negation: {@link NegativeExpectations.toBeA `not.toBeA(...)`}
93
+ */
94
+ toBeA<Name extends TypeName>(type: Name): Expectations<TypeMappings[Name]>
95
+
96
+ /**
97
+ * Expects the value to be of the specified _extended_ {@link TypeName type},
98
+ * and further validates it with a {@link Matcher}.
99
+ *
100
+ * Negation: {@link NegativeExpectations.toBeA `not.toBeA(...)`}
101
+ */
102
+ toBeA<
103
+ Name extends TypeName,
104
+ Mapped extends TypeMappings[Name],
105
+ Match extends Matcher,
106
+ >(
107
+ type: Name,
108
+ matcher: Match,
109
+ ): Expectations<InferMatcher<Mapped, Match>>
110
+
82
111
  /**
83
112
  * Expects the value to be of the specified _extended_ {@link TypeName type},
84
- * and (if specified) further asserts it with an {@link AssertionFunction}.
113
+ * and further asserts it with an {@link AssertionFunction}.
85
114
  *
86
115
  * Negation: {@link NegativeExpectations.toBeA `not.toBeA(...)`}
87
116
  */
@@ -90,11 +119,20 @@ export class Expectations<T = unknown> {
90
119
  Mapped extends TypeMappings[Name],
91
120
  Assert extends AssertionFunction<Mapped>,
92
121
  >(
93
- type: Name,
94
- assertion?: Assert,
95
- ): Expectations<AssertedType<Mapped, Assert>> {
122
+ type: Name,
123
+ assertion: Assert,
124
+ ): Expectations<AssertedType<Mapped, Assert>>
125
+
126
+ toBeA(
127
+ type: TypeName,
128
+ assertionOrMatcher?: AssertionFunction | Matcher,
129
+ ): Expectations {
96
130
  if (typeOf(this.value) === type) {
97
- if (assertion) assertion(this as Expectations<any>)
131
+ if (isMatcher(assertionOrMatcher)) {
132
+ assertionOrMatcher.expect(this.value)
133
+ } else if (assertionOrMatcher) {
134
+ assertionOrMatcher(this as Expectations<any>)
135
+ }
98
136
  return this as Expectations<any>
99
137
  }
100
138
 
@@ -250,9 +288,32 @@ export class Expectations<T = unknown> {
250
288
 
251
289
  /* ------------------------------------------------------------------------ */
252
290
 
291
+ /**
292
+ * Expects the value to be an instance of the specified {@link Constructor}.
293
+ *
294
+ * Negation: {@link NegativeExpectations.toBeInstanceOf `not.toInstanceOf(...)`}
295
+ */
296
+ toBeInstanceOf<Class extends Constructor>(
297
+ constructor: Class,
298
+ ): Expectations<InstanceType<Class>>
299
+
253
300
  /**
254
301
  * Expects the value to be an instance of the specified {@link Constructor},
255
- * and (if specified) further asserts it with an {@link AssertionFunction}.
302
+ * and further validates it with a {@link Matcher}.
303
+ *
304
+ * Negation: {@link NegativeExpectations.toBeInstanceOf `not.toInstanceOf(...)`}
305
+ */
306
+ toBeInstanceOf<
307
+ Class extends Constructor,
308
+ Match extends Matcher,
309
+ >(
310
+ constructor: Class,
311
+ matcher: Match,
312
+ ): Expectations<InferMatcher<InstanceType<Class>, Match>>
313
+
314
+ /**
315
+ * Expects the value to be an instance of the specified {@link Constructor},
316
+ * and further asserts it with an {@link AssertionFunction}.
256
317
  *
257
318
  * Negation: {@link NegativeExpectations.toBeInstanceOf `not.toInstanceOf(...)`}
258
319
  */
@@ -260,11 +321,20 @@ export class Expectations<T = unknown> {
260
321
  Class extends Constructor,
261
322
  Assert extends AssertionFunction<InstanceType<Class>>,
262
323
  >(
263
- constructor: Class,
264
- assertion?: Assert,
265
- ): Expectations<AssertedType<InstanceType<Class>, Assert>> {
324
+ constructor: Class,
325
+ assertion: Assert,
326
+ ): Expectations<AssertedType<InstanceType<Class>, Assert>>
327
+
328
+ toBeInstanceOf(
329
+ constructor: Constructor,
330
+ assertionOrMatcher?: AssertionFunction | Matcher,
331
+ ): Expectations {
266
332
  if (this.value instanceof constructor) {
267
- if (assertion) assertion(this as Expectations<any>)
333
+ if (isMatcher(assertionOrMatcher)) {
334
+ assertionOrMatcher.expect(this.value)
335
+ } else if (assertionOrMatcher) {
336
+ assertionOrMatcher(this as Expectations<any>)
337
+ }
268
338
  return this as Expectations<any>
269
339
  }
270
340
 
@@ -404,7 +474,7 @@ export class Expectations<T = unknown> {
404
474
  *
405
475
  * Negation: {@link NegativeExpectations.toEqual `not.toEqual(...)`}
406
476
  */
407
- toEqual<Type>(expected: Type): Expectations<InferMatchers<Type>> {
477
+ toEqual<Type>(expected: Type): Expectations<InferToEqual<Type>> {
408
478
  if ((this.value as any) === expected) return this as Expectations<any>
409
479
 
410
480
  const result = diff(this.value, expected)
@@ -443,6 +513,29 @@ export class Expectations<T = unknown> {
443
513
 
444
514
  /* ------------------------------------------------------------------------ */
445
515
 
516
+ /**
517
+ * Expects the value to have the specified _property_.
518
+ *
519
+ * Negation: {@link NegativeExpectations.toHaveProperty `not.toHaveProperty(...)`}
520
+ */
521
+ toHaveProperty<Prop extends string | number | symbol>(
522
+ property: Prop,
523
+ ): Expectations<T & { [keyt in Prop] : unknown }>
524
+
525
+ /**
526
+ * Expects the value to have the specified _property_ and (if specified)
527
+ * further validates its value with a {@link Matcher}.
528
+ *
529
+ * Negation: {@link NegativeExpectations.toHaveProperty `not.toHaveProperty(...)`}
530
+ */
531
+ toHaveProperty<
532
+ Prop extends string | number | symbol,
533
+ Match extends Matcher,
534
+ >(
535
+ property: Prop,
536
+ matcher: Match,
537
+ ): Expectations<T & { [keyt in Prop] : InferMatcher<unknown, Match> }>
538
+
446
539
  /**
447
540
  * Expects the value to have the specified _property_ and (if specified)
448
541
  * further asserts its value with an {@link AssertionFunction}.
@@ -453,9 +546,14 @@ export class Expectations<T = unknown> {
453
546
  Prop extends string | number | symbol,
454
547
  Assert extends AssertionFunction,
455
548
  >(
456
- property: Prop,
457
- assertion?: Assert,
458
- ): Expectations<T & { [keyt in Prop] : AssertedType<unknown, Assert> }> {
549
+ property: Prop,
550
+ assertion: Assert,
551
+ ): Expectations<T & { [keyt in Prop] : AssertedType<unknown, Assert> }>
552
+
553
+ toHaveProperty(
554
+ property: string | number | symbol,
555
+ assertionOrMatcher?: AssertionFunction | Matcher,
556
+ ): Expectations {
459
557
  this.toBeDefined()
460
558
 
461
559
  const propertyValue = (this.value as any)[property]
@@ -464,11 +562,15 @@ export class Expectations<T = unknown> {
464
562
  this._fail(`to have property "${String(property)}"`)
465
563
  }
466
564
 
467
- if (assertion) {
565
+ if (assertionOrMatcher) {
566
+ const parent: ExpectationsParent = { expectations: this, prop: property }
468
567
  try {
469
- const parent: ExpectationsParent = { expectations: this, prop: property }
470
- const expectations = new Expectations(propertyValue, this.remarks, parent)
471
- assertion(expectations)
568
+ if (isMatcher(assertionOrMatcher)) {
569
+ assertionOrMatcher.expect(propertyValue, parent)
570
+ } else if (assertionOrMatcher) {
571
+ const expectations = new Expectations(propertyValue, this.remarks, parent)
572
+ assertionOrMatcher(expectations)
573
+ }
472
574
  } catch (error) {
473
575
  // any caught error difference gets remapped as a property diff
474
576
  if ((error instanceof ExpectationError) && (error.diff)) {
@@ -596,12 +698,31 @@ export class Expectations<T = unknown> {
596
698
  /* ------------------------------------------------------------------------ */
597
699
 
598
700
  /**
599
- * Expects the value to be a `function` throwing, and (if specified) further
600
- * asserts the thrown value with an {@link AssertionFunction}.
701
+ * Expects the value to be a `function` throwing.
601
702
  *
602
703
  * Negation: {@link NegativeExpectations.toThrow `not.toThrow()`}
603
704
  */
604
- toThrow(assert?: AssertionFunction): Expectations<() => any> {
705
+ toThrow(): Expectations<() => any>
706
+
707
+ /**
708
+ * Expects the value to be a `function` throwing, and further validates the
709
+ * thrown value with a {@link Matcher}.
710
+ *
711
+ * Negation: {@link NegativeExpectations.toThrow `not.toThrow()`}
712
+ */
713
+ toThrow(matcher: Matcher): Expectations<() => any>
714
+
715
+ /**
716
+ * Expects the value to be a `function` throwing, and further asserts the
717
+ * thrown value with an {@link AssertionFunction}.
718
+ *
719
+ * Negation: {@link NegativeExpectations.toThrow `not.toThrow()`}
720
+ */
721
+ toThrow(assert: AssertionFunction): Expectations<() => any>
722
+
723
+ toThrow(
724
+ assertionOrMatcher?: AssertionFunction | Matcher,
725
+ ): Expectations<() => any> {
605
726
  const func = this.toBeA('function')
606
727
 
607
728
  let passed = false
@@ -609,7 +730,11 @@ export class Expectations<T = unknown> {
609
730
  func.value()
610
731
  passed = true
611
732
  } catch (thrown) {
612
- if (assert) assert(new Expectations(thrown, this.remarks))
733
+ if (isMatcher(assertionOrMatcher)) {
734
+ assertionOrMatcher.expect(thrown)
735
+ } else if (assertionOrMatcher) {
736
+ assertionOrMatcher(new Expectations(thrown, this.remarks))
737
+ }
613
738
  }
614
739
 
615
740
  if (passed) this._fail('to throw')