CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-loopback--testlab

A collection of test utilities specifically designed for LoopBack 4 applications and TypeScript testing

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

test-doubles.mddocs/

Test Doubles and Mocking

Complete Sinon.js integration for spies, stubs, and mocks with enhanced TypeScript experience and improved stubbing utilities.

Capabilities

Sinon Integration

Complete Sinon.js library re-export with full TypeScript support.

/**
 * Complete Sinon.js library for creating test doubles
 * Includes spies, stubs, mocks, and fake timers
 */
const sinon: sinon.SinonStatic;

/**
 * Sinon spy type definition for TypeScript
 */
type SinonSpy = sinon.SinonSpy;

Usage Examples:

import { sinon } from "@loopback/testlab";

// Creating spies
const spy = sinon.spy();
const objectSpy = sinon.spy(console, 'log');

// Creating stubs
const stub = sinon.stub();
stub.returns("mocked value");
stub.withArgs("specific").returns("specific response");

// Creating mocks
const mock = sinon.mock(console);
mock.expects("log").once().withArgs("Hello");

// Fake timers
const clock = sinon.useFakeTimers();
clock.tick(1000);
clock.restore();

Enhanced Stub Instance Creation

Improved stub instance creation with better TypeScript support and stubs accessor.

/**
 * Creates a new object with the given functions as the prototype and stubs all
 * implemented functions with enhanced TypeScript support
 * @param constructor - Object or class to stub
 * @returns A stubbed version with stubs accessor
 */
function createStubInstance<TType extends object>(
  constructor: sinon.StubbableType<TType>
): StubbedInstanceWithSinonAccessor<TType>;

/**
 * Type for stubbed instances with additional stubs accessor
 * Provides both the stubbed interface and access to Sinon stub methods
 */
type StubbedInstanceWithSinonAccessor<T> = T & {
  stubs: sinon.SinonStubbedInstance<T>;
};

Usage Examples:

import { createStubInstance } from "@loopback/testlab";

class UserService {
  async findUser(id: string): Promise<User> {
    // Implementation
  }
  
  async createUser(data: UserData): Promise<User> {
    // Implementation
  }
}

// Create stubbed instance
const userServiceStub = createStubInstance(UserService);

// Configure stubs - both approaches work
userServiceStub.findUser.resolves({id: "123", name: "Alice"});
userServiceStub.stubs.findUser.resolves({id: "123", name: "Alice"});

// Use as normal instance
const user = await userServiceStub.findUser("123");

// Access stub methods for verification
expect(userServiceStub.stubs.findUser).to.have.been.calledWith("123");

Spy Capabilities

Comprehensive spy functionality for monitoring function calls.

// Spy creation methods (from Sinon)
sinon.spy(): sinon.SinonSpy;
sinon.spy(target: any, property: string): sinon.SinonSpy;
sinon.spy(func: Function): sinon.SinonSpy;

// Spy interface
interface SinonSpy {
  (): any;
  called: boolean;
  callCount: number;
  calledOnce: boolean;
  calledTwice: boolean;
  calledThrice: boolean;
  firstCall: sinon.SinonSpyCall;
  secondCall: sinon.SinonSpyCall;
  thirdCall: sinon.SinonSpyCall;
  lastCall: sinon.SinonSpyCall;
  calledBefore(anotherSpy: sinon.SinonSpy): boolean;
  calledAfter(anotherSpy: sinon.SinonSpy): boolean;
  calledOn(obj: any): boolean;
  alwaysCalledOn(obj: any): boolean;
  calledWith(...args: any[]): boolean;
  alwaysCalledWith(...args: any[]): boolean;
  calledWithExactly(...args: any[]): boolean;
  alwaysCalledWithExactly(...args: any[]): boolean;
  neverCalledWith(...args: any[]): boolean;
  threw(): boolean;
  threw(exception: string | Function): boolean;
  alwaysThrew(): boolean;
  alwaysThrew(exception: string | Function): boolean;
  returned(value: any): boolean;
  alwaysReturned(value: any): boolean;
  restore(): void;
  reset(): void;
  getCalls(): sinon.SinonSpyCall[];
}

Stub Capabilities

