@fluffy-spoon/substitute
Advanced tools
Comparing version 2.0.0-beta.3 to 2.0.0-beta.4
@@ -6,6 +6,6 @@ declare type PredicateFunction<T> = (arg: T) => boolean; | ||
declare class BaseArgument<T> { | ||
private _description; | ||
private _matchingFunction; | ||
private _options?; | ||
constructor(_description: string, _matchingFunction: PredicateFunction<T>, _options?: ArgumentOptions | undefined); | ||
private _description; | ||
constructor(description: string, _matchingFunction: PredicateFunction<T>, _options?: ArgumentOptions | undefined); | ||
matches(arg: T): boolean; | ||
@@ -12,0 +12,0 @@ toString(): string; |
@@ -5,6 +5,7 @@ "use strict"; | ||
class BaseArgument { | ||
constructor(_description, _matchingFunction, _options) { | ||
this._description = _description; | ||
constructor(description, _matchingFunction, _options) { | ||
var _a; | ||
this._matchingFunction = _matchingFunction; | ||
this._options = _options; | ||
this._description = `${((_a = this._options) === null || _a === void 0 ? void 0 : _a.inverseMatch) ? 'Not ' : ''}${description}`; | ||
} | ||
@@ -35,3 +36,3 @@ matches(arg) { | ||
constructor() { | ||
super('{all}', () => true, {}); | ||
super('Arg.all{}', () => true, {}); | ||
this._type = 'AllArguments'; | ||
@@ -59,6 +60,6 @@ } | ||
Arg.all = () => new AllArguments(); | ||
const isFunction = (predicate, options) => new Argument(`{predicate ${toStringify(predicate)}}`, predicate, options); | ||
const isFunction = (predicate, options) => new Argument(`Arg.is{${toStringify(predicate)}}`, predicate, options); | ||
Arg.is = createInversable(isFunction); | ||
const anyFunction = (type = 'any', options) => { | ||
const description = `{type ${type}}`; | ||
const description = `Arg.any{${type}}`; | ||
const predicate = (x) => { | ||
@@ -65,0 +66,0 @@ switch (type) { |
import { Substitute, SubstituteOf } from './Substitute'; | ||
declare const clear: { | ||
all: "all"; | ||
receivedCalls: "receivedCalls"; | ||
substituteValues: "substituteValues"; | ||
}; | ||
export { Arg } from './Arguments'; | ||
export { Substitute, SubstituteOf }; | ||
export { ClearType } from './Utilities'; | ||
export { clear as ClearType }; | ||
export default Substitute; |
@@ -6,6 +6,7 @@ "use strict"; | ||
Object.defineProperty(exports, "Substitute", { enumerable: true, get: function () { return Substitute_1.Substitute; } }); | ||
const utilities_1 = require("./utilities"); | ||
const clear = utilities_1.constants.CLEAR; | ||
exports.ClearType = clear; | ||
var Arguments_1 = require("./Arguments"); | ||
Object.defineProperty(exports, "Arg", { enumerable: true, get: function () { return Arguments_1.Arg; } }); | ||
var Utilities_1 = require("./Utilities"); | ||
Object.defineProperty(exports, "ClearType", { enumerable: true, get: function () { return Utilities_1.ClearType; } }); | ||
exports.default = Substitute_1.Substitute; |
@@ -1,19 +0,11 @@ | ||
import { PropertyType } from './Types'; | ||
import { RecordedArguments } from './RecordedArguments'; | ||
declare enum SubstituteExceptionTypes { | ||
CallCountMissMatch = "CallCountMissMatch", | ||
PropertyNotMocked = "PropertyNotMocked" | ||
} | ||
import { SubstituteNodeModel, SubstituteExceptionType } from './Types'; | ||
export declare class SubstituteException extends Error { | ||
type?: SubstituteExceptionTypes; | ||
constructor(msg: string, exceptionType?: SubstituteExceptionTypes); | ||
static forCallCountMissMatch(count: { | ||
expected: number | undefined; | ||
received: number; | ||
}, property: { | ||
type: PropertyType; | ||
value: PropertyKey; | ||
}, calls: { | ||
expected: RecordedArguments; | ||
received: RecordedArguments[]; | ||
type?: SubstituteExceptionType; | ||
constructor(msg: string, exceptionType?: SubstituteExceptionType); | ||
static forCallCountMismatch(expected: { | ||
count: number | undefined; | ||
call: SubstituteNodeModel; | ||
}, received: { | ||
matchCount: number; | ||
calls: SubstituteNodeModel[]; | ||
}): SubstituteException; | ||
@@ -23,2 +15,1 @@ static forPropertyNotMocked(property: PropertyKey): SubstituteException; | ||
} | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.SubstituteException = void 0; | ||
const Utilities_1 = require("./Utilities"); | ||
var SubstituteExceptionTypes; | ||
(function (SubstituteExceptionTypes) { | ||
SubstituteExceptionTypes["CallCountMissMatch"] = "CallCountMissMatch"; | ||
SubstituteExceptionTypes["PropertyNotMocked"] = "PropertyNotMocked"; | ||
})(SubstituteExceptionTypes || (SubstituteExceptionTypes = {})); | ||
const utilities_1 = require("./utilities"); | ||
class SubstituteException extends Error { | ||
constructor(msg, exceptionType) { | ||
super(msg); | ||
Error.captureStackTrace(this, SubstituteException); | ||
this.name = new.target.name; | ||
this.type = exceptionType; | ||
const errorConstructor = exceptionType !== undefined ? SubstituteException[`for${exceptionType}`] : undefined; | ||
Error.captureStackTrace(this, errorConstructor); | ||
} | ||
static forCallCountMissMatch(count, property, calls) { | ||
const propertyValue = Utilities_1.textModifier.bold(property.value.toString()); | ||
const commonMessage = `Expected ${Utilities_1.textModifier.bold(count.expected === undefined ? '1 or more' : count.expected.toString())} ${(0, Utilities_1.plurify)('call', count.expected)} to the ${Utilities_1.textModifier.italic(property.type)} ${propertyValue}`; | ||
const messageForMethods = property.type === Utilities_1.PropertyType.Method ? ` with ${(0, Utilities_1.stringifyArguments)(calls.expected)}` : ''; | ||
const receivedMessage = `, but received ${Utilities_1.textModifier.bold(count.received < 1 ? 'none' : count.received.toString())} of such calls.`; | ||
const callTrace = calls.received.length > 0 | ||
? `\nAll calls received to ${Utilities_1.textModifier.italic(property.type)} ${propertyValue}:${(0, Utilities_1.stringifyCalls)(calls.received)}` | ||
: ''; | ||
return new this(commonMessage + messageForMethods + receivedMessage + callTrace, SubstituteExceptionTypes.CallCountMissMatch); | ||
static forCallCountMismatch(expected, received) { | ||
const callPath = `@Substitute.${expected.call.property.toString()}`; | ||
const textBuilder = new utilities_1.TextBuilder() | ||
.add('Call count mismatch in ') | ||
.add('@Substitute.', t => t.underline()) | ||
.add(expected.call.property.toString(), t => t.bold().underline()) | ||
.add(':') | ||
.newLine().add('Expected to receive ') | ||
.addParts(...utilities_1.stringify.expectation(expected)) | ||
.add(', but received ') | ||
.add(received.matchCount < 1 ? 'none' : received.matchCount.toString(), t => t.faint()) | ||
.add('.'); | ||
if (received.calls.length > 0) | ||
textBuilder.newLine().add(`All property or method calls to ${callPath} received so far:${utilities_1.stringify.receivedCalls(callPath, expected.call, received.calls)}`); | ||
return new this(textBuilder.toString(), utilities_1.constants.EXCEPTION.callCountMismatch); | ||
} | ||
static forPropertyNotMocked(property) { | ||
return new this(`There is no mock for property: ${property.toString()}`, SubstituteExceptionTypes.PropertyNotMocked); | ||
return new this(`There is no mock for property: ${property.toString()}`, utilities_1.constants.EXCEPTION.propertyNotMocked); | ||
} | ||
@@ -30,0 +32,0 @@ static generic(message) { |
@@ -5,3 +5,3 @@ /// <reference types="node" /> | ||
import { RecordedArguments } from './RecordedArguments'; | ||
import type { SubstituteContext, ClearType, PropertyType } from './Types'; | ||
import type { SubstituteContext, ClearType, PropertyType, SubstituteNodeModel, AccessorType } from './Types'; | ||
import type { ObjectSubstitute } from './Transformations'; | ||
@@ -12,3 +12,3 @@ declare const instance: unique symbol; | ||
}; | ||
export declare class SubstituteNode extends SubstituteNodeBase implements ObjectSubstitute<unknown> { | ||
export declare class SubstituteNode extends SubstituteNodeBase implements ObjectSubstitute<unknown>, SubstituteNodeModel { | ||
private _proxy; | ||
@@ -21,2 +21,3 @@ private _rootContext; | ||
private _retrySubstitutionExecutionAttempt; | ||
stack?: string; | ||
private constructor(); | ||
@@ -34,3 +35,3 @@ static instance: typeof instance; | ||
get propertyType(): PropertyType; | ||
get accessorType(): "set" | "get"; | ||
get accessorType(): AccessorType; | ||
get recordedArguments(): RecordedArguments; | ||
@@ -55,5 +56,3 @@ received(amount?: number): SubstituteNode; | ||
private printableForm; | ||
private printRootNode; | ||
private printNode; | ||
} | ||
export {}; |
@@ -7,3 +7,3 @@ "use strict"; | ||
const RecordedArguments_1 = require("./RecordedArguments"); | ||
const Utilities_1 = require("./Utilities"); | ||
const utilities_1 = require("./utilities"); | ||
const SubstituteException_1 = require("./SubstituteException"); | ||
@@ -13,4 +13,4 @@ const instance = Symbol('Substitute:Instance'); | ||
all: () => true, | ||
receivedCalls: node => !node.hasContext, | ||
substituteValues: node => node.isSubstitution | ||
receivedCalls: node => utilities_1.is.CONTEXT.none(node.context), | ||
substituteValues: node => utilities_1.is.CONTEXT.substitution(node.context) | ||
}; | ||
@@ -20,6 +20,6 @@ class SubstituteNode extends SubstituteNodeBase_1.SubstituteNodeBase { | ||
super(key, parent); | ||
this._propertyType = Utilities_1.PropertyType.Property; | ||
this._accessorType = 'get'; | ||
this._propertyType = utilities_1.constants.PROPERTY.property; | ||
this._accessorType = utilities_1.constants.ACCESSOR.get; | ||
this._recordedArguments = RecordedArguments_1.RecordedArguments.none(); | ||
this._context = 'none'; | ||
this._context = utilities_1.constants.CONTEXT.none; | ||
this._retrySubstitutionExecutionAttempt = false; | ||
@@ -39,6 +39,7 @@ if (this.isRoot()) | ||
newNode.executeAssertion(); | ||
if (target.isRoot() && target.rootContext.substituteMethodsEnabled && ((0, Utilities_1.isAssertionMethod)(property) || (0, Utilities_1.isConfigurationMethod)(property))) { | ||
if (target.isRoot() && target.rootContext.substituteMethodsEnabled && (utilities_1.is.method.assertion(property) || utilities_1.is.method.configuration(property))) { | ||
newNode.assignContext(property); | ||
return newNode[property].bind(newNode); | ||
} | ||
Error.captureStackTrace(newNode, this.get); | ||
return newNode.attemptSubstitutionExecution(); | ||
@@ -56,3 +57,3 @@ }, | ||
if (target.hasDepthOfAtLeast(2)) { | ||
if ((0, Utilities_1.isSubstitutionMethod)(target.property)) | ||
if (utilities_1.is.method.substitution(target.property)) | ||
return target.parent.assignContext(target.property); | ||
@@ -62,2 +63,3 @@ if (target.parent.isAssertion) | ||
} | ||
Error.captureStackTrace(target, this.apply); | ||
return target.isAssertion ? target.proxy : target.attemptSubstitutionExecution(); | ||
@@ -86,6 +88,6 @@ } | ||
get isSubstitution() { | ||
return (0, Utilities_1.isSubstitutionMethod)(this.context); | ||
return utilities_1.is.method.substitution(this.context); | ||
} | ||
get isAssertion() { | ||
return (0, Utilities_1.isAssertionMethod)(this.context); | ||
return utilities_1.is.method.assertion(this.context); | ||
} | ||
@@ -115,3 +117,3 @@ get property() { | ||
} | ||
clearSubstitute(clearType = Utilities_1.ClearType.All) { | ||
clearSubstitute(clearType = utilities_1.constants.CLEAR.all) { | ||
this.handleMethod([clearType]); | ||
@@ -125,3 +127,3 @@ const filter = clearTypeToFilterMap[clearType]; | ||
assignContext(context) { | ||
if (!(0, Utilities_1.isSubstituteMethod)(context)) | ||
if (!utilities_1.is.method.substitute(context)) | ||
throw new Error(`Cannot assign context for property ${context.toString()}`); | ||
@@ -155,3 +157,3 @@ this._context = context; | ||
case 'mimicks': | ||
if (this.propertyType === Utilities_1.PropertyType.Property) | ||
if (utilities_1.is.PROPERTY.property(this.propertyType)) | ||
return substitutionValue(); | ||
@@ -187,3 +189,3 @@ if (!contextArguments.hasArguments()) | ||
(!finiteExpectation || expectedCount > 0)) | ||
throw SubstituteException_1.SubstituteException.forCallCountMissMatch({ expected: expectedCount, received: 0 }, { type: this.propertyType, value: this.property }, { expected: this.recordedArguments, received: allRecordedArguments }); | ||
throw SubstituteException_1.SubstituteException.forCallCountMismatch({ count: expectedCount, call: this }, { matchCount: 0, calls: siblings }); | ||
if (!hasBeenCalled || hasSiblingOfSamePropertyType) { | ||
@@ -195,4 +197,4 @@ this._scheduledAssertionException = undefined; | ||
return; | ||
const exception = SubstituteException_1.SubstituteException.forCallCountMissMatch({ expected: expectedCount, received: actualCount }, { type: this.propertyType, value: this.property }, { expected: this.recordedArguments, received: allRecordedArguments }); | ||
const potentialMethodAssertion = this.propertyType === Utilities_1.PropertyType.Property && siblings.some(sibling => sibling.propertyType === Utilities_1.PropertyType.Method); | ||
const exception = SubstituteException_1.SubstituteException.forCallCountMismatch({ count: expectedCount, call: this }, { matchCount: actualCount, calls: siblings }); | ||
const potentialMethodAssertion = utilities_1.is.PROPERTY.property(this.propertyType) && siblings.some(sibling => utilities_1.is.PROPERTY.method(sibling.propertyType)); | ||
if (potentialMethodAssertion) | ||
@@ -207,3 +209,3 @@ this.schedulePropertyAssertionException(exception); | ||
process.nextTick(() => { | ||
const nodeIsStillProperty = this.propertyType === Utilities_1.PropertyType.Property; | ||
const nodeIsStillProperty = utilities_1.is.PROPERTY.property(this.propertyType); | ||
if (nodeIsStillProperty && this._scheduledAssertionException !== undefined) | ||
@@ -214,7 +216,7 @@ throw this._scheduledAssertionException; | ||
handleSetter(value) { | ||
this._accessorType = 'set'; | ||
this._accessorType = utilities_1.constants.ACCESSOR.set; | ||
this._recordedArguments = RecordedArguments_1.RecordedArguments.from([value]); | ||
} | ||
handleMethod(rawArguments) { | ||
this._propertyType = Utilities_1.PropertyType.Method; | ||
this._propertyType = utilities_1.constants.PROPERTY.method; | ||
this._recordedArguments = RecordedArguments_1.RecordedArguments.from(rawArguments); | ||
@@ -225,4 +227,4 @@ } | ||
const strictSuitableSubstitutionsSet = commonSuitableSubstitutionsSet.filter(node => node.propertyType === this.propertyType && node.recordedArguments.match(this.recordedArguments)); | ||
const potentialSuitableSubstitutionsSet = this.propertyType === Utilities_1.PropertyType.Property && !this._retrySubstitutionExecutionAttempt ? | ||
commonSuitableSubstitutionsSet.filter(node => node.propertyType === Utilities_1.PropertyType.Method) : | ||
const potentialSuitableSubstitutionsSet = utilities_1.is.PROPERTY.property(this.propertyType) && !this._retrySubstitutionExecutionAttempt ? | ||
commonSuitableSubstitutionsSet.filter(node => utilities_1.is.PROPERTY.method(node.propertyType)) : | ||
[]; | ||
@@ -239,3 +241,3 @@ const strictSuitableSubstitutions = [...strictSuitableSubstitutionsSet]; | ||
isSpecialProperty(property) { | ||
return property === SubstituteNode.instance || property === util_1.inspect.custom || property === 'then'; | ||
return property === SubstituteNode.instance || property === util_1.inspect.custom || property === Symbol.toPrimitive || property === 'then' || property === 'toJSON'; | ||
} | ||
@@ -246,3 +248,5 @@ evaluateSpecialProperty(property) { | ||
return this; | ||
case 'toJSON': | ||
case util_1.inspect.custom: | ||
case Symbol.toPrimitive: | ||
return this.printableForm.bind(this); | ||
@@ -256,24 +260,6 @@ case 'then': | ||
printableForm(_, options) { | ||
return this.isRoot() ? this.printRootNode(options) : this.printNode(options); | ||
return this.isRoot() ? utilities_1.stringify.rootNode(this, (0, util_1.inspect)(this.recorder, options)) : utilities_1.stringify.node(this, this.child, options); | ||
} | ||
printRootNode(options) { | ||
const records = (0, util_1.inspect)(this.recorder, options); | ||
const instanceName = '*Substitute<Root>'; | ||
return instanceName + ' {' + records + '\n}'; | ||
} | ||
printNode(options) { | ||
var _a, _b; | ||
const hasContext = this.hasContext; | ||
const args = (0, util_1.inspect)(this.recordedArguments, options); | ||
const label = this.isSubstitution ? | ||
'=> ' : | ||
this.isAssertion ? | ||
`${(_a = this.child) === null || _a === void 0 ? void 0 : _a.property.toString()}` : | ||
''; | ||
const s = hasContext ? `${label}${(0, util_1.inspect)((_b = this.child) === null || _b === void 0 ? void 0 : _b.recordedArguments, options)}` : ''; | ||
const printableNode = `${this.propertyType}<${this.property.toString()}>: ${args}${s}`; | ||
return hasContext ? Utilities_1.textModifier.italic(printableNode) : printableNode; | ||
} | ||
} | ||
exports.SubstituteNode = SubstituteNode; | ||
SubstituteNode.instance = instance; |
@@ -0,2 +1,4 @@ | ||
import { RecordedArguments } from './RecordedArguments'; | ||
export declare type PropertyType = 'method' | 'property'; | ||
export declare type AccessorType = 'get' | 'set'; | ||
export declare type AssertionMethod = 'received' | 'didNotReceive'; | ||
@@ -9,2 +11,10 @@ export declare type ConfigurationMethod = 'clearSubstitute' | 'mimick'; | ||
export declare type ClearType = 'all' | 'receivedCalls' | 'substituteValues'; | ||
export declare type SubstituteExceptionType = 'CallCountMismatch' | 'PropertyNotMocked'; | ||
export declare type FilterFunction<T> = (item: T) => boolean; | ||
export declare type SubstituteNodeModel = { | ||
propertyType: PropertyType; | ||
property: PropertyKey; | ||
context: SubstituteContext; | ||
recordedArguments: RecordedArguments; | ||
stack?: string; | ||
}; |
{ | ||
"name": "@fluffy-spoon/substitute", | ||
"version": "2.0.0-beta.3", | ||
"version": "2.0.0-beta.4", | ||
"description": "TypeScript port of NSubstitute, which aims to provide a much more fluent mocking opportunity for strong-typed languages", | ||
@@ -49,7 +49,10 @@ "license": "MIT", | ||
"@sinonjs/fake-timers": "^11.2.2", | ||
"@types/node": "^12.20.55", | ||
"@types/node": "^18.19.22", | ||
"@types/sinonjs__fake-timers": "^8.1.5", | ||
"ava": "^4.3.3", | ||
"typescript": "^4.8.4" | ||
}, | ||
"volta": { | ||
"node": "18.19.1" | ||
} | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
69296
35
1331
0