From b11715187c9f9e501bb2d32a95c4ed14e0a05bd1 Mon Sep 17 00:00:00 2001 From: idango10 Date: Fri, 23 May 2025 20:28:54 +0300 Subject: [PATCH 1/9] test_runner: support object property mocking --- doc/api/test.md | 40 ++++++++ lib/internal/test_runner/mock/mock.js | 133 +++++++++++++++++++++++++- test/parallel/test-runner-mocking.js | 65 +++++++++++++ 3 files changed, 237 insertions(+), 1 deletion(-) diff --git a/doc/api/test.md b/doc/api/test.md index b13b4fdeb30cdb..5fdfd372085be5 100644 --- a/doc/api/test.md +++ b/doc/api/test.md @@ -2240,6 +2240,46 @@ test('mocks a builtin module in both module systems', async (t) => { }); ``` +### `mock.value(object, valueName, value)` + + + +* `object` {Object} The object whose value is being mocked. +* `valueName` {string|symbol} The identifier of the value on object to mock. +* `value` {any} A value used as the mock value for `object[valueName]`. + +Creates a mock for a property value on an object. This allows you to track and control access to a specific property, including how many times it is read (getter) or written (setter), and to restore the original value after mocking. + +```js +test('mocks a property value', (t) => { + const obj = { foo: 42 }; + const valueMock = t.mock.value(obj, 'foo', 100); + + assert.strictEqual(obj.foo, 100); + assert.strictEqual(valueMock.callGetterCount(), 1); + + obj.foo = 200; + assert.strictEqual(obj.foo, 200); + assert.strictEqual(valueMock.callSetterCount(), 1); + + valueMock.restore(); + assert.strictEqual(obj.foo, 42); +}); +``` + +The returned mock object provides the following methods: + +- `callGetterCount()`: Retrieves the number of times the property was read. +- `callSetterCount()`: Retrieves the number of times the property was written. +- `callCount()`: Retrieves the total number of times the property was accessed (getter or setter). +- `mockValue(value)`: Sets the current mock value. +- `resetCallGetters()`: Resets only the getter call count. +- `resetCallSetters()`: Resets only the setter call count. +- `resetCalls()`: Resets both getter and setter call counts. +- `restore()`: Restores the original property value and descriptor. + ### `mock.reset()` + +The `MockPropertyContext` class is used to inspect or manipulate the behavior +of property mocks created via the [`MockTracker`][] APIs. + +### `ctx.accesses` + +* {Array} + +A getter that returns a copy of the internal array used to track accesses (get/set) to +the mocked property. Each entry in the array is an object with the following properties: + +* `type` {string} Either `'get'` or `'set'`, indicating the type of access. +* `value` {any} The value that was read (for `'get'`) or written (for `'set'`). +* `stack` {Error} An `Error` object whose stack can be used to determine the + callsite of the mocked function invocation. + +### `ctx.accessCount()` + +* Returns: {integer} The number of times that the property was accessed (read or written). + +This function returns the number of times that the property was accessed. +This function is more efficient than checking `ctx.accesses.length` because +`ctx.accesses` is a getter that creates a copy of the internal access tracking array. + +### `ctx.mockImplementation(value)` + +* `value` {any} The new value to be set as the mocked property value. + +This function is used to change the value returned by the mocked property getter. + +### `ctx.resetAccesses()` + +Resets the access history of the mocked property. + +### `ctx.restore()` + +Resets the implementation of the mock property to its original behavior. The +mock can still be used after calling this function. + ## Class: `MockTracker` * `object` {Object} The object whose value is being mocked. -* `valueName` {string|symbol} The identifier of the value on object to mock. -* `value` {any} A value used as the mock value for `object[valueName]`. +* `propertyName` {string|symbol} The identifier of the property on `object` to mock. +* `value` {any} An optional value used as the mock value for `object[valueName]`. **Default:** The original property value. +* Returns: {Proxy} A proxy to the mocked object. The mocked object contains a + special `mock` property, which is an instance of [`MockPropertyContext`], and + can be used for inspecting and changing the behavior of the mocked property. Creates a mock for a property value on an object. This allows you to track and control access to a specific property, including how many times it is read (getter) or written (setter), and to restore the original value after mocking. @@ -2256,31 +2303,23 @@ including how many times it is read (getter) or written (setter), and to restore ```js test('mocks a property value', (t) => { const obj = { foo: 42 }; - const valueMock = t.mock.value(obj, 'foo', 100); + const prop = t.mock.property(obj, 'foo', 100); assert.strictEqual(obj.foo, 100); - assert.strictEqual(valueMock.callGetterCount(), 1); + assert.strictEqual(prop.mock.accessCount(), 1); + assert.strictEqual(prop.mock.accesses[0].type, 'get'); + assert.strictEqual(prop.mock.accesses[0].value, 100); obj.foo = 200; - assert.strictEqual(obj.foo, 200); - assert.strictEqual(valueMock.callSetterCount(), 1); + assert.strictEqual(prop.mock.accessCount(), 2); + assert.strictEqual(prop.mock.accesses[1].type, 'set'); + assert.strictEqual(prop.mock.accesses[1].value, 200); - valueMock.restore(); + prop.mock.restore(); assert.strictEqual(obj.foo, 42); }); ``` -The returned mock object provides the following methods: - -* `callGetterCount()`: Retrieves the number of times the property was read. -* `callSetterCount()`: Retrieves the number of times the property was written. -* `callCount()`: Retrieves the total number of times the property was accessed (getter or setter). -* `mockValue(value)`: Sets the current mock value. -* `resetCallGetters()`: Resets only the getter call count. -* `resetCallSetters()`: Resets only the setter call count. -* `resetCalls()`: Resets both getter and setter call counts. -* `restore()`: Restores the original property value and descriptor. - ### `mock.reset()`