Advanced stubbing functionality with method chaining and conditional responses.

// Stub creation methods (from Sinon)
sinon.stub(): sinon.SinonStub;
sinon.stub(obj: any): sinon.SinonStubbedInstance<any>;
sinon.stub(obj: any, property: string): sinon.SinonStub;

// Stub interface (extends SinonSpy)
interface SinonStub extends SinonSpy {
  returns(value: any): sinon.SinonStub;
  returnsArg(index: number): sinon.SinonStub;
  returnsThis(): sinon.SinonStub;
  resolves(value?: any): sinon.SinonStub;
  rejects(error?: any): sinon.SinonStub;
  throws(error?: Error | string): sinon.SinonStub;
  callsArg(index: number): sinon.SinonStub;
  callsArgWith(index: number, ...args: any[]): sinon.SinonStub;
  yields(...args: any[]): sinon.SinonStub;
  yieldsTo(property: string, ...args: any[]): sinon.SinonStub;
  withArgs(...args: any[]): sinon.SinonStub;
  onCall(n: number): sinon.SinonStub;
  onFirstCall(): sinon.SinonStub;
  onSecondCall(): sinon.SinonStub;
  onThirdCall(): sinon.SinonStub;
}

Usage Examples:

import { sinon, expect } from "@loopback/testlab";

// Basic stubbing
const stub = sinon.stub();
stub.returns("default");
stub.withArgs("special").returns("special case");

expect(stub()).to.equal("default");
expect(stub("special")).to.equal("special case");

// Promise stubbing
const asyncStub = sinon.stub();
asyncStub.resolves("success");
asyncStub.withArgs("error").rejects(new Error("failed"));

const result = await asyncStub();
expect(result).to.equal("success");

// Object method stubbing
const obj = { method: () => "original" };
const methodStub = sinon.stub(obj, "method");
methodStub.returns("stubbed");

expect(obj.method()).to.equal("stubbed");
methodStub.restore();

Mock Capabilities

Mock objects with expectations and verification.

// Mock creation (from Sinon)
sinon.mock(obj: any): sinon.SinonMock;

// Mock interface
interface SinonMock {
  expects(method: string): sinon.SinonExpectation;
  restore(): void;
  verify(): void;
}

// Expectation interface
interface SinonExpectation {
  atLeast(n: number): sinon.SinonExpectation;
  atMost(n: number): sinon.SinonExpectation;
  never(): sinon.SinonExpectation;
  once(): sinon.SinonExpectation;
  twice(): sinon.SinonExpectation;
  thrice(): sinon.SinonExpectation;
  exactly(n: number): sinon.SinonExpectation;
  withArgs(...args: any[]): sinon.SinonExpectation;
  withExactArgs(...args: any[]): sinon.SinonExpectation;
  returns(value: any): sinon.SinonExpectation;
  throws(error?: Error | string): sinon.SinonExpectation;
}

Usage Examples:

import { sinon } from "@loopback/testlab";

const logger = { log: (msg: string) => console.log(msg) };

// Create mock with expectations
const mock = sinon.mock(logger);
mock.expects("log").once().withArgs("Hello World");

// Use the mocked object
logger.log("Hello World");

// Verify expectations
mock.verify(); // Throws if expectations not met
mock.restore();

Fake Timers

Control time and async behavior in tests.

// Timer methods (from Sinon)
sinon.useFakeTimers(): sinon.SinonFakeTimers;
sinon.useFakeTimers(config: Partial<sinon.SinonFakeTimersConfig>): sinon.SinonFakeTimers;

interface SinonFakeTimers {
  tick(ms: number): void;
  next(): void;
  runAll(): void;
  restore(): void;
  reset(): void;
}

Usage Examples:

import { sinon, expect } from "@loopback/testlab";

// Test with fake timers
const clock = sinon.useFakeTimers();
let called = false;

setTimeout(() => { called = true; }, 1000);

expect(called).to.be.false();
clock.tick(1000);
expect(called).to.be.true();

clock.restore();

docs

assertions.md

http-client.md

http-utilities.md

index.md

request-response-mocking.md

test-doubles.md

test-sandbox.md

validation-helpers.md

tile.json