@vitest/expect 2.1.5 → 2.2.0-beta.2

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.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { MockInstance } from '@vitest/spy';
1
2
  import { stringify, Constructable } from '@vitest/utils';
2
3
  import * as tinyrainbow from 'tinyrainbow';
3
4
  import { Formatter } from 'tinyrainbow';
@@ -549,6 +550,14 @@ interface Assertion<T = any> extends VitestAssertion<Chai.Assertion, T>, JestAss
549
550
  * expect(mockFunc).toHaveBeenCalledOnce();
550
551
  */
551
552
  toHaveBeenCalledOnce: () => void;
553
+ /**
554
+ * Ensure that a mock function is called with specific arguments and called
555
+ * exactly once.
556
+ *
557
+ * @example
558
+ * expect(mockFunc).toHaveBeenCalledExactlyOnceWith('arg1', 42);
559
+ */
560
+ toHaveBeenCalledExactlyOnceWith: <E extends any[]>(...args: E) => void;
552
561
  /**
553
562
  * Checks that a value satisfies a custom matcher function.
554
563
  *
@@ -559,6 +568,36 @@ interface Assertion<T = any> extends VitestAssertion<Chai.Assertion, T>, JestAss
559
568
  * expect(age).toSatisfy(val => val >= 18, 'Age must be at least 18');
560
569
  */
561
570
  toSatisfy: <E>(matcher: (value: E) => boolean, message?: string) => void;
