-
-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1edfd9c
commit 07165bd
Showing
6 changed files
with
203 additions
and
168 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { ClearType, PropertyType } from '../Types' | ||
|
||
type ValueToMap<T extends string> = { [key in T]: key } | ||
const propertyTypes: ValueToMap<PropertyType> = { | ||
method: 'method', | ||
property: 'property' | ||
} | ||
const clearTypes: ValueToMap<ClearType> = { | ||
all: 'all', | ||
receivedCalls: 'receivedCalls', | ||
substituteValues: 'substituteValues' | ||
} | ||
|
||
export const constants = { | ||
PROPERTY: propertyTypes, | ||
CLEAR: clearTypes | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { AssertionMethod, ClearType, ConfigurationMethod, PropertyType, SubstituteMethod, SubstitutionMethod } from '../Types' | ||
import { constants } from './Constants' | ||
|
||
const isAssertionMethod = (property: PropertyKey): property is AssertionMethod => | ||
property === 'received' || property === 'didNotReceive' | ||
const isConfigurationMethod = (property: PropertyKey): property is ConfigurationMethod => property === 'clearSubstitute' || property === 'mimick' | ||
const isSubstitutionMethod = (property: PropertyKey): property is SubstitutionMethod => | ||
property === 'mimicks' || property === 'returns' || property === 'throws' || property === 'resolves' || property === 'rejects' | ||
const isSubstituteMethod = (property: PropertyKey): property is SubstituteMethod => | ||
isSubstitutionMethod(property) || isConfigurationMethod(property) || isAssertionMethod(property) | ||
|
||
const isPropertyProperty = (value: PropertyType): value is (typeof constants['PROPERTY']['property']) => value === constants.PROPERTY.property | ||
const isPropertyMethod = (value: PropertyType): value is (typeof constants['PROPERTY']['method']) => value === constants.PROPERTY.method | ||
|
||
const isClearAll = (value: ClearType): value is (typeof constants['CLEAR']['all']) => value === constants.CLEAR.all | ||
const isClearReceivedCalls = (value: ClearType): value is (typeof constants['CLEAR']['receivedCalls']) => value === constants.CLEAR.receivedCalls | ||
const isClearSubstituteValues = (value: ClearType): value is (typeof constants['CLEAR']['substituteValues']) => value === constants.CLEAR.substituteValues | ||
|
||
export const method = { | ||
assertion: isAssertionMethod, | ||
configuration: isConfigurationMethod, | ||
substitution: isSubstitutionMethod, | ||
substitute: isSubstituteMethod, | ||
} | ||
|
||
export const PROPERTY = { | ||
property: isPropertyProperty, | ||
method: isPropertyMethod | ||
} | ||
|
||
export const CLEAR = { | ||
all: isClearAll, | ||
receivedCalls: isClearReceivedCalls, | ||
substituteValues: isClearSubstituteValues | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { inspect } from 'node:util' | ||
import { RecordedArguments } from '../RecordedArguments' | ||
import { SubstituteNodeModel } from '../Types' | ||
import { TextBuilder, TextPart } from './TextBuilder' | ||
|
||
const stringifyArguments = (args: RecordedArguments) => args.hasArguments() | ||
? `(${args.value.map(x => inspect(x, { colors: true })).join(', ')})` | ||
: '' | ||
|
||
const matchBasedPrefix = (isMatch?: boolean) => { | ||
switch (isMatch) { | ||
case true: return '✔ ' | ||
case false: return '✘ ' | ||
default: return '' | ||
} | ||
} | ||
|
||
const matchBasedTextPartModifier = (isMatch?: boolean) => (part: TextPart) => isMatch === undefined | ||
? part | ||
: isMatch | ||
? part.faint() | ||
: part.bold() | ||
|
||
const stringifyCall = (context: { callPath: string, expectedArguments?: RecordedArguments }) => { | ||
return (call: SubstituteNodeModel): TextPart[] => { | ||
const isMatch = context.expectedArguments?.match(call.recordedArguments) | ||
const textBuilder = new TextBuilder() | ||
.add(matchBasedPrefix(isMatch)) | ||
.add(context.callPath) | ||
.add(stringifyArguments(call.recordedArguments)) | ||
if (call.stack !== undefined && isMatch !== undefined) textBuilder.newLine().add(call.stack.split('\n')[1].replace('at ', 'called at '), t => t.faint()) | ||
return textBuilder.parts.map(matchBasedTextPartModifier(isMatch)) | ||
} | ||
} | ||
|
||
const plurify = (str: string, count?: number) => `${str}${count === 1 ? '' : 's'}` | ||
|
||
const stringifyExpectation = (expected: { count: number | undefined, call: SubstituteNodeModel }) => { | ||
const textBuilder = new TextBuilder() | ||
textBuilder.add(expected.count === undefined ? '1 or more' : expected.count.toString(), t => t.bold()) | ||
.add(' ') | ||
.add(expected.call.propertyType, t => t.bold()) | ||
.add(plurify(' call', expected.count), t => t.bold()) | ||
.add(' matching ') | ||
.addParts(...stringifyCall({ callPath: expected.call.key.toString() })(expected.call).map(t => t.bold())) | ||
return textBuilder.parts | ||
} | ||
|
||
const createKey = () => { | ||
const textBuilder = new TextBuilder() | ||
textBuilder.newLine().add('› ') | ||
return textBuilder | ||
} | ||
|
||
const stringifyReceivedCalls = (callPath: string, expected: SubstituteNodeModel, received: SubstituteNodeModel[]) => { | ||
const textBuilder = new TextBuilder() | ||
const stringify = stringifyCall({ callPath, expectedArguments: expected.recordedArguments }) | ||
received.forEach(receivedCall => textBuilder.addParts(...createKey().parts, ...stringify(receivedCall))) | ||
return textBuilder.newLine().toString() | ||
} | ||
|
||
// const stringifyNode | ||
|
||
export const stringify = { | ||
call: stringifyCall, | ||
expectation: stringifyExpectation, | ||
receivedCalls: stringifyReceivedCalls | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
export class TextPart { | ||
private _modifiers: string[] = [] | ||
private readonly _value: string | ||
constructor(valueOrInstance: string | TextPart) { | ||
if (valueOrInstance instanceof TextPart) { | ||
this._modifiers = [...valueOrInstance._modifiers] | ||
this._value = valueOrInstance._value | ||
} else this._value = valueOrInstance | ||
} | ||
|
||
private baseTextModifier(modifier: number) { | ||
return `\x1b[${modifier}m` | ||
} | ||
|
||
public bold() { | ||
this._modifiers.push(this.baseTextModifier(1)) | ||
return this | ||
} | ||
|
||
public faint() { | ||
this._modifiers.push(this.baseTextModifier(2)) | ||
return this | ||
} | ||
|
||
public italic() { | ||
this._modifiers.push(this.baseTextModifier(3)) | ||
return this | ||
} | ||
|
||
public underline() { | ||
this._modifiers.push(this.baseTextModifier(4)) | ||
return this | ||
} | ||
|
||
public resetFormat(): void { | ||
this._modifiers = [] | ||
} | ||
|
||
public clone(): TextPart { | ||
return new TextPart(this) | ||
} | ||
|
||
toString() { | ||
return this._modifiers.length > 0 ? `${this._modifiers.join('')}${this._value}\x1b[0m` : this._value | ||
} | ||
} | ||
|
||
export class TextBuilder { | ||
private readonly _parts: TextPart[] = [] | ||
|
||
public add(text: string, texPartCb: (textPart: TextPart) => void = () => { }): this { | ||
const textPart = new TextPart(text) | ||
this._parts.push(textPart) | ||
texPartCb(textPart) | ||
return this | ||
} | ||
|
||
public addParts(...textParts: TextPart[]): this { | ||
this._parts.push(...textParts) | ||
return this | ||
} | ||
|
||
public newLine() { | ||
this._parts.push(new TextPart('\n')) | ||
return this | ||
} | ||
|
||
public toString() { | ||
return this._parts.join('') | ||
} | ||
|
||
public clone() { | ||
return new TextBuilder().addParts(...this._parts.map(x => x.clone())) | ||
} | ||
|
||
public get parts() { | ||
return this._parts | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export * from './TextBuilder' | ||
export * from './Stringify' | ||
export * from './Constants' | ||
export * as is from './Guards' |