Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

mock-property

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mock-property - npm Package Compare versions

Comparing version 1.0.3 to 1.1.0

index.d.ts

14

CHANGELOG.md

@@ -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:../../"
}
}
}

@@ -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();
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc