* Bump the npm group with 12 updates Bumps the npm group with 12 updates: | Package | From | To | | --- | --- | --- | | [@octokit/types](https://github.com/octokit/types.ts) | `12.1.1` | `12.3.0` | | [@types/uuid](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/uuid) | `9.0.6` | `9.0.7` | | [@types/adm-zip](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/adm-zip) | `0.5.3` | `0.5.4` | | [@types/js-yaml](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/js-yaml) | `4.0.8` | `4.0.9` | | [@types/semver](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/semver) | `7.5.4` | `7.5.5` | | [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) | `6.9.1` | `6.12.0` | | [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `6.9.1` | `6.12.0` | | [eslint](https://github.com/eslint/eslint) | `8.52.0` | `8.54.0` | | [nock](https://github.com/nock/nock) | `13.3.7` | `13.3.8` | | [sinon](https://github.com/sinonjs/sinon) | `17.0.0` | `17.0.1` | | [@types/sinon](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/sinon) | `10.0.20` | `17.0.1` | | [typescript](https://github.com/Microsoft/TypeScript) | `5.2.2` | `5.3.2` | Updates `@octokit/types` from 12.1.1 to 12.3.0 - [Release notes](https://github.com/octokit/types.ts/releases) - [Commits](https://github.com/octokit/types.ts/compare/v12.1.1...v12.3.0) Updates `@types/uuid` from 9.0.6 to 9.0.7 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/uuid) Updates `@types/adm-zip` from 0.5.3 to 0.5.4 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/adm-zip) Updates `@types/js-yaml` from 4.0.8 to 4.0.9 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/js-yaml) Updates `@types/semver` from 7.5.4 to 7.5.5 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/semver) Updates `@typescript-eslint/eslint-plugin` from 6.9.1 to 6.12.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.12.0/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 6.9.1 to 6.12.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.12.0/packages/parser) Updates `eslint` from 8.52.0 to 8.54.0 - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.52.0...v8.54.0) Updates `nock` from 13.3.7 to 13.3.8 - [Release notes](https://github.com/nock/nock/releases) - [Changelog](https://github.com/nock/nock/blob/main/CHANGELOG.md) - [Commits](https://github.com/nock/nock/compare/v13.3.7...v13.3.8) Updates `sinon` from 17.0.0 to 17.0.1 - [Release notes](https://github.com/sinonjs/sinon/releases) - [Changelog](https://github.com/sinonjs/sinon/blob/main/docs/changelog.md) - [Commits](https://github.com/sinonjs/sinon/compare/v17.0.0...v17.0.1) Updates `@types/sinon` from 10.0.20 to 17.0.1 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/sinon) Updates `typescript` from 5.2.2 to 5.3.2 - [Release notes](https://github.com/Microsoft/TypeScript/releases) - [Commits](https://github.com/Microsoft/TypeScript/commits) --- updated-dependencies: - dependency-name: "@octokit/types" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: npm - dependency-name: "@types/uuid" dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm - dependency-name: "@types/adm-zip" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm - dependency-name: "@types/js-yaml" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm - dependency-name: "@types/semver" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm - dependency-name: nock dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm - dependency-name: sinon dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm - dependency-name: "@types/sinon" dependency-type: direct:development update-type: version-update:semver-major dependency-group: npm - dependency-name: typescript dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm ... Signed-off-by: dependabot[bot] <support@github.com> * Update checked-in dependencies * Rebuild --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
538 lines
15 KiB
JavaScript
538 lines
15 KiB
JavaScript
"use strict";
|
|
|
|
const arrayProto = require("@sinonjs/commons").prototypes.array;
|
|
const logger = require("@sinonjs/commons").deprecated;
|
|
const collectOwnMethods = require("./collect-own-methods");
|
|
const getPropertyDescriptor = require("./util/core/get-property-descriptor");
|
|
const isPropertyConfigurable = require("./util/core/is-property-configurable");
|
|
const match = require("@sinonjs/samsam").createMatcher;
|
|
const sinonAssert = require("./assert");
|
|
const sinonClock = require("./util/fake-timers");
|
|
const sinonMock = require("./mock");
|
|
const sinonSpy = require("./spy");
|
|
const sinonStub = require("./stub");
|
|
const sinonCreateStubInstance = require("./create-stub-instance");
|
|
const sinonFake = require("./fake");
|
|
const valueToString = require("@sinonjs/commons").valueToString;
|
|
const fakeServer = require("nise").fakeServer;
|
|
const fakeXhr = require("nise").fakeXhr;
|
|
const usePromiseLibrary = require("./util/core/use-promise-library");
|
|
|
|
const DEFAULT_LEAK_THRESHOLD = 10000;
|
|
|
|
const filter = arrayProto.filter;
|
|
const forEach = arrayProto.forEach;
|
|
const push = arrayProto.push;
|
|
const reverse = arrayProto.reverse;
|
|
|
|
function applyOnEach(fakes, method) {
|
|
const matchingFakes = filter(fakes, function (fake) {
|
|
return typeof fake[method] === "function";
|
|
});
|
|
|
|
forEach(matchingFakes, function (fake) {
|
|
fake[method]();
|
|
});
|
|
}
|
|
|
|
function throwOnAccessors(descriptor) {
|
|
if (typeof descriptor.get === "function") {
|
|
throw new Error("Use sandbox.replaceGetter for replacing getters");
|
|
}
|
|
|
|
if (typeof descriptor.set === "function") {
|
|
throw new Error("Use sandbox.replaceSetter for replacing setters");
|
|
}
|
|
}
|
|
|
|
function verifySameType(object, property, replacement) {
|
|
if (typeof object[property] !== typeof replacement) {
|
|
throw new TypeError(
|
|
`Cannot replace ${typeof object[
|
|
property
|
|
]} with ${typeof replacement}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
function checkForValidArguments(descriptor, property, replacement) {
|
|
if (typeof descriptor === "undefined") {
|
|
throw new TypeError(
|
|
`Cannot replace non-existent property ${valueToString(
|
|
property,
|
|
)}. Perhaps you meant sandbox.define()?`,
|
|
);
|
|
}
|
|
|
|
if (typeof replacement === "undefined") {
|
|
throw new TypeError("Expected replacement argument to be defined");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A sinon sandbox
|
|
*
|
|
* @param opts
|
|
* @param {object} [opts.assertOptions] see the CreateAssertOptions in ./assert
|
|
* @class
|
|
*/
|
|
function Sandbox(opts = {}) {
|
|
const sandbox = this;
|
|
const assertOptions = opts.assertOptions || {};
|
|
let fakeRestorers = [];
|
|
let promiseLib;
|
|
|
|
let collection = [];
|
|
let loggedLeakWarning = false;
|
|
sandbox.leakThreshold = DEFAULT_LEAK_THRESHOLD;
|
|
|
|
function addToCollection(object) {
|
|
if (
|
|
push(collection, object) > sandbox.leakThreshold &&
|
|
!loggedLeakWarning
|
|
) {
|
|
// eslint-disable-next-line no-console
|
|
logger.printWarning(
|
|
"Potential memory leak detected; be sure to call restore() to clean up your sandbox. To suppress this warning, modify the leakThreshold property of your sandbox.",
|
|
);
|
|
loggedLeakWarning = true;
|
|
}
|
|
}
|
|
|
|
sandbox.assert = sinonAssert.createAssertObject(assertOptions);
|
|
|
|
sandbox.serverPrototype = fakeServer;
|
|
|
|
// this is for testing only
|
|
sandbox.getFakes = function getFakes() {
|
|
return collection;
|
|
};
|
|
|
|
sandbox.createStubInstance = function createStubInstance() {
|
|
const stubbed = sinonCreateStubInstance.apply(null, arguments);
|
|
|
|
const ownMethods = collectOwnMethods(stubbed);
|
|
|
|
forEach(ownMethods, function (method) {
|
|
addToCollection(method);
|
|
});
|
|
|
|
usePromiseLibrary(promiseLib, ownMethods);
|
|
|
|
return stubbed;
|
|
};
|
|
|
|
sandbox.inject = function inject(obj) {
|
|
obj.spy = function () {
|
|
return sandbox.spy.apply(null, arguments);
|
|
};
|
|
|
|
obj.stub = function () {
|
|
return sandbox.stub.apply(null, arguments);
|
|
};
|
|
|
|
obj.mock = function () {
|
|
return sandbox.mock.apply(null, arguments);
|
|
};
|
|
|
|
obj.createStubInstance = function () {
|
|
return sandbox.createStubInstance.apply(sandbox, arguments);
|
|
};
|
|
|
|
obj.fake = function () {
|
|
return sandbox.fake.apply(null, arguments);
|
|
};
|
|
|
|
obj.define = function () {
|
|
return sandbox.define.apply(null, arguments);
|
|
};
|
|
|
|
obj.replace = function () {
|
|
return sandbox.replace.apply(null, arguments);
|
|
};
|
|
|
|
obj.replaceSetter = function () {
|
|
return sandbox.replaceSetter.apply(null, arguments);
|
|
};
|
|
|
|
obj.replaceGetter = function () {
|
|
return sandbox.replaceGetter.apply(null, arguments);
|
|
};
|
|
|
|
if (sandbox.clock) {
|
|
obj.clock = sandbox.clock;
|
|
}
|
|
|
|
if (sandbox.server) {
|
|
obj.server = sandbox.server;
|
|
obj.requests = sandbox.server.requests;
|
|
}
|
|
|
|
obj.match = match;
|
|
|
|
return obj;
|
|
};
|
|
|
|
sandbox.mock = function mock() {
|
|
const m = sinonMock.apply(null, arguments);
|
|
|
|
addToCollection(m);
|
|
usePromiseLibrary(promiseLib, m);
|
|
|
|
return m;
|
|
};
|
|
|
|
sandbox.reset = function reset() {
|
|
applyOnEach(collection, "reset");
|
|
applyOnEach(collection, "resetHistory");
|
|
};
|
|
|
|
sandbox.resetBehavior = function resetBehavior() {
|
|
applyOnEach(collection, "resetBehavior");
|
|
};
|
|
|
|
sandbox.resetHistory = function resetHistory() {
|
|
function privateResetHistory(f) {
|
|
const method = f.resetHistory || f.reset;
|
|
if (method) {
|
|
method.call(f);
|
|
}
|
|
}
|
|
|
|
forEach(collection, privateResetHistory);
|
|
};
|
|
|
|
sandbox.restore = function restore() {
|
|
if (arguments.length) {
|
|
throw new Error(
|
|
"sandbox.restore() does not take any parameters. Perhaps you meant stub.restore()",
|
|
);
|
|
}
|
|
|
|
reverse(collection);
|
|
applyOnEach(collection, "restore");
|
|
collection = [];
|
|
|
|
forEach(fakeRestorers, function (restorer) {
|
|
restorer();
|
|
});
|
|
fakeRestorers = [];
|
|
|
|
sandbox.restoreContext();
|
|
};
|
|
|
|
sandbox.restoreContext = function restoreContext() {
|
|
if (!sandbox.injectedKeys) {
|
|
return;
|
|
}
|
|
|
|
forEach(sandbox.injectedKeys, function (injectedKey) {
|
|
delete sandbox.injectInto[injectedKey];
|
|
});
|
|
|
|
sandbox.injectedKeys.length = 0;
|
|
};
|
|
|
|
/**
|
|
* Creates a restorer function for the property
|
|
*
|
|
* @param {object|Function} object
|
|
* @param {string} property
|
|
* @param {boolean} forceAssignment
|
|
* @returns {Function} restorer function
|
|
*/
|
|
function getFakeRestorer(object, property, forceAssignment = false) {
|
|
const descriptor = getPropertyDescriptor(object, property);
|
|
const value = object[property];
|
|
|
|
function restorer() {
|
|
if (forceAssignment) {
|
|
object[property] = value;
|
|
} else if (descriptor?.isOwn) {
|
|
Object.defineProperty(object, property, descriptor);
|
|
} else {
|
|
delete object[property];
|
|
}
|
|
}
|
|
|
|
restorer.object = object;
|
|
restorer.property = property;
|
|
return restorer;
|
|
}
|
|
|
|
function verifyNotReplaced(object, property) {
|
|
forEach(fakeRestorers, function (fakeRestorer) {
|
|
if (
|
|
fakeRestorer.object === object &&
|
|
fakeRestorer.property === property
|
|
) {
|
|
throw new TypeError(
|
|
`Attempted to replace ${property} which is already replaced`,
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Replace an existing property
|
|
*
|
|
* @param {object|Function} object
|
|
* @param {string} property
|
|
* @param {*} replacement a fake, stub, spy or any other value
|
|
* @returns {*}
|
|
*/
|
|
sandbox.replace = function replace(object, property, replacement) {
|
|
const descriptor = getPropertyDescriptor(object, property);
|
|
checkForValidArguments(descriptor, property, replacement);
|
|
throwOnAccessors(descriptor);
|
|
verifySameType(object, property, replacement);
|
|
|
|
verifyNotReplaced(object, property);
|
|
|
|
// store a function for restoring the replaced property
|
|
push(fakeRestorers, getFakeRestorer(object, property));
|
|
|
|
object[property] = replacement;
|
|
|
|
return replacement;
|
|
};
|
|
|
|
sandbox.replace.usingAccessor = function replaceUsingAccessor(
|
|
object,
|
|
property,
|
|
replacement,
|
|
) {
|
|
const descriptor = getPropertyDescriptor(object, property);
|
|
checkForValidArguments(descriptor, property, replacement);
|
|
verifySameType(object, property, replacement);
|
|
|
|
verifyNotReplaced(object, property);
|
|
|
|
// store a function for restoring the replaced property
|
|
push(fakeRestorers, getFakeRestorer(object, property, true));
|
|
|
|
object[property] = replacement;
|
|
|
|
return replacement;
|
|
};
|
|
|
|
sandbox.define = function define(object, property, value) {
|
|
const descriptor = getPropertyDescriptor(object, property);
|
|
|
|
if (descriptor) {
|
|
throw new TypeError(
|
|
`Cannot define the already existing property ${valueToString(
|
|
property,
|
|
)}. Perhaps you meant sandbox.replace()?`,
|
|
);
|
|
}
|
|
|
|
if (typeof value === "undefined") {
|
|
throw new TypeError("Expected value argument to be defined");
|
|
}
|
|
|
|
verifyNotReplaced(object, property);
|
|
|
|
// store a function for restoring the defined property
|
|
push(fakeRestorers, getFakeRestorer(object, property));
|
|
|
|
object[property] = value;
|
|
|
|
return value;
|
|
};
|
|
|
|
sandbox.replaceGetter = function replaceGetter(
|
|
object,
|
|
property,
|
|
replacement,
|
|
) {
|
|
const descriptor = getPropertyDescriptor(object, property);
|
|
|
|
if (typeof descriptor === "undefined") {
|
|
throw new TypeError(
|
|
`Cannot replace non-existent property ${valueToString(
|
|
property,
|
|
)}`,
|
|
);
|
|
}
|
|
|
|
if (typeof replacement !== "function") {
|
|
throw new TypeError(
|
|
"Expected replacement argument to be a function",
|
|
);
|
|
}
|
|
|
|
if (typeof descriptor.get !== "function") {
|
|
throw new Error("`object.property` is not a getter");
|
|
}
|
|
|
|
verifyNotReplaced(object, property);
|
|
|
|
// store a function for restoring the replaced property
|
|
push(fakeRestorers, getFakeRestorer(object, property));
|
|
|
|
Object.defineProperty(object, property, {
|
|
get: replacement,
|
|
configurable: isPropertyConfigurable(object, property),
|
|
});
|
|
|
|
return replacement;
|
|
};
|
|
|
|
sandbox.replaceSetter = function replaceSetter(
|
|
object,
|
|
property,
|
|
replacement,
|
|
) {
|
|
const descriptor = getPropertyDescriptor(object, property);
|
|
|
|
if (typeof descriptor === "undefined") {
|
|
throw new TypeError(
|
|
`Cannot replace non-existent property ${valueToString(
|
|
property,
|
|
)}`,
|
|
);
|
|
}
|
|
|
|
if (typeof replacement !== "function") {
|
|
throw new TypeError(
|
|
"Expected replacement argument to be a function",
|
|
);
|
|
}
|
|
|
|
if (typeof descriptor.set !== "function") {
|
|
throw new Error("`object.property` is not a setter");
|
|
}
|
|
|
|
verifyNotReplaced(object, property);
|
|
|
|
// store a function for restoring the replaced property
|
|
push(fakeRestorers, getFakeRestorer(object, property));
|
|
|
|
// eslint-disable-next-line accessor-pairs
|
|
Object.defineProperty(object, property, {
|
|
set: replacement,
|
|
configurable: isPropertyConfigurable(object, property),
|
|
});
|
|
|
|
return replacement;
|
|
};
|
|
|
|
function commonPostInitSetup(args, spy) {
|
|
const [object, property, types] = args;
|
|
|
|
const isSpyingOnEntireObject =
|
|
typeof property === "undefined" && typeof object === "object";
|
|
|
|
if (isSpyingOnEntireObject) {
|
|
const ownMethods = collectOwnMethods(spy);
|
|
|
|
forEach(ownMethods, function (method) {
|
|
addToCollection(method);
|
|
});
|
|
|
|
usePromiseLibrary(promiseLib, ownMethods);
|
|
} else if (Array.isArray(types)) {
|
|
for (const accessorType of types) {
|
|
addToCollection(spy[accessorType]);
|
|
usePromiseLibrary(promiseLib, spy[accessorType]);
|
|
}
|
|
} else {
|
|
addToCollection(spy);
|
|
usePromiseLibrary(promiseLib, spy);
|
|
}
|
|
|
|
return spy;
|
|
}
|
|
|
|
sandbox.spy = function spy() {
|
|
const createdSpy = sinonSpy.apply(sinonSpy, arguments);
|
|
return commonPostInitSetup(arguments, createdSpy);
|
|
};
|
|
|
|
sandbox.stub = function stub() {
|
|
const createdStub = sinonStub.apply(sinonStub, arguments);
|
|
return commonPostInitSetup(arguments, createdStub);
|
|
};
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
sandbox.fake = function fake(f) {
|
|
const s = sinonFake.apply(sinonFake, arguments);
|
|
|
|
addToCollection(s);
|
|
|
|
return s;
|
|
};
|
|
|
|
forEach(Object.keys(sinonFake), function (key) {
|
|
const fakeBehavior = sinonFake[key];
|
|
if (typeof fakeBehavior === "function") {
|
|
sandbox.fake[key] = function () {
|
|
const s = fakeBehavior.apply(fakeBehavior, arguments);
|
|
|
|
addToCollection(s);
|
|
|
|
return s;
|
|
};
|
|
}
|
|
});
|
|
|
|
sandbox.useFakeTimers = function useFakeTimers(args) {
|
|
const clock = sinonClock.useFakeTimers.call(null, args);
|
|
|
|
sandbox.clock = clock;
|
|
addToCollection(clock);
|
|
|
|
return clock;
|
|
};
|
|
|
|
sandbox.verify = function verify() {
|
|
applyOnEach(collection, "verify");
|
|
};
|
|
|
|
sandbox.verifyAndRestore = function verifyAndRestore() {
|
|
let exception;
|
|
|
|
try {
|
|
sandbox.verify();
|
|
} catch (e) {
|
|
exception = e;
|
|
}
|
|
|
|
sandbox.restore();
|
|
|
|
if (exception) {
|
|
throw exception;
|
|
}
|
|
};
|
|
|
|
sandbox.useFakeServer = function useFakeServer() {
|
|
const proto = sandbox.serverPrototype || fakeServer;
|
|
|
|
if (!proto || !proto.create) {
|
|
return null;
|
|
}
|
|
|
|
sandbox.server = proto.create();
|
|
addToCollection(sandbox.server);
|
|
|
|
return sandbox.server;
|
|
};
|
|
|
|
sandbox.useFakeXMLHttpRequest = function useFakeXMLHttpRequest() {
|
|
const xhr = fakeXhr.useFakeXMLHttpRequest();
|
|
addToCollection(xhr);
|
|
return xhr;
|
|
};
|
|
|
|
sandbox.usingPromise = function usingPromise(promiseLibrary) {
|
|
promiseLib = promiseLibrary;
|
|
collection.promiseLibrary = promiseLibrary;
|
|
|
|
return sandbox;
|
|
};
|
|
}
|
|
|
|
Sandbox.prototype.match = match;
|
|
|
|
module.exports = Sandbox;
|