@@ -1971,6 +1971,87 @@ added: v22.3.0
19711971
19721972Resets the implementation of the mock module.
19731973
1974+ ## Class: ` MockPropertyContext `
1975+
1976+ <!-- YAML
1977+ added: REPLACEME
1978+ -->
1979+
1980+ The ` MockPropertyContext ` class is used to inspect or manipulate the behavior
1981+ of property mocks created via the [ ` MockTracker ` ] [ ] APIs.
1982+
1983+ ### ` ctx.accesses `
1984+
1985+ * {Array}
1986+
1987+ A getter that returns a copy of the internal array used to track accesses (get/set) to
1988+ the mocked property. Each entry in the array is an object with the following properties:
1989+
1990+ * ` type ` {string} Either ` 'get' ` or ` 'set' ` , indicating the type of access.
1991+ * ` value ` {any} The value that was read (for ` 'get' ` ) or written (for ` 'set' ` ).
1992+ * ` stack ` {Error} An ` Error ` object whose stack can be used to determine the
1993+ callsite of the mocked function invocation.
1994+
1995+ ### ` ctx.accessCount() `
1996+
1997+ * Returns: {integer} The number of times that the property was accessed (read or written).
1998+
1999+ This function returns the number of times that the property was accessed.
2000+ This function is more efficient than checking ` ctx.accesses.length ` because
2001+ ` ctx.accesses ` is a getter that creates a copy of the internal access tracking array.
2002+
2003+ ### ` ctx.mockImplementation(value) `
2004+
2005+ * ` value ` {any} The new value to be set as the mocked property value.
2006+
2007+ This function is used to change the value returned by the mocked property getter.
2008+
2009+ ### ` ctx.mockImplementationOnce(value[, onAccess]) `
2010+
2011+ * ` value ` {any} The value to be used as the mock's
2012+ implementation for the invocation number specified by ` onAccess ` .
2013+ * ` onAccess ` {integer} The invocation number that will use ` value ` . If
2014+ the specified invocation has already occurred then an exception is thrown.
2015+ ** Default:** The number of the next invocation.
2016+
2017+ This function is used to change the behavior of an existing mock for a single
2018+ invocation. Once invocation ` onAccess ` has occurred, the mock will revert to
2019+ whatever behavior it would have used had ` mockImplementationOnce() ` not been
2020+ called.
2021+
2022+ The following example creates a mock function using ` t.mock.property() ` , calls the
2023+ mock property, changes the mock implementation to a different value for the
2024+ next invocation, and then resumes its previous behavior.
2025+
2026+ ``` js
2027+ test (' changes a mock behavior once' , (t ) => {
2028+ const obj = { foo: 1 };
2029+
2030+ const prop = t .mock .property (obj, ' foo' , 5 );
2031+
2032+ assert .strictEqual (obj .foo , 5 );
2033+ prop .mock .mockImplementationOnce (25 );
2034+ assert .strictEqual (obj .foo , 25 );
2035+ assert .strictEqual (obj .foo , 5 );
2036+ });
2037+ ```
2038+
2039+ #### Caveat
2040+
2041+ For consistency with the rest of the mocking API, this function treats both property gets and sets
2042+ as accesses. If a property set occurs at the same access index, the "once" value will be consumed
2043+ by the set operation, and the mocked property value will be changed to the "once" value. This may
2044+ lead to unexpected behavior if you intend the "once" value to only be used for a get operation.
2045+
2046+ ### ` ctx.resetAccesses() `
2047+
2048+ Resets the access history of the mocked property.
2049+
2050+ ### ` ctx.restore() `
2051+
2052+ Resets the implementation of the mock property to its original behavior. The
2053+ mock can still be used after calling this function.
2054+
19742055## Class: ` MockTracker `
19752056
19762057<!-- YAML
@@ -2173,6 +2254,43 @@ test('mocks a builtin module in both module systems', async (t) => {
21732254});
21742255```
21752256
2257+ ### ` mock.property(object, propertyName[, value]) `
2258+
2259+ <!-- YAML
2260+ added: REPLACEME
2261+ -->
2262+
2263+ * ` object ` {Object} The object whose value is being mocked.
2264+ * ` propertyName ` {string|symbol} The identifier of the property on ` object ` to mock.
2265+ * ` value ` {any} An optional value used as the mock value
2266+ for ` object[propertyName] ` . ** Default:** The original property value.
2267+ * Returns: {Proxy} A proxy to the mocked object. The mocked object contains a
2268+ special ` mock ` property, which is an instance of [ ` MockPropertyContext ` ] [ ] , and
2269+ can be used for inspecting and changing the behavior of the mocked property.
2270+
2271+ Creates a mock for a property value on an object. This allows you to track and control access to a specific property,
2272+ including how many times it is read (getter) or written (setter), and to restore the original value after mocking.
2273+
2274+ ``` js
2275+ test (' mocks a property value' , (t ) => {
2276+ const obj = { foo: 42 };
2277+ const prop = t .mock .property (obj, ' foo' , 100 );
2278+
2279+ assert .strictEqual (obj .foo , 100 );
2280+ assert .strictEqual (prop .mock .accessCount (), 1 );
2281+ assert .strictEqual (prop .mock .accesses [0 ].type , ' get' );
2282+ assert .strictEqual (prop .mock .accesses [0 ].value , 100 );
2283+
2284+ obj .foo = 200 ;
2285+ assert .strictEqual (prop .mock .accessCount (), 2 );
2286+ assert .strictEqual (prop .mock .accesses [1 ].type , ' set' );
2287+ assert .strictEqual (prop .mock .accesses [1 ].value , 200 );
2288+
2289+ prop .mock .restore ();
2290+ assert .strictEqual (obj .foo , 42 );
2291+ });
2292+ ```
2293+
21762294### ` mock.reset() `
21772295
21782296<!-- YAML
@@ -3703,6 +3821,7 @@ Can be used to abort test subtasks when the test has been aborted.
37033821[ `--test-update-snapshots` ] : cli.md#--test-update-snapshots
37043822[ `--test` ] : cli.md#--test
37053823[ `MockFunctionContext` ] : #class-mockfunctioncontext
3824+ [ `MockPropertyContext` ] : #class-mockpropertycontext
37063825[ `MockTimers` ] : #class-mocktimers
37073826[ `MockTracker.method` ] : #mockmethodobject-methodname-implementation-options
37083827[ `MockTracker` ] : #class-mocktracker
0 commit comments