571
+ /**
572
+ * This assertion checks if a `Mock` was called before another `Mock`.
573
+ * @param mock - A mock function created by `vi.spyOn` or `vi.fn`
574
+ * @param failIfNoFirstInvocation - Fail if the first mock was never called
575
+ * @example
576
+ * const mock1 = vi.fn()
577
+ * const mock2 = vi.fn()
578
+ *
579
+ * mock1()
580
+ * mock2()
581
+ * mock1()
582
+ *
583
+ * expect(mock1).toHaveBeenCalledBefore(mock2)
584
+ */
585
+ toHaveBeenCalledBefore: (mock: MockInstance, failIfNoFirstInvocation?: boolean) => void;
586
+ /**
587
+ * This assertion checks if a `Mock` was called after another `Mock`.
588
+ * @param mock - A mock function created by `vi.spyOn` or `vi.fn`
589
+ * @param failIfNoFirstInvocation - Fail if the first mock was never called
590
+ * @example
591
+ * const mock1 = vi.fn()
592
+ * const mock2 = vi.fn()
593
+ *
594
+ * mock2()
595
+ * mock1()
596
+ * mock2()
597
+ *
598
+ * expect(mock1).toHaveBeenCalledAfter(mock2)
599
+ */
600
+ toHaveBeenCalledAfter: (mock: MockInstance, failIfNoFirstInvocation?: boolean) => void;
562
601
  /**
563
602
  * Checks that a promise resolves successfully at least once.
564
603
  *
package/dist/index.js CHANGED
@@ -1465,6 +1465,25 @@ const JestChaiExpect = (chai, utils) => {
1465
1465
  throw new AssertionError(formatCalls(spy, msg, args));
1466
1466
  }
1467
1467
  });
1468
+ def("toHaveBeenCalledExactlyOnceWith", function(...args) {
1469
+ const spy = getSpy(this);
1470
+ const spyName = spy.getMockName();
1471
+ const callCount = spy.mock.calls.length;
1472
+ const hasCallWithArgs = spy.mock.calls.some(
1473
+ (callArg) => equals(callArg, args, [...customTesters, iterableEquality])
1474
+ );
1475
+ const pass = hasCallWithArgs && callCount === 1;
1476
+ const isNot = utils.flag(this, "negate");
1477
+ const msg = utils.getMessage(this, [
1478
+ pass,
1479
+ `expected "${spyName}" to be called once with arguments: #{exp}`,
1480
+ `expected "${spyName}" to not be called once with arguments: #{exp}`,
1481
+ args
1482
+ ]);
1483
+ if (pass && isNot || !pass && !isNot) {
1484
+ throw new AssertionError(formatCalls(spy, msg, args));
1485
+ }
1486
+ });
1468
1487
  def(
1469
1488
  ["toHaveBeenNthCalledWith", "nthCalledWith"],
1470
1489
  function(times, ...args) {
@@ -1502,6 +1521,61 @@ const JestChaiExpect = (chai, utils) => {
1502
1521
  );
1503
1522
  }
1504
1523
  );
1524
+ function isSpyCalledBeforeAnotherSpy(beforeSpy, afterSpy, failIfNoFirstInvocation) {
1525
+ const beforeInvocationCallOrder = beforeSpy.mock.invocationCallOrder;
1526
+ const afterInvocationCallOrder = afterSpy.mock.invocationCallOrder;
1527
+ if (beforeInvocationCallOrder.length === 0) {
1528
+ return !failIfNoFirstInvocation;
1529
+ }
1530
+ if (afterInvocationCallOrder.length === 0) {
1531
+ return false;
1532
+ }
1533
+ return beforeInvocationCallOrder[0] < afterInvocationCallOrder[0];
1534
+ }
1535
+ def(
1536
+ ["toHaveBeenCalledBefore"],
1537
+ function(resultSpy, failIfNoFirstInvocation = true) {
1538
+ const expectSpy = getSpy(this);
1539
+ if (!isMockFunction(resultSpy)) {
1540
+ throw new TypeError(
1541
+ `${utils.inspect(resultSpy)} is not a spy or a call to a spy`
1542
+ );
1543
+ }
1544
+ this.assert(
1545
+ isSpyCalledBeforeAnotherSpy(
1546
+ expectSpy,
1547
+ resultSpy,
1548
+ failIfNoFirstInvocation
1549
+ ),
1550
+ `expected "${expectSpy.getMockName()}" to have been called before "${resultSpy.getMockName()}"`,
1551
+ `expected "${expectSpy.getMockName()}" to not have been called before "${resultSpy.getMockName()}"`,
1552
+ resultSpy,
1553
+ expectSpy
1554
+ );
1555
+ }
1556
+ );
1557
+ def(
1558
+ ["toHaveBeenCalledAfter"],
1559
+ function(resultSpy, failIfNoFirstInvocation = true) {
1560
+ const expectSpy = getSpy(this);
1561
+ if (!isMockFunction(resultSpy)) {
1562
+ throw new TypeError(
1563
+ `${utils.inspect(resultSpy)} is not a spy or a call to a spy`
1564
+ );
1565
+ }
1566
+ this.assert(
1567
+ isSpyCalledBeforeAnotherSpy(
1568
+ resultSpy,
1569
+ expectSpy,
1570
+ failIfNoFirstInvocation
1571
+ ),
1572
+ `expected "${expectSpy.getMockName()}" to have been called after "${resultSpy.getMockName()}"`,
1573
+ `expected "${expectSpy.getMockName()}" to not have been called after "${resultSpy.getMockName()}"`,
1574
+ resultSpy,
1575
+ expectSpy
1576
+ );
1577
+ }
1578
+ );
1505
1579
  def(
1506
1580
  ["toThrow", "toThrowError"],
1507
1581
  function(expected) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/expect",
3
3
  "type": "module",
4
- "version": "2.1.5",
4
+ "version": "2.2.0-beta.2",
5
5
  "description": "Jest's expect matchers as a Chai plugin",
6
6
  "license": "MIT",
7
7
  "funding": "https://opencollective.com/vitest",
@@ -32,13 +32,13 @@
32
32
  "dependencies": {
33
33
  "chai": "^5.1.2",
34
34
  "tinyrainbow": "^1.2.0",
35
- "@vitest/utils": "2.1.5",
36
- "@vitest/spy": "2.1.5"
35
+ "@vitest/spy": "2.2.0-beta.2",
36
+ "@vitest/utils": "2.2.0-beta.2"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/chai": "4.3.6",
40
40
  "rollup-plugin-copy": "^3.5.0",
41
- "@vitest/runner": "2.1.5"
41
+ "@vitest/runner": "2.2.0-beta.2"
42
42
  },
43
43
  "scripts": {
44
44
  "build": "rimraf dist && rollup -c",