Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: assertion log limit #2485

Merged
merged 8 commits into from Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 19 additions & 4 deletions .unimportedrc.json
@@ -1,8 +1,23 @@
{
"entry": ["lib/sinon.js", "lib/sinon-esm.js"],
"extensions": [".js"],
"ignorePatterns": ["**/node_modules/**"],
"entry": [
"lib/sinon.js",
"lib/sinon-esm.js",
"test/**/*-test.js",
"test/webworker/webworker-script.js",
"test/webworker/webworker-support-assessment.js"
],
"extensions": [
".js"
],
"ignorePatterns": [
"**/node_modules/**"
],
"ignoreUnresolved": [],
"ignoreUnimported": ["docs/**", "pkg/**", "test/**"],
"ignoreUnimported": [
"docs/**",
"pkg/**",
"vendor/**/*",
"test/es2015/check-esm-bundle-is-runnable.js"
],
"ignoreUnused": []
}
1 change: 0 additions & 1 deletion lib/create-sinon-api.js
Expand Up @@ -21,7 +21,6 @@ module.exports = function createApi(opts = { sinonXhrLib: nise }) {

const apiMethods = {
createSandbox: createSandbox,
assert: require("./sinon/assert"),
match: require("@sinonjs/samsam").createMatcher,
restoreObject: require("./sinon/restore-object"),

Expand Down
59 changes: 56 additions & 3 deletions lib/sinon/assert.js
@@ -1,4 +1,5 @@
"use strict";
/** @module */

const arrayProto = require("@sinonjs/commons").prototypes.array;
const calledInOrder = require("@sinonjs/commons").calledInOrder;
Expand All @@ -15,12 +16,48 @@ const forEach = arrayProto.forEach;
const join = arrayProto.join;
const splice = arrayProto.splice;

function createAssertObject() {
function applyDefaults(obj, defaults) {
for (const key of Object.keys(defaults)) {
const val = obj[key];
if (val === null || typeof val === "undefined") {
obj[key] = defaults[key];
}
}
}

/**
* @typedef {object} CreateAssertOptions
* @global
*
* @property {boolean} [shouldLimitAssertionLogs] default is false
* @property {number} [assertionLogLimit] default is 10K
*/

/**
* Create an assertion object that exposes several methods to invoke
*
* @param {CreateAssertOptions} [opts] options bag
* @returns {object} object with multiple assertion methods
*/
function createAssertObject(opts) {
const cleanedAssertOptions = opts || {};
applyDefaults(cleanedAssertOptions, {
shouldLimitAssertionLogs: false,
assertionLogLimit: 1e4,
});

const assert = {
failException: "AssertError",

fail: function fail(message) {
const error = new Error(message);
let msg = message;
if (cleanedAssertOptions.shouldLimitAssertionLogs) {
msg = message.substring(
0,
cleanedAssertOptions.assertionLogLimit,
);
}
const error = new Error(msg);
error.name = this.failException || assert.failException;

throw error;
Expand Down Expand Up @@ -296,4 +333,20 @@ function createAssertObject() {
}

module.exports = createAssertObject();
module.exports.createAssertObject = createAssertObject;
Object.defineProperty(module.exports, "createAssertObject", {
get() {
return createAssertObject;
},
});

// allow for easy mocking
module.exports.mock = {};
Object.defineProperty(module.exports.mock, "createAssertObject", {
fatso83 marked this conversation as resolved.
Show resolved Hide resolved
get() {
return createAssertObject;
},
set(newImpl) {
// eslint-disable-next-line no-func-assign
createAssertObject = newImpl;
},
});
30 changes: 29 additions & 1 deletion lib/sinon/create-sandbox.js
Expand Up @@ -7,7 +7,7 @@ const forEach = arrayProto.forEach;
const push = arrayProto.push;

function prepareSandboxFromConfig(config) {
const sandbox = new Sandbox();
const sandbox = new Sandbox({ assertOptions: config.assertOptions });

if (config.useFakeServer) {
if (typeof config.useFakeServer === "object") {
Expand Down Expand Up @@ -41,6 +41,34 @@ function exposeValue(sandbox, config, key, value) {
}
}

/**
* Customize the sandbox.
* This is mostly an integration feature most users will not need
*
* @typedef {object} SandboxConfig
* @property {string[]} properties The properties of the API to expose on the sandbox. Examples: ['spy', 'fake', 'restore']
* @property {(object|null)} injectInto TBD
* @property {boolean} useFakeTimers whether timers are faked by default
* @property {boolean} useFakeServer whether XHR's are faked and the server feature enabled by default
* @property {object} [assertOptions] see CreateAssertOptions in ./assert
*/
// This type def is really suffering from JSDoc not being
// able to reference types in other modules

/**
* A configured sinon sandbox.
*
* @typedef {object} ConfiguredSinonSandboxType
* @augments Sandbox
* @property {string[]} injectedKeys the keys that have been injected (from config.injectInto)
* @property {*} injectInto TBD
* @property {*[]} args the arguments for the sandbox
*/

/**
* @param config {SandboxConfig}
* @returns {Sandbox}
*/
function createSandbox(config) {
if (!config) {
return new Sandbox();
Expand Down
12 changes: 10 additions & 2 deletions lib/sinon/sandbox.js
Expand Up @@ -69,8 +69,16 @@ function checkForValidArguments(descriptor, property, replacement) {
}
}

function Sandbox() {
/**
* 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;

Expand All @@ -91,7 +99,7 @@ function Sandbox() {
}
}

sandbox.assert = sinonAssert.createAssertObject();
sandbox.assert = sinonAssert.createAssertObject(assertOptions);

sandbox.serverPrototype = fakeServer;

Expand Down
12 changes: 12 additions & 0 deletions test/assert-test.js
Expand Up @@ -65,6 +65,18 @@ describe("assert", function () {
sinonAssert.failException = this.exceptionName;
});

it("can be configured to limit the error message length", function () {
const customAssert = sinonAssert.createAssertObject({
shouldLimitAssertionLogs: true,
assertionLogLimit: 10,
});

assert.exception(
() => customAssert.fail("1234567890--THIS SHOULD NOT SHOW--"),
{ message: "1234567890" },
);
});

it("throws exception", function () {
assert.exception(
function () {
Expand Down
31 changes: 31 additions & 0 deletions test/create-sandbox-test.js
@@ -0,0 +1,31 @@
"use strict";

const sinonAssert = require("../lib/sinon/assert");
const createSandbox = require("../lib/sinon/create-sandbox");

describe("create-sandbox", function () {
it("passes on options to the creation of the assert object", function () {
fatso83 marked this conversation as resolved.
Show resolved Hide resolved
// Arrange
const sb = createSandbox();
const spy = sb.spy();
sb.replace.usingAccessor(sinonAssert.mock, "createAssertObject", spy);

// Act
createSandbox({
assertOptions: {
shouldLimitAssertionLogs: true,
assertionLogLimit: 1234,
},
});

// Assert
sb.assert.calledWith(
spy,
sb.match({
shouldLimitAssertionLogs: true,
assertionLogLimit: 1234,
}),
);
sb.restore();
});
});