mock-property
Advanced tools
Comparing version 1.0.3 to 1.1.0
@@ -8,2 +8,16 @@ # Changelog | ||
## [v1.1.0](https://github.com/ljharb/mock-property/compare/v1.0.3...v1.1.0) - 2024-08-06 | ||
### Commits | ||
- [Tests] refactor tests for easier testing of multiple properties [`605c32e`](https://github.com/ljharb/mock-property/commit/605c32e8bc3c53320fe9c5eb7fd3836c55607443) | ||
- [New] add types [`848be58`](https://github.com/ljharb/mock-property/commit/848be58428a8d17d46d083c8978138c432b7dfeb) | ||
- [Fix] properly stringify Symbol properties [`369d824`](https://github.com/ljharb/mock-property/commit/369d8247d1dd840390a1f6bfe6afa239023b0e37) | ||
- [Fix] avoid a crash when mocking a nonexistent data property as non-enumerable sans a value [`9994626`](https://github.com/ljharb/mock-property/commit/99946267704fd87f9044372ce016b48f4edb8081) | ||
- [Dev Deps] update `@ljharb/eslint-config`, `aud`,` npmignore`, `object-inspect`, `tape` [`ebfaf9a`](https://github.com/ljharb/mock-property/commit/ebfaf9a2c3882fb1adcbd68df418c134cd39e85e) | ||
- [Dev Deps] ensure tape’s mock-property is ourself, for testing [`2deaf72`](https://github.com/ljharb/mock-property/commit/2deaf72e8cb486b6044f9fb3a142f321107e7939) | ||
- [Deps] update `define-data-property`, `has-property-descriptors`, `hasown` [`e9f503d`](https://github.com/ljharb/mock-property/commit/e9f503dd782f2d6c8531f4020a9a275badcb6d0c) | ||
- [Tests] switch from `aud` to `npm audit` [`f5e6ce2`](https://github.com/ljharb/mock-property/commit/f5e6ce2b80d978aa7b6f8af38446ee67c1ae44ce) | ||
- [meta] add `sideEffects` flag [`2089940`](https://github.com/ljharb/mock-property/commit/2089940cb0717102275bbac85708e9bf74d732e0) | ||
## [v1.0.3](https://github.com/ljharb/mock-property/compare/v1.0.2...v1.0.3) - 2023-10-20 | ||
@@ -10,0 +24,0 @@ |
37
index.js
@@ -9,2 +9,3 @@ 'use strict'; | ||
var defineDataProperty = require('define-data-property'); | ||
var inspect = require('object-inspect'); | ||
@@ -19,2 +20,3 @@ var hasDescriptors = hasPropertyDescriptors(); | ||
/** @type {import('.')} */ | ||
module.exports = function mockProperty(obj, prop, options) { | ||
@@ -65,4 +67,4 @@ if (hasOwn(options, 'nonEnumerable') && typeof options.nonEnumerable !== 'boolean') { | ||
var origConfigurable = origDescriptor ? origDescriptor.configurable : true; | ||
var origEnumerable = origDescriptor ? origDescriptor.enumerable : true; | ||
var origConfigurable = origDescriptor ? !!origDescriptor.configurable : true; | ||
var origEnumerable = origDescriptor ? !!origDescriptor.enumerable : true; | ||
@@ -82,7 +84,7 @@ if (wantsAccessor) { | ||
if (isChangingEnumerability) { | ||
throw new $TypeError('`' + prop + '` is nonconfigurable, and can not be changed'); | ||
throw new $TypeError('`' + inspect(prop) + '` is nonconfigurable, and can not be changed'); | ||
} | ||
if (wantsAccessor) { | ||
if (hasOwn(origDescriptor, 'value')) { | ||
throw new $TypeError('`' + prop + '` is a nonconfigurable data property, and can not be changed to an accessor'); | ||
throw new $TypeError('`' + inspect(prop) + '` is a nonconfigurable data property, and can not be changed to an accessor'); | ||
} | ||
@@ -94,3 +96,3 @@ | ||
if (isChangingGetter || isChangingSetter) { | ||
throw new $TypeError('`' + prop + '` is nonconfigurable, and can not be changed'); | ||
throw new $TypeError('`' + inspect(prop) + '` is nonconfigurable, and can not be changed'); | ||
} | ||
@@ -100,3 +102,3 @@ return function restore() {}; | ||
if (hasOwn(origDescriptor, 'get') || hasOwn(origDescriptor, 'set')) { | ||
throw new $TypeError('`' + prop + '` is a nonconfigurable accessor property, and can not be changed to a data property'); | ||
throw new $TypeError('`' + inspect(prop) + '` is a nonconfigurable accessor property, and can not be changed to a data property'); | ||
} | ||
@@ -108,3 +110,3 @@ | ||
if ((!origDescriptor.writable && isChangingValue) || isChangingEnumerability || isChangingWriteability) { | ||
throw new $TypeError('`' + prop + '` is nonconfigurable, and can not be changed'); | ||
throw new $TypeError('`' + inspect(prop) + '` is nonconfigurable, and can not be changed'); | ||
} | ||
@@ -117,2 +119,3 @@ if (!isChangingWriteability && !isChangingValue) { | ||
if (options['delete']) { | ||
// @ts-expect-error TS can't handle indexing properly here | ||
delete obj[prop]; // eslint-disable-line no-param-reassign | ||
@@ -127,2 +130,3 @@ } else if ( | ||
) { | ||
// @ts-expect-error TS can't handle indexing properly here | ||
obj[prop] = options.value; // eslint-disable-line no-param-reassign | ||
@@ -138,5 +142,6 @@ } else { | ||
defineDataProperty( | ||
obj, | ||
// eslint-disable-next-line no-extra-parens | ||
/** @type {Record<PropertyKey, unknown>} */ (obj), | ||
prop, | ||
hasOwn(options, 'value') ? options.value : origDescriptor.value, | ||
hasOwn(options, 'value') ? options.value : origDescriptor && origDescriptor.value, | ||
!newEnumerable, | ||
@@ -149,3 +154,5 @@ hasOwn(options, 'nonWritable') ? options.nonWritable : hasOwn(origDescriptor, 'writable') ? !origDescriptor.writable : false | ||
$defineProperty(obj, prop, { | ||
/** @type {Exclude<typeof $defineProperty, false>} */ | ||
// eslint-disable-next-line no-extra-parens | ||
($defineProperty)(obj, prop, { | ||
configurable: origConfigurable, | ||
@@ -158,5 +165,6 @@ enumerable: newEnumerable, | ||
defineDataProperty( | ||
obj, | ||
// eslint-disable-next-line no-extra-parens | ||
/** @type {Record<PropertyKey, unknown>} */ (obj), | ||
prop, | ||
origDescriptor.value, | ||
origDescriptor && origDescriptor.value, | ||
!newEnumerable | ||
@@ -169,2 +177,3 @@ ); | ||
if (!origDescriptor) { | ||
// @ts-expect-error TS can't handle indexing properly here | ||
delete obj[prop]; // eslint-disable-line no-param-reassign | ||
@@ -174,3 +183,4 @@ } else if ($defineProperty) { | ||
defineDataProperty( | ||
obj, | ||
// eslint-disable-next-line no-extra-parens | ||
/** @type {Record<PropertyKey, unknown>} */ (obj), | ||
prop, | ||
@@ -194,2 +204,3 @@ origDescriptor.value, | ||
} else { | ||
// @ts-expect-error TS can't handle indexing properly here | ||
obj[prop] = origDescriptor.value; // eslint-disable-line no-param-reassign | ||
@@ -196,0 +207,0 @@ } |
{ | ||
"name": "mock-property", | ||
"version": "1.0.3", | ||
"version": "1.1.0", | ||
"description": "Given an object and a property, replaces a property descriptor (or deletes it), and returns a thunk to restore it.", | ||
@@ -10,2 +10,4 @@ "main": "index.js", | ||
}, | ||
"types": "./index.d.ts", | ||
"sideEffects": false, | ||
"scripts": { | ||
@@ -17,6 +19,7 @@ "prepack": "npmignore --auto --commentLines=autogenerated", | ||
"lint": "eslint --ext=.js,.mjs .", | ||
"postlint": "tsc && attw -P", | ||
"pretest": "npm run lint", | ||
"tests-only": "nyc tape 'test/**/*.js'", | ||
"test": "npm run tests-only", | ||
"posttest": "aud --production", | ||
"posttest": "npx npm@'>=10.2' audit --production", | ||
"version": "auto-changelog && git add CHANGELOG.md", | ||
@@ -50,5 +53,24 @@ "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\"" | ||
"devDependencies": { | ||
"@ljharb/eslint-config": "^21.1.0", | ||
"aud": "^2.0.3", | ||
"@arethetypeswrong/cli": "^0.15.3", | ||
"@ljharb/eslint-config": "^21.1.1", | ||
"@ljharb/tsconfig": "^0.2.0", | ||
"@types/es-value-fixtures": "^1.4.4", | ||
"@types/for-each": "^0.3.3", | ||
"@types/functions-have-names": "^1.2.2", | ||
"@types/get-intrinsic": "^1.2.2", | ||
"@types/gopd": "^1.0.3", | ||
"@types/has-bigints": "^1.0.2", | ||
"@types/has-property-descriptors": "^1.0.3", | ||
"@types/has-symbols": "^1.0.2", | ||
"@types/is-callable": "^1.1.2", | ||
"@types/isarray": "^2.0.2", | ||
"@types/make-arrow-function": "^1.2.2", | ||
"@types/make-async-function": "^1.0.2", | ||
"@types/make-generator-function": "^2.0.3", | ||
"@types/node": "^0.12.25", | ||
"@types/object-inspect": "^1.13.0", | ||
"@types/object.assign": "^4.1.0", | ||
"@types/tape": "^5.6.4", | ||
"auto-changelog": "^2.4.0", | ||
"encoding": "^0.1.13", | ||
"es-value-fixtures": "^1.4.2", | ||
@@ -58,16 +80,18 @@ "eslint": "=8.8.0", | ||
"for-each": "^0.3.3", | ||
"has-symbols": "^1.0.3", | ||
"in-publish": "^2.0.1", | ||
"npmignore": "^0.3.0", | ||
"npmignore": "^0.3.1", | ||
"nyc": "^10.3.2", | ||
"object-inspect": "^1.13.1", | ||
"safe-publish-latest": "^2.0.0", | ||
"tape": "^5.7.2" | ||
"tape": "^5.8.1", | ||
"typescript": "next" | ||
}, | ||
"dependencies": { | ||
"define-data-property": "^1.1.1", | ||
"define-data-property": "^1.1.4", | ||
"functions-have-names": "^1.2.3", | ||
"gopd": "^1.0.1", | ||
"has-property-descriptors": "^1.0.0", | ||
"hasown": "^2.0.0", | ||
"isarray": "^2.0.5" | ||
"has-property-descriptors": "^1.0.2", | ||
"hasown": "^2.0.2", | ||
"isarray": "^2.0.5", | ||
"object-inspect": "^1.13.2" | ||
}, | ||
@@ -92,3 +116,8 @@ "engines": { | ||
] | ||
}, | ||
"overrides": { | ||
"tape": { | ||
"mock-property@1": "file:../../" | ||
} | ||
} | ||
} |
1587
test/index.js
@@ -8,9 +8,18 @@ 'use strict'; | ||
var inspect = require('object-inspect'); | ||
var hasSymbols = require('has-symbols')(); | ||
/** @typedef {NonNullable<Parameters<import('../')>[2]['get']>} Getter */ | ||
/** @typedef {NonNullable<Parameters<import('../')>[2]['set']>} Setter */ | ||
var mockProperty = require('../'); | ||
var sentinel = { sentinel: true }; | ||
/** @type {Getter} */ | ||
var getter = function () {}; | ||
var setter = function (value) {}; // eslint-disable-line no-unused-vars | ||
/** @type {Setter} */ | ||
var setter = function (value) { value; }; // eslint-disable-line no-unused-expressions | ||
// @ts-expect-error TS sucks with concat | ||
var props = ['string property'].concat(hasSymbols ? Symbol.iterator : []); | ||
test('mockProperty', function (t) { | ||
@@ -20,3 +29,3 @@ t.equal(typeof mockProperty, 'function', 'is a function'); | ||
t.test('errors', function (st) { | ||
var o = {}; | ||
/** @type {Record<typeof p, unknown>} */ var o = {}; | ||
var p = 'property'; | ||
@@ -26,2 +35,3 @@ | ||
st['throws']( | ||
// @ts-expect-error | ||
function () { mockProperty(o, p, { nonEnumerable: nonBoolean }); }, | ||
@@ -32,2 +42,3 @@ TypeError, | ||
st['throws']( | ||
// @ts-expect-error | ||
function () { mockProperty(o, p, { nonWritable: nonBoolean }); }, | ||
@@ -38,2 +49,3 @@ TypeError, | ||
st['throws']( | ||
// @ts-expect-error | ||
function () { mockProperty(o, p, { 'delete': nonBoolean }); }, | ||
@@ -56,2 +68,3 @@ TypeError, | ||
st['throws']( | ||
// @ts-expect-error | ||
function () { mockProperty(o, p, { get: function () {}, nonWritable: true }); }, | ||
@@ -62,2 +75,3 @@ TypeError, | ||
st['throws']( | ||
// @ts-expect-error | ||
function () { mockProperty(o, p, { set: function () {}, nonWritable: true }); }, | ||
@@ -70,2 +84,3 @@ TypeError, | ||
st['throws']( | ||
// @ts-expect-error | ||
function () { mockProperty(o, p, { get: nonFunction }); }, | ||
@@ -76,2 +91,3 @@ TypeError, | ||
st['throws']( | ||
// @ts-expect-error | ||
function () { mockProperty(o, p, { set: nonFunction }); }, | ||
@@ -83,4 +99,5 @@ TypeError, | ||
// these lack ts-expect-error, because TS can't differentiate undefined and absent | ||
st['throws']( | ||
function () { mockProperty(o, p, { 'delete': true, get: function () {} }); }, | ||
function () { mockProperty(o, p, { 'delete': true, get: undefined }); }, | ||
TypeError, | ||
@@ -90,3 +107,3 @@ 'delete and get are mutually exclusive' | ||
st['throws']( | ||
function () { mockProperty(o, p, { 'delete': true, set: function () {} }); }, | ||
function () { mockProperty(o, p, { 'delete': true, set: undefined }); }, | ||
TypeError, | ||
@@ -101,3 +118,3 @@ 'delete and set are mutually exclusive' | ||
st['throws']( | ||
function () { mockProperty(o, p, { 'delete': true, nonWritable: false }); }, | ||
function () { mockProperty(o, p, { 'delete': true, nonWritable: undefined }); }, | ||
TypeError, | ||
@@ -107,3 +124,3 @@ 'delete and nonWritable are mutually exclusive' | ||
st['throws']( | ||
function () { mockProperty(o, p, { 'delete': true, nonEnumerable: false }); }, | ||
function () { mockProperty(o, p, { 'delete': true, nonEnumerable: undefined }); }, | ||
TypeError, | ||
@@ -117,15 +134,18 @@ 'delete and nonEnumerable are mutually exclusive' | ||
t.test('data -> data', function (st) { | ||
var obj = { a: sentinel }; | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = sentinel; | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { value: obj }); | ||
st.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { value: obj }); | ||
st.ok('a' in obj, 'property still exists'); | ||
st.equal(obj.a, obj, 'obj has expected value'); | ||
st.ok(p in obj, 'property still exists'); | ||
st.equal(obj[p], obj, 'obj has expected value'); | ||
t.comment('restore'); | ||
restore(); | ||
st.comment('restore: ' + inspect(p)); | ||
restore(); | ||
st.ok('a' in obj, 'property is restored'); | ||
st.equal(obj.a, sentinel, 'data property holds sentinel'); | ||
st.ok(p in obj, 'property is restored'); | ||
st.equal(obj[p], sentinel, 'data property holds sentinel'); | ||
}); | ||
@@ -136,18 +156,21 @@ st.end(); | ||
t.test('data: enumerable -> nonEnumerable', { skip: !hasPropertyDescriptors() }, function (st) { | ||
var obj = { a: sentinel }; | ||
st.ok(Object.prototype.propertyIsEnumerable.call(obj, 'a'), 'starts enumerable'); | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = sentinel; | ||
st.ok(Object.prototype.propertyIsEnumerable.call(obj, p), 'starts enumerable'); | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { nonEnumerable: true }); | ||
st.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { nonEnumerable: true }); | ||
st.ok('a' in obj, 'property still exists'); | ||
st.equal(obj.a, sentinel, 'data property still holds sentinel'); | ||
st.notOk(Object.prototype.propertyIsEnumerable.call(obj, 'a'), 'is not enumerable'); | ||
st.ok(p in obj, 'property still exists'); | ||
st.equal(obj[p], sentinel, 'data property still holds sentinel'); | ||
st.notOk(Object.prototype.propertyIsEnumerable.call(obj, p), 'is not enumerable'); | ||
t.comment('restore'); | ||
restore(); | ||
st.comment('restore: ' + inspect(p)); | ||
restore(); | ||
st.ok('a' in obj, 'property is restored'); | ||
st.equal(obj.a, sentinel, 'data property again holds sentinel'); | ||
st.ok(Object.prototype.propertyIsEnumerable.call(obj, 'a'), 'ends enumerable'); | ||
st.ok(p in obj, 'property is restored'); | ||
st.equal(obj[p], sentinel, 'data property again holds sentinel'); | ||
st.ok(Object.prototype.propertyIsEnumerable.call(obj, p), 'ends enumerable'); | ||
}); | ||
@@ -158,14 +181,17 @@ st.end(); | ||
t.test('data -> absent', function (st) { | ||
var obj = { a: sentinel }; | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = sentinel; | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { 'delete': true }); | ||
st.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { 'delete': true }); | ||
st.notOk('a' in obj, 'property is deleted'); | ||
st.notOk(p in obj, 'property is deleted'); | ||
t.comment('restore'); | ||
restore(); | ||
st.comment('restore: ' + inspect(p)); | ||
restore(); | ||
st.ok('a' in obj, 'property is restored'); | ||
st.equal(obj.a, sentinel, 'object value is restored to sentinel'); | ||
st.ok(p in obj, 'property is restored'); | ||
st.equal(obj[p], sentinel, 'object value is restored to sentinel'); | ||
}); | ||
@@ -176,17 +202,20 @@ st.end(); | ||
t.test('absent -> data', function (st) { | ||
var obj = {}; | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
st.notOk('a' in obj, 'property is initially absent'); | ||
st.notOk(p in obj, 'property is initially absent'); | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { value: sentinel }); | ||
st.comment('mockProperty(…): ' + inspect(p)); | ||
st.ok('a' in obj, 'property exists'); | ||
st.equal(obj.a, sentinel, 'data property holds sentinel'); | ||
var restore = mockProperty(obj, p, { value: sentinel }); | ||
t.comment('restore'); | ||
restore(); | ||
st.ok(p in obj, 'property exists'); | ||
st.equal(obj[p], sentinel, 'data property holds sentinel'); | ||
st.notOk('a' in obj, 'property is absent again'); | ||
st.comment('restore: ' + inspect(p)); | ||
restore(); | ||
st.notOk(p in obj, 'property is absent again'); | ||
}); | ||
st.end(); | ||
@@ -196,15 +225,17 @@ }); | ||
t.test('absent -> absent', function (st) { | ||
var obj = {}; | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
st.notOk('a' in obj, 'property is initially absent'); | ||
st.notOk(p in obj, 'property is initially absent'); | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { 'delete': true }); | ||
st.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { 'delete': true }); | ||
st.notOk('a' in obj, 'property still does not exist'); | ||
st.notOk(p in obj, 'property still does not exist'); | ||
t.comment('restore'); | ||
restore(); | ||
st.comment('restore: ' + inspect(p)); | ||
restore(); | ||
st.notOk('a' in obj, 'property remains absent'); | ||
st.notOk(p in obj, 'property remains absent'); | ||
}); | ||
@@ -216,22 +247,23 @@ st.end(); | ||
st.test('data: nonconfigurable, nonwritable, change value', function (s2t) { | ||
var o = {}; | ||
var p = 'property'; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, writable: false }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: false | ||
}, | ||
'precondition: expected descriptor' | ||
); | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var o = {}; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, writable: false }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: false | ||
}, | ||
'precondition: expected descriptor: ' + inspect(p) | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { value: 42 }); }, | ||
TypeError, | ||
'nonconfigurable property throws' | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { value: 42 }); }, | ||
TypeError, | ||
'nonconfigurable property throws: ' + inspect(p) | ||
); | ||
}); | ||
@@ -242,21 +274,22 @@ s2t.end(); | ||
st.test('data: nonconfigurable, nonwritable, same value', function (s2t) { | ||
var o = {}; | ||
var p = 'property'; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, writable: false }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: false | ||
}, | ||
'precondition: expected descriptor' | ||
); | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var o = {}; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, writable: false }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: false | ||
}, | ||
'precondition: expected descriptor: ' + inspect(p) | ||
); | ||
s2t.doesNotThrow( | ||
function () { mockProperty(o, p, { value: sentinel }); }, | ||
'same value is a noop' | ||
); | ||
s2t.doesNotThrow( | ||
function () { mockProperty(o, p, { value: sentinel }); }, | ||
'same value is a noop: ' + inspect(p) | ||
); | ||
}); | ||
@@ -267,31 +300,32 @@ s2t.end(); | ||
st.test('data: nonconfigurable, writable, change value', function (s2t) { | ||
var o = {}; | ||
var p = 'property'; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, writable: true }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: true | ||
}, | ||
'precondition: expected descriptor' | ||
); | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var o = {}; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, writable: true }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: true | ||
}, | ||
'precondition: expected descriptor: ' + inspect(p) | ||
); | ||
s2t.doesNotThrow( | ||
function () { mockProperty(o, p, { value: { wrong: true } })(); }, | ||
'writable property can change value' | ||
); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: true | ||
}, | ||
'postcondition: expected descriptor' | ||
); | ||
s2t.doesNotThrow( | ||
function () { mockProperty(o, p, { value: { wrong: true } })(); }, | ||
'writable property can change value: ' + inspect(p) | ||
); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: true | ||
}, | ||
'postcondition: expected descriptor: ' + inspect(p) | ||
); | ||
}); | ||
@@ -302,22 +336,23 @@ s2t.end(); | ||
st.test('data: nonconfigurable, writable, change writability', function (s2t) { | ||
var o = {}; | ||
var p = 'property'; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, writable: true }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: true | ||
}, | ||
'precondition: expected descriptor' | ||
); | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var o = {}; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, writable: true }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: true | ||
}, | ||
'precondition: expected descriptor: ' + inspect(p) | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { nonWritable: true }); }, | ||
TypeError, | ||
'nonconfigurable property throws' | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { nonWritable: true }); }, | ||
TypeError, | ||
'nonconfigurable property throws: ' + inspect(p) | ||
); | ||
}); | ||
@@ -328,22 +363,23 @@ s2t.end(); | ||
st.test('data: nonconfigurable, nonwritable, change writability', function (s2t) { | ||
var o = {}; | ||
var p = 'property'; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, writable: false }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: false | ||
}, | ||
'precondition: expected descriptor' | ||
); | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var o = {}; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, writable: false }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: false | ||
}, | ||
'precondition: expected descriptor: ' + inspect(p) | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { nonWritable: false }); }, | ||
TypeError, | ||
'nonconfigurable property throws' | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { nonWritable: false }); }, | ||
TypeError, | ||
'nonconfigurable property throws: ' + inspect(p) | ||
); | ||
}); | ||
@@ -354,27 +390,28 @@ s2t.end(); | ||
st.test('data: nonconfigurable, writable, nonenumerable', function (s2t) { | ||
var o = {}; | ||
var p = 'property'; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, enumerable: false, writable: true }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: false, | ||
value: sentinel, | ||
writable: true | ||
}, | ||
'precondition: expected descriptor' | ||
); | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var o = {}; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, enumerable: false, writable: true }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: false, | ||
value: sentinel, | ||
writable: true | ||
}, | ||
'precondition: expected descriptor: ' + inspect(p) | ||
); | ||
s2t.doesNotThrow( | ||
function () { mockProperty(o, p, { nonEnumerable: true })(); }, | ||
'nonconfigurable nonenumerable, to nonenumerable, is a noop' | ||
); | ||
s2t.doesNotThrow( | ||
function () { mockProperty(o, p, { nonEnumerable: true })(); }, | ||
'nonconfigurable nonenumerable, to nonenumerable, is a noop: ' + inspect(p) | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { nonEnumerable: false })(); }, | ||
TypeError, | ||
'nonconfigurable nonenumerable, to enumerable, throws' | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { nonEnumerable: false })(); }, | ||
TypeError, | ||
'nonconfigurable nonenumerable, to enumerable, throws: ' + inspect(p) | ||
); | ||
}); | ||
@@ -385,27 +422,28 @@ s2t.end(); | ||
st.test('data: nonconfigurable, writable, enumerable', function (s2t) { | ||
var o = {}; | ||
var p = 'property'; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, enumerable: true, writable: true }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: true | ||
}, | ||
'precondition: expected descriptor' | ||
); | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var o = {}; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, enumerable: true, writable: true }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: true | ||
}, | ||
'precondition: expected descriptor: ' + inspect(p) | ||
); | ||
s2t.doesNotThrow( | ||
function () { mockProperty(o, p, { nonEnumerable: false })(); }, | ||
'nonconfigurable enumerable, to enumerable, is a noop' | ||
); | ||
s2t.doesNotThrow( | ||
function () { mockProperty(o, p, { nonEnumerable: false })(); }, | ||
'nonconfigurable enumerable, to enumerable, is a noop: ' + inspect(p) | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { nonEnumerable: true }); }, | ||
TypeError, | ||
'nonconfigurable enumerable, to nonenumerable, throws' | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { nonEnumerable: true }); }, | ||
TypeError, | ||
'nonconfigurable enumerable, to nonenumerable, throws: ' + inspect(p) | ||
); | ||
}); | ||
@@ -416,34 +454,35 @@ s2t.end(); | ||
st.test('nonconfigurable data -> accessor', function (s2t) { | ||
var o = {}; | ||
var p = 'property'; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: true | ||
}, | ||
'precondition: expected descriptor' | ||
); | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var o = {}; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
value: sentinel, | ||
writable: true | ||
}, | ||
'precondition: expected descriptor: ' + inspect(p) | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { get: getter }); }, | ||
TypeError, | ||
'nonconfigurable data, with getter, throws' | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { get: getter }); }, | ||
TypeError, | ||
'nonconfigurable data, with getter, throws: ' + inspect(p) | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { set: setter }); }, | ||
TypeError, | ||
'nonconfigurable data, with getter, throws' | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { set: setter }); }, | ||
TypeError, | ||
'nonconfigurable data, with getter, throws: ' + inspect(p) | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { get: getter, set: setter }); }, | ||
TypeError, | ||
'nonconfigurable data, with both, throws' | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { get: getter, set: setter }); }, | ||
TypeError, | ||
'nonconfigurable data, with both, throws: ' + inspect(p) | ||
); | ||
}); | ||
@@ -454,22 +493,23 @@ s2t.end(); | ||
st.test('nonconfigurable accessor -> data', function (s2t) { | ||
var o = {}; | ||
var p = 'property'; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, get: getter, set: setter }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
get: getter, | ||
set: setter | ||
}, | ||
'precondition: expected descriptor' | ||
); | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var o = {}; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, get: getter, set: setter }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
get: getter, | ||
set: setter | ||
}, | ||
'precondition: expected descriptor: ' + inspect(p) | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { value: sentinel }); }, | ||
TypeError, | ||
'nonconfigurable both, with data, throws' | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { value: sentinel }); }, | ||
TypeError, | ||
'nonconfigurable both, with data, throws: ' + inspect(p) | ||
); | ||
}); | ||
@@ -480,44 +520,45 @@ s2t.end(); | ||
st.test('accessor: nonconfigurable', function (s2t) { | ||
var o = {}; | ||
var p = 'property'; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, get: getter, set: setter }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
get: getter, | ||
set: setter | ||
}, | ||
'precondition: expected descriptor' | ||
); | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var o = {}; | ||
o[p] = sentinel; | ||
Object.defineProperty(o, p, { configurable: false, get: getter, set: setter }); | ||
s2t.deepEqual( | ||
Object.getOwnPropertyDescriptor(o, p), | ||
{ | ||
configurable: false, | ||
enumerable: true, | ||
get: getter, | ||
set: setter | ||
}, | ||
'precondition: expected descriptor: ' + inspect(p) | ||
); | ||
s2t.doesNotThrow( | ||
function () { mockProperty(o, p, { get: getter })(); }, | ||
'same getter is a noop' | ||
); | ||
s2t.doesNotThrow( | ||
function () { mockProperty(o, p, { get: getter })(); }, | ||
'same getter is a noop: ' + inspect(p) | ||
); | ||
s2t.doesNotThrow( | ||
function () { mockProperty(o, p, { set: setter })(); }, | ||
'same setter is a noop' | ||
); | ||
s2t.doesNotThrow( | ||
function () { mockProperty(o, p, { set: setter })(); }, | ||
'same setter is a noop: ' + inspect(p) | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { get: function () {} }); }, | ||
TypeError, | ||
'nonconfigurable both, changing getter, throws' | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { get: function () {} }); }, | ||
TypeError, | ||
'nonconfigurable both, changing getter, throws: ' + inspect(p) | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { set: function (value) {} }); }, // eslint-disable-line no-unused-vars | ||
TypeError, | ||
'nonconfigurable both, changing setter, throws' | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { set: function (value) { value; } }); }, // eslint-disable-line no-unused-expressions | ||
TypeError, | ||
'nonconfigurable both, changing setter, throws: ' + inspect(p) | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { enumerable: false }); }, | ||
TypeError, | ||
'nonconfigurable both, changing setter, throws' | ||
); | ||
s2t['throws']( | ||
function () { mockProperty(o, p, { nonEnumerable: true }); }, | ||
TypeError, | ||
'nonconfigurable both, changing setter, throws: ' + inspect(p) | ||
); | ||
}); | ||
@@ -528,30 +569,33 @@ s2t.end(); | ||
st.test('getter -> getter', function (s2t) { | ||
var calls = 0; | ||
var obj = { a: 1 }; | ||
Object.defineProperty(obj, 'a', { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
forEach(props, function (p) { | ||
var calls = 0; | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = 1; | ||
Object.defineProperty(obj, p, { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
s2t.equal(obj.a, 'calls: 1', 'getter returns 1 call'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
s2t.equal(obj[p], 'calls: 1', 'getter returns 1 call'); | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { | ||
get: function () { | ||
calls += 100; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { | ||
get: function () { | ||
calls += 100; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, 'calls: 101', 'getter returns 101 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], 'calls: 101', 'getter returns 101 calls'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, 'calls: 102', 'getter returns 102 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], 'calls: 102', 'getter returns 102 calls'); | ||
}); | ||
@@ -562,33 +606,36 @@ s2t.end(); | ||
st.test('getter -> setter', function (s2t) { | ||
var calls = 0; | ||
var obj = { a: 1 }; | ||
Object.defineProperty(obj, 'a', { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
forEach(props, function (p) { | ||
var calls = 0; | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = 1; | ||
Object.defineProperty(obj, p, { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
s2t.equal(obj.a, 'calls: 1', 'getter returns 1 call'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
s2t.equal(obj[p], 'calls: 1', 'getter returns 1 call'); | ||
var holder; | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { | ||
get: undefined, | ||
set: function (value) { | ||
holder = 'holder mocked: ' + value; | ||
} | ||
}); | ||
var holder; | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { | ||
get: undefined, | ||
set: function (value) { | ||
holder = 'holder mocked: ' + value; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
obj.a = 'second'; | ||
s2t.equal(holder, 'holder mocked: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj.a, undefined, 'getter returns undefined'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
obj[p] = 'second'; | ||
s2t.equal(holder, 'holder mocked: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj[p], undefined, 'getter returns undefined'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, 'calls: 2', 'getter returns 2 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], 'calls: 2', 'getter returns 2 calls'); | ||
}); | ||
@@ -599,34 +646,37 @@ s2t.end(); | ||
st.test('getter -> both', function (s2t) { | ||
var calls = 0; | ||
var obj = { a: 1 }; | ||
Object.defineProperty(obj, 'a', { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
forEach(props, function (p) { | ||
var calls = 0; | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = 1; | ||
Object.defineProperty(obj, p, { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
s2t.equal(obj.a, 'calls: 1', 'getter returns 1 call'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
s2t.equal(obj[p], 'calls: 1', 'getter returns 1 call'); | ||
var holder; | ||
var holder; | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { | ||
set: function (value) { | ||
holder = 'holder mocked: ' + value; | ||
} | ||
}); | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { | ||
set: function (value) { | ||
holder = 'holder mocked: ' + value; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
obj.a = 'second'; | ||
s2t.equal(holder, 'holder mocked: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj.a, 'calls: 2', 'getter returns 2 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
obj[p] = 'second'; | ||
s2t.equal(holder, 'holder mocked: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj[p], 'calls: 2', 'getter returns 2 calls'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(holder, 'holder mocked: second', 'setter was not invoked ("third")'); | ||
s2t.equal(obj.a, 'calls: 3', 'getter returns 3 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(holder, 'holder mocked: second', 'setter was not invoked ("third")'); | ||
s2t.equal(obj[p], 'calls: 3', 'getter returns 3 calls'); | ||
}); | ||
@@ -637,27 +687,28 @@ s2t.end(); | ||
st.test('getter -> data', function (s2t) { | ||
var calls = 0; | ||
var obj = { a: 1 }; | ||
Object.defineProperty(obj, 'a', { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
forEach(props, function (p) { | ||
var calls = 0; | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = 1; | ||
Object.defineProperty(obj, p, { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
s2t.equal(obj.a, 'calls: 1', 'getter returns 1 call'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
s2t.equal(obj[p], 'calls: 1', 'getter returns 1 call'); | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { | ||
value: sentinel | ||
}); | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { value: sentinel }); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, sentinel, 'data property holds sentinel'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], sentinel, 'data property holds sentinel'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, 'calls: 2', 'getter returns 2 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], 'calls: 2', 'getter returns 2 calls'); | ||
}); | ||
@@ -668,25 +719,27 @@ s2t.end(); | ||
st.test('getter -> absent', function (s2t) { | ||
var calls = 0; | ||
var obj = { a: 1 }; | ||
Object.defineProperty(obj, 'a', { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
forEach(props, function (p) { | ||
var calls = 0; | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = 1; | ||
Object.defineProperty(obj, p, { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
s2t.equal(obj.a, 'calls: 1', 'getter returns 1 call'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
s2t.equal(obj[p], 'calls: 1', 'getter returns 1 call'); | ||
var restore = mockProperty(obj, 'a', { | ||
'delete': true | ||
}); | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { 'delete': true }); | ||
s2t.notOk('a' in obj, 'property is deleted'); | ||
s2t.notOk(p in obj, 'property ' + inspect(p) + ' is deleted'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, 'calls: 2', 'getter returns 2 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], 'calls: 2', 'getter returns 2 calls'); | ||
}); | ||
@@ -697,40 +750,43 @@ s2t.end(); | ||
st.test('setter -> getter', function (s2t) { | ||
var calls = 0; | ||
var holder; | ||
var obj = { a: 1 }; | ||
Object.defineProperty(obj, 'a', { | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
forEach(props, function (p) { | ||
var calls = 0; | ||
var holder; | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = 1; | ||
Object.defineProperty(obj, p, { | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
obj.a = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
s2t.equal(obj.a, undefined, 'getter returns undefined'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
obj[p] = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
s2t.equal(obj[p], undefined, 'getter returns undefined'); | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
}, | ||
set: undefined | ||
}); | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
}, | ||
set: undefined | ||
}); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, 'calls: 1', 'getter returns 1 calls'); | ||
s2t['throws']( | ||
function () { obj.a = 42; }, | ||
TypeError, | ||
'no setter, throws' | ||
); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], 'calls: 1', 'getter returns 1 calls'); | ||
s2t['throws']( | ||
function () { obj[p] = 42; }, | ||
TypeError, | ||
'no setter, throws' | ||
); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
obj.a = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
s2t.equal(obj.a, undefined, 'getter returns undefined'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
obj[p] = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
s2t.equal(obj[p], undefined, 'getter returns undefined'); | ||
}); | ||
@@ -741,36 +797,39 @@ s2t.end(); | ||
st.test('setter -> both', function (s2t) { | ||
var calls = 0; | ||
var holder; | ||
var obj = { a: 1 }; | ||
Object.defineProperty(obj, 'a', { | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
forEach(props, function (p) { | ||
var calls = 0; | ||
var holder; | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = 1; | ||
Object.defineProperty(obj, p, { | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
obj.a = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
s2t.equal(obj.a, undefined, 'no getter, undefined'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
obj[p] = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
s2t.equal(obj[p], undefined, 'no getter, undefined'); | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
obj.a = 'second'; | ||
s2t.equal(holder, 'holder: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj.a, 'calls: 1', 'getter returns 1 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
obj[p] = 'second'; | ||
s2t.equal(holder, 'holder: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj[p], 'calls: 1', 'getter returns 1 calls'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
obj.a = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
s2t.equal(obj.a, undefined, 'no getter, undefined'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
obj[p] = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
s2t.equal(obj[p], undefined, 'no getter, undefined'); | ||
}); | ||
@@ -781,31 +840,34 @@ s2t.end(); | ||
st.test('setter -> setter', function (s2t) { | ||
var obj = { a: 1 }; | ||
var holder; | ||
Object.defineProperty(obj, 'a', { | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = 1; | ||
var holder; | ||
Object.defineProperty(obj, p, { | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
obj.a = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
obj[p] = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { | ||
set: function (value) { | ||
holder = 'holder mocked: ' + value; | ||
} | ||
}); | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { | ||
set: function (value) { | ||
holder = 'holder mocked: ' + value; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
obj.a = 'second'; | ||
s2t.equal(holder, 'holder mocked: second', 'setter was invoked ("second")'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
obj[p] = 'second'; | ||
s2t.equal(holder, 'holder mocked: second', 'setter was invoked ("second")'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.ok('a' in obj, 'property exists'); | ||
obj.a = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
obj[p] = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
}); | ||
@@ -816,33 +878,36 @@ s2t.end(); | ||
st.test('setter -> data', function (s2t) { | ||
var obj = { a: 1 }; | ||
var holder; | ||
Object.defineProperty(obj, 'a', { | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = 1; | ||
var holder; | ||
Object.defineProperty(obj, p, { | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
s2t.equal(obj.a, undefined, 'no getter, undefined'); | ||
obj.a = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
s2t.equal(obj[p], undefined, 'no getter, undefined'); | ||
obj[p] = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { | ||
value: sentinel | ||
}); | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { | ||
value: sentinel | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
s2t.equal(obj.a, sentinel, 'data property holds sentinel'); | ||
obj.a = 'second'; | ||
s2t.equal(holder, 'holder: first', 'setter was not invoked ("second")'); | ||
s2t.notEqual(obj.a, sentinel, 'data property no longer holds sentinel'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
s2t.equal(obj[p], sentinel, 'data property holds sentinel'); | ||
obj[p] = 'second'; | ||
s2t.equal(holder, 'holder: first', 'setter was not invoked ("second")'); | ||
s2t.notEqual(obj[p], sentinel, 'data property no longer holds sentinel'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.ok('a' in obj, 'property exists'); | ||
s2t.equal(obj.a, undefined, 'no getter, undefined'); | ||
obj.a = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
s2t.equal(obj[p], undefined, 'no getter, undefined'); | ||
obj[p] = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
}); | ||
@@ -853,27 +918,30 @@ s2t.end(); | ||
st.test('setter -> absent', function (s2t) { | ||
var obj = { a: 1 }; | ||
var holder; | ||
Object.defineProperty(obj, 'a', { | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = 1; | ||
var holder; | ||
Object.defineProperty(obj, p, { | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
obj.a = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
obj[p] = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { | ||
'delete': true | ||
}); | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { | ||
'delete': true | ||
}); | ||
s2t.notOk('a' in obj, 'property no longer exists'); | ||
s2t.notOk(p in obj, 'property ' + inspect(p) + ' no longer exists'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.ok('a' in obj, 'property exists'); | ||
obj.a = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
obj[p] = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
}); | ||
@@ -884,29 +952,32 @@ s2t.end(); | ||
st.test('data -> getter', function (s2t) { | ||
var calls = 0; | ||
var obj = { a: sentinel }; | ||
forEach(props, function (p) { | ||
var calls = 0; | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = sentinel; | ||
s2t.ok('a' in obj, 'property exists'); | ||
s2t.equal(obj.a, sentinel, 'data property holds sentinel'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
s2t.equal(obj[p], sentinel, 'data property holds sentinel'); | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { | ||
get: function () { | ||
calls += 100; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { | ||
get: function () { | ||
calls += 100; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, 'calls: 100', 'getter returns 100 calls'); | ||
s2t['throws']( | ||
function () { obj.a = 42; }, | ||
TypeError, | ||
'no setter, throws' | ||
); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], 'calls: 100', 'getter returns 100 calls'); | ||
s2t['throws']( | ||
function () { obj[p] = 42; }, | ||
TypeError, | ||
'no setter, throws' | ||
); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, sentinel, 'data property holds sentinel'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], sentinel, 'data property holds sentinel'); | ||
}); | ||
@@ -917,26 +988,29 @@ s2t.end(); | ||
st.test('data -> setter', function (s2t) { | ||
var obj = { a: sentinel }; | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = sentinel; | ||
s2t.ok('a' in obj, 'property exists'); | ||
s2t.equal(obj.a, sentinel, 'data property holds sentinel'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
s2t.equal(obj[p], sentinel, 'data property holds sentinel'); | ||
var holder; | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { | ||
set: function (value) { | ||
holder = 'holder mocked: ' + value; | ||
} | ||
}); | ||
var holder; | ||
s2t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, p, { | ||
set: function (value) { | ||
holder = 'holder mocked: ' + value; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
obj.a = 'second'; | ||
s2t.equal(holder, 'holder mocked: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj.a, undefined, 'no getter, undefined'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
obj[p] = 'second'; | ||
s2t.equal(holder, 'holder mocked: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj[p], undefined, 'no getter, undefined'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore'); | ||
restore(); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, sentinel, 'data property holds sentinel'); | ||
s2t.equal(holder, 'holder mocked: second', 'setter was not invoked ("second")'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], sentinel, 'data property holds sentinel'); | ||
s2t.equal(holder, 'holder mocked: second', 'setter was not invoked ("second")'); | ||
}); | ||
@@ -947,31 +1021,34 @@ s2t.end(); | ||
st.test('data -> both', function (s2t) { | ||
var calls = 0; | ||
var obj = { a: sentinel }; | ||
forEach(props, function (p) { | ||
var calls = 0; | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = sentinel; | ||
s2t.ok('a' in obj, 'property exists'); | ||
s2t.equal(obj.a, sentinel, 'data property holds sentinel'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
s2t.equal(obj[p], sentinel, 'data property holds sentinel'); | ||
var holder; | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { | ||
get: function () { | ||
calls += 100; | ||
return 'calls: ' + calls; | ||
}, | ||
set: function (value) { | ||
holder = 'holder mocked: ' + value; | ||
} | ||
}); | ||
var holder; | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { | ||
get: function () { | ||
calls += 100; | ||
return 'calls: ' + calls; | ||
}, | ||
set: function (value) { | ||
holder = 'holder mocked: ' + value; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
obj.a = 'second'; | ||
s2t.equal(holder, 'holder mocked: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj.a, 'calls: 100', 'getter returns 100 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
obj[p] = 'second'; | ||
s2t.equal(holder, 'holder mocked: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj[p], 'calls: 100', 'getter returns 100 calls'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, sentinel, 'data property holds sentinel'); | ||
s2t.equal(holder, 'holder mocked: second', 'setter was not invoked ("second")'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], sentinel, 'data property holds sentinel'); | ||
s2t.equal(holder, 'holder mocked: second', 'setter was not invoked ("second")'); | ||
}); | ||
@@ -982,22 +1059,24 @@ s2t.end(); | ||
st.test('absent -> getter', function (s2t) { | ||
var calls = 0; | ||
var obj = {}; | ||
forEach(props, function (p) { | ||
var calls = 0; | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
s2t.notOk('a' in obj, 'property does not exist'); | ||
s2t.notOk(p in obj, 'property ' + inspect(p) + ' does not exist'); | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { | ||
get: function () { | ||
calls += 100; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { | ||
get: function () { | ||
calls += 100; | ||
return 'calls: ' + calls; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
s2t.equal(obj.a, 'calls: 100', 'getter returns 100 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
s2t.equal(obj[p], 'calls: 100', 'getter returns 100 calls'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.notOk('a' in obj, 'property no longer exists'); | ||
s2t.notOk(p in obj, 'property ' + inspect(p) + ' no longer exists'); | ||
}); | ||
@@ -1008,23 +1087,25 @@ s2t.end(); | ||
st.test('absent -> setter', function (s2t) { | ||
var obj = {}; | ||
forEach(props, function (p) { | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
s2t.notOk('a' in obj, 'property does not exist'); | ||
s2t.notOk(p in obj, 'property ' + inspect(p) + ' does not exist'); | ||
var holder; | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { | ||
set: function (value) { | ||
holder = 'holder mocked: ' + value; | ||
} | ||
}); | ||
var holder; | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { | ||
set: function (value) { | ||
holder = 'holder mocked: ' + value; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
obj.a = 'second'; | ||
s2t.equal(holder, 'holder mocked: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj.a, undefined, 'no getter, undefined'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
obj[p] = 'second'; | ||
s2t.equal(holder, 'holder mocked: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj[p], undefined, 'no getter, undefined'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.notOk('a' in obj, 'property no longer exists'); | ||
s2t.notOk(p in obj, 'property ' + inspect(p) + ' no longer exists'); | ||
}); | ||
@@ -1035,28 +1116,30 @@ s2t.end(); | ||
st.test('absent -> both', function (s2t) { | ||
var calls = 0; | ||
var obj = {}; | ||
forEach(props, function (p) { | ||
var calls = 0; | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
s2t.notOk('a' in obj, 'property does not exist'); | ||
s2t.notOk(p in obj, 'property ' + inspect(p) + ' does not exist'); | ||
var holder; | ||
t.comment('mockProperty(…)'); | ||
var restore = mockProperty(obj, 'a', { | ||
get: function () { | ||
calls += 100; | ||
return 'calls: ' + calls; | ||
}, | ||
set: function (value) { | ||
holder = 'holder mocked: ' + value; | ||
} | ||
}); | ||
var holder; | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { | ||
get: function () { | ||
calls += 100; | ||
return 'calls: ' + calls; | ||
}, | ||
set: function (value) { | ||
holder = 'holder mocked: ' + value; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
obj.a = 'second'; | ||
s2t.equal(holder, 'holder mocked: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj.a, 'calls: 100', 'getter returns 100 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
obj[p] = 'second'; | ||
s2t.equal(holder, 'holder mocked: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj[p], 'calls: 100', 'getter returns 100 calls'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.notOk('a' in obj, 'property no longer exists'); | ||
s2t.notOk(p in obj, 'property ' + inspect(p) + ' no longer exists'); | ||
}); | ||
@@ -1067,35 +1150,37 @@ s2t.end(); | ||
st.test('both -> absent', function (s2t) { | ||
var calls = 0; | ||
var holder; | ||
var obj = { a: 1 }; | ||
Object.defineProperty(obj, 'a', { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
}, | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
forEach(props, function (p) { | ||
var calls = 0; | ||
var holder; | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = 1; | ||
Object.defineProperty(obj, p, { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
}, | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
s2t.equal(obj.a, 'calls: 1', 'getter returns 1 calls'); | ||
obj.a = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
s2t.equal(obj.a, 'calls: 2', 'getter returns 2 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
s2t.equal(obj[p], 'calls: 1', 'getter returns 1 calls'); | ||
obj[p] = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
s2t.equal(obj[p], 'calls: 2', 'getter returns 2 calls'); | ||
var restore = mockProperty(obj, 'a', { | ||
'delete': true | ||
}); | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { 'delete': true }); | ||
s2t.notOk('a' in obj, 'property is deleted'); | ||
s2t.notOk(p in obj, 'property ' + inspect(p) + ' is deleted'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, 'calls: 3', 'getter returns 3 calls'); | ||
obj.a = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
s2t.equal(obj.a, 'calls: 4', 'getter returns 4 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], 'calls: 3', 'getter returns 3 calls'); | ||
obj[p] = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
s2t.equal(obj[p], 'calls: 4', 'getter returns 4 calls'); | ||
}); | ||
@@ -1106,42 +1191,44 @@ s2t.end(); | ||
st.test('both -> getter', function (s2t) { | ||
var calls = 0; | ||
var holder; | ||
var obj = { a: 1 }; | ||
Object.defineProperty(obj, 'a', { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
}, | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
forEach(props, function (p) { | ||
var calls = 0; | ||
var holder; | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = sentinel; | ||
Object.defineProperty(obj, p, { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
}, | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
s2t.equal(obj.a, 'calls: 1', 'getter returns 1 calls'); | ||
obj.a = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
s2t.equal(obj.a, 'calls: 2', 'getter returns 2 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
s2t.equal(obj[p], 'calls: 1', 'getter returns 1 calls'); | ||
obj[p] = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
s2t.equal(obj[p], 'calls: 2', 'getter returns 2 calls'); | ||
var restore = mockProperty(obj, 'a', { | ||
set: undefined | ||
}); | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { set: undefined }); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, 'calls: 3', 'getter returns 3 calls'); | ||
s2t['throws']( | ||
function () { obj.a = 'second'; }, | ||
TypeError, | ||
'no setter, throws' | ||
); | ||
s2t.equal(obj.a, 'calls: 4', 'getter returns 4 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], 'calls: 3', 'getter returns 3 calls'); | ||
s2t['throws']( | ||
function () { obj[p] = 'second'; }, | ||
TypeError, | ||
'no setter, throws' | ||
); | ||
s2t.equal(obj[p], 'calls: 4', 'getter returns 4 calls'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, 'calls: 5', 'getter returns 5 calls'); | ||
obj.a = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
s2t.equal(obj.a, 'calls: 6', 'getter returns 6 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], 'calls: 5', 'getter returns 5 calls'); | ||
obj[p] = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
s2t.equal(obj[p], 'calls: 6', 'getter returns 6 calls'); | ||
}); | ||
@@ -1152,39 +1239,41 @@ s2t.end(); | ||
st.test('both -> setter', function (s2t) { | ||
var calls = 0; | ||
var holder; | ||
var obj = { a: 1 }; | ||
Object.defineProperty(obj, 'a', { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
}, | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
forEach(props, function (p) { | ||
var calls = 0; | ||
var holder; | ||
/** @type {Record<typeof p, unknown>} */ var obj = {}; | ||
obj[p] = 1; | ||
Object.defineProperty(obj, p, { | ||
get: function () { | ||
calls += 1; | ||
return 'calls: ' + calls; | ||
}, | ||
set: function (value) { | ||
holder = 'holder: ' + value; | ||
} | ||
}); | ||
s2t.ok('a' in obj, 'property exists'); | ||
s2t.equal(obj.a, 'calls: 1', 'getter returns 1 calls'); | ||
obj.a = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
s2t.equal(obj.a, 'calls: 2', 'getter returns 2 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' exists'); | ||
s2t.equal(obj[p], 'calls: 1', 'getter returns 1 calls'); | ||
obj[p] = 'first'; | ||
s2t.equal(holder, 'holder: first', 'setter was invoked ("first")'); | ||
s2t.equal(obj[p], 'calls: 2', 'getter returns 2 calls'); | ||
var restore = mockProperty(obj, 'a', { | ||
get: undefined | ||
}); | ||
s2t.comment('mockProperty(…): ' + inspect(p)); | ||
var restore = mockProperty(obj, p, { get: undefined }); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, undefined, 'no getter, undefined'); | ||
obj.a = 'second'; | ||
s2t.equal(holder, 'holder: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj.a, undefined, 'no getter, undefined'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], undefined, 'no getter, undefined'); | ||
obj[p] = 'second'; | ||
s2t.equal(holder, 'holder: second', 'setter was invoked ("second")'); | ||
s2t.equal(obj[p], undefined, 'no getter, undefined'); | ||
t.comment('restore'); | ||
restore(); | ||
s2t.comment('restore: ' + inspect(p)); | ||
restore(); | ||
s2t.ok('a' in obj, 'property still exists'); | ||
s2t.equal(obj.a, 'calls: 3', 'getter returns 3 calls'); | ||
obj.a = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
s2t.equal(obj.a, 'calls: 4', 'getter returns 4 calls'); | ||
s2t.ok(p in obj, 'property ' + inspect(p) + ' still exists'); | ||
s2t.equal(obj[p], 'calls: 3', 'getter returns 3 calls'); | ||
obj[p] = 'third'; | ||
s2t.equal(holder, 'holder: third', 'setter was invoked ("third")'); | ||
s2t.equal(obj[p], 'calls: 4', 'getter returns 4 calls'); | ||
}); | ||
@@ -1208,3 +1297,15 @@ s2t.end(); | ||
t.test('mocking a nonexistent data property, nonenumerable, with no value', function (st) { | ||
/** @type {Record<string, unknown>} */ var obj = {}; | ||
mockProperty(obj, 'foo', { nonEnumerable: true, nonWritable: false }); | ||
mockProperty(obj, 'bar', { nonEnumerable: true }); | ||
st.ok('foo' in obj, 'property "foo" exists'); | ||
st.ok('bar' in obj, 'property "bar" exists'); | ||
st.end(); | ||
}); | ||
t.end(); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
58097
11
1257
7
33
+ Addedobject-inspect@^1.13.2
+ Addedobject-inspect@1.13.2(transitive)
Updateddefine-data-property@^1.1.4
Updatedhasown@^2.0.2