| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 86e22b4 commit 6158d74
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -352,6 +352,89 @@ Otherwise, the test is considered to be a failure. Test files must be | |||
| 352 | 352 | executable by Node.js, but are not required to use the `node:test` module | |
| 353 | 353 | internally. | |
| 354 | 354 | ||
| 355 | + ## Mocking | ||
| 356 | + | ||
| 357 | + The `node:test` module supports mocking during testing via a top-level `mock` | ||
| 358 | + object. The following example creates a spy on a function that adds two numbers | ||
| 359 | + together. The spy is then used to assert that the function was called as | ||
| 360 | + expected. | ||
| 361 | + | ||
| 362 | + ```mjs | ||
| 363 | + import assert from 'node:assert'; | ||
| 364 | + import { mock, test } from 'node:test'; | ||
| 365 | + | ||
| 366 | + test('spies on a function', () => { | ||
| 367 | + const sum = mock.fn((a, b) => { | ||
| 368 | + return a + b; | ||
| 369 | + }); | ||
| 370 | + | ||
| 371 | + assert.strictEqual(sum.mock.calls.length, 0); | ||
| 372 | + assert.strictEqual(sum(3, 4), 7); | ||
| 373 | + assert.strictEqual(sum.mock.calls.length, 1); | ||
| 374 | + | ||
| 375 | + const call = sum.mock.calls[0]; | ||
| 376 | + assert.deepStrictEqual(call.arguments, [3, 4]); | ||
| 377 | + assert.strictEqual(call.result, 7); | ||
| 378 | + assert.strictEqual(call.error, undefined); | ||
| 379 | + | ||
| 380 | + // Reset the globally tracked mocks. | ||
| 381 | + mock.reset(); | ||
| 382 | + }); | ||
| 383 | + ``` | ||
| 384 | + | ||
| 385 | + ```cjs | ||
| 386 | + 'use strict'; | ||
| 387 | + const assert = require('node:assert'); | ||
| 388 | + const { mock, test } = require('node:test'); | ||
| 389 | + | ||
| 390 | + test('spies on a function', () => { | ||
| 391 | + const sum = mock.fn((a, b) => { | ||
| 392 | + return a + b; | ||
| 393 | + }); | ||
| 394 | + | ||
| 395 | + assert.strictEqual(sum.mock.calls.length, 0); | ||
| 396 | + assert.strictEqual(sum(3, 4), 7); | ||
| 397 | + assert.strictEqual(sum.mock.calls.length, 1); | ||
| 398 | + | ||
| 399 | + const call = sum.mock.calls[0]; | ||
| 400 | + assert.deepStrictEqual(call.arguments, [3, 4]); | ||
| 401 | + assert.strictEqual(call.result, 7); | ||
| 402 | + assert.strictEqual(call.error, undefined); | ||
| 403 | + | ||
| 404 | + // Reset the globally tracked mocks. | ||
| 405 | + mock.reset(); | ||
| 406 | + }); | ||
| 407 | + ``` | ||
| 408 | + | ||
| 409 | + The same mocking functionality is also exposed on the [`TestContext`][] object | ||
| 410 | + of each test. The following example creates a spy on an object method using the | ||
| 411 | + API exposed on the `TestContext`. The benefit of mocking via the test context is | ||
| 412 | + that the test runner will automatically restore all mocked functionality once | ||
| 413 | + the test finishes. | ||
| 414 | + | ||
| 415 | + ```js | ||
| 416 | + test('spies on an object method', (t) => { | ||
| 417 | + const number = { | ||
| 418 | + value: 5, | ||
| 419 | + add(a) { | ||
| 420 | + return this.value + a; | ||
| 421 | + }, | ||
| 422 | + }; | ||
| 423 | + | ||
| 424 | + t.mock.method(number, 'add'); | ||
| 425 | + assert.strictEqual(number.add.mock.calls.length, 0); | ||
| 426 | + assert.strictEqual(number.add(3), 8); | ||
| 427 | + assert.strictEqual(number.add.mock.calls.length, 1); | ||
| 428 | + | ||
| 429 | + const call = number.add.mock.calls[0]; | ||
| 430 | + | ||
| 431 | + assert.deepStrictEqual(call.arguments, [3]); | ||
| 432 | + assert.strictEqual(call.result, 8); | ||
| 433 | + assert.strictEqual(call.target, undefined); | ||
| 434 | + assert.strictEqual(call.this, number); | ||
| 435 | + }); | ||
| 436 | + ``` | ||
| 437 | + | ||
| 355 | 438 | ## `run([options])` | |
| 356 | 439 | ||
| 357 | 440 | <!-- YAML | |
@@ -644,6 +727,281 @@ describe('tests', async () => { | |||
| 644 | 727 | }); | |
| 645 | 728 | ``` | |
| 646 | 729 | ||
| 730 | + ## Class: `MockFunctionContext` | ||
| 731 | + | ||
| 732 | + <!-- YAML | ||
| 733 | + added: REPLACEME | ||
| 734 | + --> | ||
| 735 | + | ||
| 736 | + The `MockFunctionContext` class is used to inspect or manipulate the behavior of | ||
| 737 | + mocks created via the [`MockTracker`][] APIs. | ||
| 738 | + | ||
| 739 | + ### `ctx.calls` | ||
| 740 | + | ||
| 741 | + <!-- YAML | ||
| 742 | + added: REPLACEME | ||
| 743 | + --> | ||
| 744 | + | ||
| 745 | + * {Array} | ||
| 746 | + | ||
| 747 | + A getter that returns a copy of the internal array used to track calls to the | ||
| 748 | + mock. Each entry in the array is an object with the following properties. | ||
| 749 | + | ||
| 750 | + * `arguments` {Array} An array of the arguments passed to the mock function. | ||
| 751 | + * `error` {any} If the mocked function threw then this property contains the | ||
| 752 | + thrown value. **Default:** `undefined`. | ||
| 753 | + * `result` {any} The value returned by the mocked function. | ||
| 754 | + * `stack` {Error} An `Error` object whose stack can be used to determine the | ||
| 755 | + callsite of the mocked function invocation. | ||
| 756 | + * `target` {Function|undefined} If the mocked function is a constructor, this | ||
| 757 | + field contains the class being constructed. Otherwise this will be | ||
| 758 | + `undefined`. | ||
| 759 | + * `this` {any} The mocked function's `this` value. | ||
| 760 | + | ||
| 761 | + ### `ctx.callCount()` | ||
| 762 | + | ||
| 763 | + <!-- YAML | ||
| 764 | + added: REPLACEME | ||
| 765 | + --> | ||
| 766 | + | ||
| 767 | + * Returns: {integer} The number of times that this mock has been invoked. | ||
| 768 | + | ||
| 769 | + This function returns the number of times that this mock has been invoked. This | ||
| 770 | + function is more efficient than checking `ctx.calls.length` because `ctx.calls` | ||
| 771 | + is a getter that creates a copy of the internal call tracking array. | ||
| 772 | + | ||
| 773 | + ### `ctx.mockImplementation(implementation)` | ||
| 774 | + | ||
| 775 | + <!-- YAML | ||
| 776 | + added: REPLACEME | ||
| 777 | + --> | ||
| 778 | + | ||
| 779 | + * `implementation` {Function|AsyncFunction} The function to be used as the | ||
| 780 | + mock's new implementation. | ||
| 781 | + | ||
| 782 | + This function is used to change the behavior of an existing mock. | ||
| 783 | + | ||
| 784 | + The following example creates a mock function using `t.mock.fn()`, calls the | ||
| 785 | + mock function, and then changes the mock implementation to a different function. | ||
| 786 | + | ||
| 787 | + ```js | ||
| 788 | + test('changes a mock behavior', (t) => { | ||
| 789 | + let cnt = 0; | ||
| 790 | + | ||
| 791 | + function addOne() { | ||
| 792 | + cnt++; | ||
| 793 | + return cnt; | ||
| 794 | + } | ||
| 795 | + | ||
| 796 | + function addTwo() { | ||
| 797 | + cnt += 2; | ||
| 798 | + return cnt; | ||
| 799 | + } | ||
| 800 | + | ||
| 801 | + const fn = t.mock.fn(addOne); | ||
| 802 | + | ||
| 803 | + assert.strictEqual(fn(), 1); | ||
| 804 | + fn.mock.mockImplementation(addTwo); | ||
| 805 | + assert.strictEqual(fn(), 3); | ||
| 806 | + assert.strictEqual(fn(), 5); | ||
| 807 | + }); | ||
| 808 | + ``` | ||
| 809 | + | ||
| 810 | + ### `ctx.mockImplementationOnce(implementation[, onCall])` | ||
| 811 | + | ||
| 812 | + <!-- YAML | ||
| 813 | + added: REPLACEME | ||
| 814 | + --> | ||
| 815 | + | ||
| 816 | + * `implementation` {Function|AsyncFunction} The function to be used as the | ||
| 817 | + mock's implementation for the invocation number specified by `onCall`. | ||
| 818 | + * `onCall` {integer} The invocation number that will use `implementation`. If | ||
| 819 | + the specified invocation has already occurred then an exception is thrown. | ||
| 820 | + **Default:** The number of the next invocation. | ||
| 821 | + | ||
| 822 | + This function is used to change the behavior of an existing mock for a single | ||
| 823 | + invocation. Once invocation `onCall` has occurred, the mock will revert to | ||
| 824 | + whatever behavior it would have used had `mockImplementationOnce()` not been | ||
| 825 | + called. | ||
| 826 | + | ||
| 827 | + The following example creates a mock function using `t.mock.fn()`, calls the | ||
| 828 | + mock function, changes the mock implementation to a different function for the | ||
| 829 | + next invocation, and then resumes its previous behavior. | ||
| 830 | + | ||
| 831 | + ```js | ||
| 832 | + test('changes a mock behavior once', (t) => { | ||
| 833 | + let cnt = 0; | ||
| 834 | + | ||
| 835 | + function addOne() { | ||
| 836 | + cnt++; | ||
| 837 | + return cnt; | ||
| 838 | + } | ||
| 839 | + | ||
| 840 | + function addTwo() { | ||
| 841 | + cnt += 2; | ||
| 842 | + return cnt; | ||
| 843 | + } | ||
| 844 | + | ||
| 845 | + const fn = t.mock.fn(addOne); | ||
| 846 | + | ||
| 847 | + assert.strictEqual(fn(), 1); | ||
| 848 | + fn.mock.mockImplementationOnce(addTwo); | ||
| 849 | + assert.strictEqual(fn(), 3); | ||
| 850 | + assert.strictEqual(fn(), 4); | ||
| 851 | + }); | ||
| 852 | + ``` | ||
| 853 | + | ||
| 854 | + ### `ctx.restore()` | ||
| 855 | + | ||
| 856 | + <!-- YAML | ||
| 857 | + added: REPLACEME | ||
| 858 | + --> | ||
| 859 | + | ||
| 860 | + Resets the implementation of the mock function to its original behavior. The | ||
| 861 | + mock can still be used after calling this function. | ||
| 862 | + | ||
| 863 | + ## Class: `MockTracker` | ||
| 864 | + | ||
| 865 | + <!-- YAML | ||
| 866 | + added: REPLACEME | ||
| 867 | + --> | ||
| 868 | + | ||
| 869 | + The `MockTracker` class is used to manage mocking functionality. The test runner | ||
| 870 | + module provides a top level `mock` export which is a `MockTracker` instance. | ||
| 871 | + Each test also provides its own `MockTracker` instance via the test context's | ||
| 872 | + `mock` property. | ||
| 873 | + | ||
| 874 | + ### `mock.fn([original[, implementation]][, options])` | ||
| 875 | + | ||
| 876 | + <!-- YAML | ||
| 877 | + added: REPLACEME | ||
| 878 | + --> | ||
| 879 | + | ||
| 880 | + * `original` {Function|AsyncFunction} An optional function to create a mock on. | ||
| 881 | + **Default:** A no-op function. | ||
| 882 | + * `implementation` {Function|AsyncFunction} An optional function used as the | ||
| 883 | + mock implementation for `original`. This is useful for creating mocks that | ||
| 884 | + exhibit one behavior for a specified number of calls and then restore the | ||
| 885 | + behavior of `original`. **Default:** The function specified by `original`. | ||
| 886 | + * `options` {Object} Optional configuration options for the mock function. The | ||
| 887 | + following properties are supported: | ||
| 888 | + * `times` {integer} The number of times that the mock will use the behavior of | ||
| 889 | + `implementation`. Once the mock function has been called `times` times, it | ||
| 890 | + will automatically restore the behavior of `original`. This value must be an | ||
| 891 | + integer greater than zero. **Default:** `Infinity`. | ||
| 892 | + * Returns: {Proxy} The mocked function. The mocked function contains a special | ||
| 893 | + `mock` property, which is an instance of [`MockFunctionContext`][], and can | ||
| 894 | + be used for inspecting and changing the behavior of the mocked function. | ||
| 895 | + | ||
| 896 | + This function is used to create a mock function. | ||
| 897 | + | ||
| 898 | + The following example creates a mock function that increments a counter by one | ||
| 899 | + on each invocation. The `times` option is used to modify the mock behavior such | ||
| 900 | + that the first two invocations add two to the counter instead of one. | ||
| 901 | + | ||
| 902 | + ```js | ||
| 903 | + test('mocks a counting function', (t) => { | ||
| 904 | + let cnt = 0; | ||
| 905 | + | ||
| 906 | + function addOne() { | ||
| 907 | + cnt++; | ||
| 908 | + return cnt; | ||
| 909 | + } | ||
| 910 | + | ||
| 911 | + function addTwo() { | ||
| 912 | + cnt += 2; | ||
| 913 | + return cnt; | ||
| 914 | + } | ||
| 915 | + | ||
| 916 | + const fn = t.mock.fn(addOne, addTwo, { times: 2 }); | ||
| 917 | + | ||
| 918 | + assert.strictEqual(fn(), 2); | ||
| 919 | + assert.strictEqual(fn(), 4); | ||
| 920 | + assert.strictEqual(fn(), 5); | ||
| 921 | + assert.strictEqual(fn(), 6); | ||
| 922 | + }); | ||
| 923 | + ``` | ||
| 924 | + | ||
| 925 | + ### `mock.method(object, methodName[, implementation][, options])` | ||
| 926 | + | ||
| 927 | + <!-- YAML | ||
| 928 | + added: REPLACEME | ||
| 929 | + --> | ||
| 930 | + | ||
| 931 | + * `object` {Object} The object whose method is being mocked. | ||
| 932 | + * `methodName` {string|symbol} The identifier of the method on `object` to mock. | ||
| 933 | + If `object[methodName]` is not a function, an error is thrown. | ||
| 934 | + * `implementation` {Function|AsyncFunction} An optional function used as the | ||
| 935 | + mock implementation for `object[methodName]`. **Default:** The original method | ||
| 936 | + specified by `object[methodName]`. | ||
| 937 | + * `options` {Object} Optional configuration options for the mock method. The | ||
| 938 | + following properties are supported: | ||
| 939 | + * `getter` {boolean} If `true`, `object[methodName]` is treated as a getter. | ||
| 940 | + This option cannot be used with the `setter` option. **Default:** false. | ||
| 941 | + * `setter` {boolean} If `true`, `object[methodName]` is treated as a setter. | ||
| 942 | + This option cannot be used with the `getter` option. **Default:** false. | ||
| 943 | + * `times` {integer} The number of times that the mock will use the behavior of | ||
| 944 | + `implementation`. Once the mocked method has been called `times` times, it | ||
| 945 | + will automatically restore the original behavior. This value must be an | ||
| 946 | + integer greater than zero. **Default:** `Infinity`. | ||
| 947 | + * Returns: {Proxy} The mocked method. The mocked method contains a special | ||
| 948 | + `mock` property, which is an instance of [`MockFunctionContext`][], and can | ||
| 949 | + be used for inspecting and changing the behavior of the mocked method. | ||
| 950 | + | ||
| 951 | + This function is used to create a mock on an existing object method. The | ||
| 952 | + following example demonstrates how a mock is created on an existing object | ||
| 953 | + method. | ||
| 954 | + | ||
| 955 | + ```js | ||
| 956 | + test('spies on an object method', (t) => { | ||
| 957 | + const number = { | ||
| 958 | + value: 5, | ||
| 959 | + subtract(a) { | ||
| 960 | + return this.value - a; | ||
| 961 | + }, | ||
| 962 | + }; | ||
| 963 | + | ||
| 964 | + t.mock.method(number, 'subtract'); | ||
| 965 | + assert.strictEqual(number.subtract.mock.calls.length, 0); | ||
| 966 | + assert.strictEqual(number.subtract(3), 2); | ||
| 967 | + assert.strictEqual(number.subtract.mock.calls.length, 1); | ||
| 968 | + | ||
| 969 | + const call = number.subtract.mock.calls[0]; | ||
| 970 | + | ||
| 971 | + assert.deepStrictEqual(call.arguments, [3]); | ||
| 972 | + assert.strictEqual(call.result, 2); | ||
| 973 | + assert.strictEqual(call.error, undefined); | ||
| 974 | + assert.strictEqual(call.target, undefined); | ||
| 975 | + assert.strictEqual(call.this, number); | ||
| 976 | + }); | ||
| 977 | + ``` | ||
| 978 | + | ||
| 979 | + ### `mock.reset()` | ||
| 980 | + | ||
| 981 | + <!-- YAML | ||
| 982 | + added: REPLACEME | ||
| 983 | + --> | ||
| 984 | + | ||
| 985 | + This function restores the default behavior of all mocks that were previously | ||
| 986 | + created by this `MockTracker` and disassociates the mocks from the | ||
| 987 | + `MockTracker` instance. Once disassociated, the mocks can still be used, but the | ||
| 988 | + `MockTracker` instance can no longer be used to reset their behavior or | ||
| 989 | + otherwise interact with them. | ||
| 990 | + | ||
| 991 | + After each test completes, this function is called on the test context's | ||
| 992 | + `MockTracker`. If the global `MockTracker` is used extensively, calling this | ||
| 993 | + function manually is recommended. | ||
| 994 | + | ||
| 995 | + ### `mock.restoreAll()` | ||
| 996 | + | ||
| 997 | + <!-- YAML | ||
| 998 | + added: REPLACEME | ||
| 999 | + --> | ||
| 1000 | + | ||
| 1001 | + This function restores the default behavior of all mocks that were previously | ||
| 1002 | + created by this `MockTracker`. Unlike `mock.reset()`, `mock.restoreAll()` does | ||
| 1003 | + not disassociate the mocks from the `MockTracker` instance. | ||
| 1004 | + | ||
| 647 | 1005 | ## Class: `TapStream` | |
| 648 | 1006 | ||
| 649 | 1007 | <!-- YAML | |
@@ -979,6 +1337,8 @@ added: | |||
| 979 | 1337 | [`--test-name-pattern`]: cli.md#--test-name-pattern | |
| 980 | 1338 | [`--test-only`]: cli.md#--test-only | |
| 981 | 1339 | [`--test`]: cli.md#--test | |
| 1340 | + [`MockFunctionContext`]: #class-mockfunctioncontext | ||
| 1341 | + [`MockTracker`]: #class-mocktracker | ||
| 982 | 1342 | [`SuiteContext`]: #class-suitecontext | |
| 983 | 1343 | [`TestContext`]: #class-testcontext | |
| 984 | 1344 | [`context.diagnostic`]: #contextdiagnosticmessage | |
| Back | FazBrowse Home | New Git URL |
0 commit comments