UNPKG

@suites/unit

Version:
391 lines (390 loc) 18.4 kB
import type { IdentifierMetadata } from '@suites/types.di'; import type { DeepPartial, Type } from '@suites/types.common'; import type { ArgsType, Stub, StubbedInstance } from '@suites/types.doubles'; import type { SociableTestBedBuilder as SociableTestBedBuilderCore, TestBedBuilder as TestBedBuilderCore, UnitReference as UnitReferenceCore, MockOverride as MockOverrideCore } from '@suites/core.unit'; /** * Represents a test double instance where all methods and properties are stubbed. * * This abstract type provides the foundation for creating test doubles in unit tests. * When a testing adapter is installed, this type is automatically augmented with * framework-specific capabilities through TypeScript module augmentation. * * @template T The type of the object being transformed into a test double * * @remarks * This is a base abstraction that adapters enhance with concrete implementations. * The actual runtime behavior depends on which testing adapter is installed. * * @since 3.0.0 * @see {@link https://suites.dev/docs/api-reference/types | Type Reference} */ export type Mocked<T> = StubbedInstance<T>; export interface SociableTestBedBuilder<TClass> extends SociableTestBedBuilderCore<TClass> { /** * Exposes a dependency to be included in the test environment in its real or partially mocked state. * This method is used to selectively expose dependencies that should not be fully mocked. * It allows for sociable testing, where the class under test interacts with real implementations * or partial mocks of certain dependencies. * * @since 3.0.0 * @template TClass The type of the class under test. * @param dependency - The dependency to be exposed in its real or partially mocked state. * @returns A TestBedBuilder instance for further configuration. * @example * ```ts * import { TestBed } from '@suites/unit'; * import { MyService, AnotherService } from './my-service.js'; * * const { unit, unitRef } = await TestBed.sociable(MyService).expose(AnotherService).compile(); * // MyService is now tested with AnotherService exposed and not fully mocked. * ``` * @see {@link https://suites.dev/docs/api-reference/testbed-sociable | TestBed.sociable() API Reference} */ expose(dependency: Type): SociableTestBedBuilder<TClass>; } export interface SolitaryTestBedBuilder<TClass> extends TestBedBuilder<TClass> { } /** * Provides access to mocked dependencies in the test environment. * * The `unitRef` allows you to retrieve mocked instances of dependencies * to configure their behavior or verify interactions. This is essential for * controlling how mocked dependencies respond during tests. * * The return type of `.get()` is augmented by adapter packages to provide * framework-specific mock types. Configure augmentation by referencing the * adapter's unit.d.ts in your global.d.ts. * * @since 3.0.0 * @see {@link https://suites.dev/docs/api-reference/unit-reference | UnitReference API Reference} * * @example * ```ts * import { TestBed } from '@suites/unit'; * * const { unit, unitRef } = await TestBed.solitary(MyService).compile(); * * // Get a mocked dependency * const mockLogger = unitRef.get(Logger); * mockLogger.log.mockReturnValue('test'); * * // Verify interactions * unit.doSomething(); * expect(mockLogger.log).toHaveBeenCalled(); * ``` */ export interface UnitReference extends UnitReferenceCore { /** * Retrieves a reference to the mocked object of a dependency corresponding to its type identifier. * * @since 3.0.0 * @template TDependency The type of the dependency being retrieved. * @param type - The type representing the dependency. * @throws {@link DependencyResolutionError} If the dependency is not found. * @returns The mocked object corresponding to the provided type identifier. */ get<TDependency>(type: Type<TDependency>): StubbedInstance<TDependency>; /** * Retrieves a reference to the mocked object of a dependency corresponding to its type identifier * and metadata object. * * @since 3.0.0 * @template TDependency The type of the dependency being retrieved. * @param type - The type representing the dependency. * @param identifierMetadata - A metadata object that corresponds to the type identifier. * @throws {@link DependencyResolutionError} If the dependency is not found. * @returns The mocked object corresponding to the provided * symbol-based token. */ get<TDependency>(type: Type<TDependency>, identifierMetadata: IdentifierMetadata): StubbedInstance<TDependency>; /** * Retrieves a reference to the mocked object of a dependency corresponding to a string-based token. * * @since 3.0.0 * @template TDependency The type of the dependency being retrieved. * @param token - The string-based token representing the dependency. * @throws {@link DependencyResolutionError} If the dependency is not found. * @returns The mocked object corresponding to the provided string-based token. */ get<TDependency>(token: string): StubbedInstance<TDependency>; /** * Retrieves a reference to the mocked object of a dependency corresponding to a string-based * token and an identifier metadata object. * * @since 3.0.0 * @template TDependency The type of the dependency being retrieved. * @param token - The symbol-based token representing the dependency. * @param identifierMetadata - An accompanying metadata object for the token identifier. * @throws {@link DependencyResolutionError} If the dependency is not found. * @returns The mocked object corresponding to the provided * symbol-based token. */ get<TDependency>(token: string, identifierMetadata: IdentifierMetadata): StubbedInstance<TDependency>; /** * Retrieves a reference to the mocked object of a dependency corresponding to a symbol-based token. * * @since 3.0.0 * @template TDependency The type of the dependency being retrieved. * @param token - The symbol-based token representing the dependency. * @throws {@link DependencyResolutionError} If the dependency is not found. * @returns The mocked object corresponding to the provided symbol-based token. */ get<TDependency>(token: symbol): StubbedInstance<TDependency>; /** * Retrieves a reference to the mocked object of a dependency corresponding to a symbol-based * token and an identifier metadata object. * * @since 3.0.0 * @template TDependency The type of the dependency being retrieved. * @param token - The symbol-based token representing the dependency. * @param identifierMetadata - An accompanying metadata object for the token identifier. * @throws {@link DependencyResolutionError} If the dependency is not found. * @returns The mocked object corresponding to the provided symbol-based token. */ get<TDependency>(token: symbol, identifierMetadata: IdentifierMetadata): StubbedInstance<TDependency>; /** * Retrieves a mocked dependency by its type, string, or symbol token with optional metadata. * * This method provides flexibility in retrieving dependencies by allowing various identifier types. * * @since 3.0.0 * @template TDependency The type of the dependency being retrieved. * @param identifier - The token representing the dependency. It can be of type `Type<TDependency>`, `string`, or `symbol`. * @param identifierMetadata - A corresponding metadata object for the token identifier. * @throws {@link DependencyResolutionError} If the dependency is not found. * @returns The mocked instance corresponding to the provided identifier and metadata. */ get<TDependency>(identifier: Type<TDependency> | string | symbol, identifierMetadata?: IdentifierMetadata): StubbedInstance<TDependency>; /** * Retrieves a mocked dependency by its type, string, or symbol token. * * This method provides flexibility in retrieving dependencies by allowing various identifier types. * * @since 3.0.0 * @template TDependency The type of the dependency being retrieved. * @param identifier - The token representing the dependency. It can be of type `Type<TDependency>`, `string`, or `symbol`. * @throws {@link DependencyResolutionError} If the dependency is not found. * @returns The mocked instance corresponding to the provided identifier. */ get<TDependency>(identifier: Type<TDependency> | string | symbol): StubbedInstance<TDependency>; } /** * A factory interface for creating UnitTestBed instances for testing classes. * * @see {@link https://suites.dev/docs/api-reference/testbed-solitary | TestBed Solitary} * @see {@link https://suites.dev/docs/api-reference/testbed-sociable | TestBed Sociable} * @since 3.0.0 * @example * ```ts * import { TestBed } from '@suites/unit'; * import { MyService } from './my-service.js'; * * const { unit, unitRef } = await TestBed.solitary(MyService).compile(); * ``` */ export interface TestBed { /** * Creates a new TestBedBuilder instance for the given target class. This builder helps in configuring * and compiling the test environment for a class that should be tested in isolation (solitary). * It sets up the necessary dependencies and mocks, ensuring that the class under test is the primary * focus without interference from other components. * * @see {@link https://suites.dev/docs/api-reference/testbed-solitary | TestBed.solitary() API Reference} * @since 3.0.0 * @template TClass - The class to be tested. * @param targetClass - The class to be tested. * @returns The TestBedBuilder instance configured for solitary testing. * @example * ```ts * import { TestBed } from '@suites/unit'; * import { MyService } from './my-service.js'; * * // MyService is now tested in isolation with all its dependencies mocked. * const { unit, unitRef } = await TestBed.solitary(MyService).compile(); * ``` */ solitary<TClass>(targetClass: Type<TClass>): SolitaryTestBedBuilder<TClass>; /** * Creates a TestBedBuilder instance for the given target class for sociable testing. * Sociable testing allows for the inclusion of real implementations or partial mocks of certain dependencies. * This method returns a subset of the SociableTestBedBuilder's methods, focusing on exposing * specific dependencies that should be included in their real or partially mocked state. * * @see {@link https://suites.dev/docs/api-reference/testbed-sociable | TestBed.sociable() API Reference} * @template TClass - The type of the target class. * @param targetClass - The target class to be tested. * @returns A subset of the SociableTestBedBuilder's methods * containing only the 'expose' method. * @since 3.0.0 * @example * ```ts * import { TestBed } from '@suites/unit'; * import { MyService } from './my-service.js'; * import { AnotherService } from './another-service.js'; * * const { unit, unitRef } = await TestBed.sociable(MyService).expose(AnotherService).compile(); * // MyService is now tested with AnotherService exposed and not fully mocked. * ``` */ sociable<TClass>(targetClass: Type<TClass>): SociableTestBedBuilder<TClass>; } /** * Represents the outcome when a `TestBedBuilder` is compiled. * * @template TClass The class type being tested. * @since 3.0.0 * @see {@link https://suites.dev/docs/api-reference | API Reference} */ export interface UnitTestBed<TClass> { /** * The instance of the class under test. * * @template TClass The class being tested. * @property TClass unit */ unit: TClass; /** * A reference to the dependencies associated with the class under test. * * @property unitRef - A reference to the mocked dependencies of the class */ unitRef: UnitReference; } /** * Interface to define overrides for mocking dependencies in a test environment. * * @see {@link https://suites.dev/docs/api-reference/mock-configuration | Mock Configuration} * @template TDependency The type of the dependency to be mocked. * @template TClass The type of the class under test. */ export interface MockOverride<TDependency, TClass> extends MockOverrideCore<TDependency, TClass> { /** * Provides a mock implementation using stub functions for methods. * * Use this when you need fine-grained control over method behavior with stub functions. * The stub function is automatically provided for creating mocked methods. * * @see {@link https://suites.dev/docs/api-reference/mock-configuration | Mock Configuration} * @since 3.0.0 * @param mockImplementation - Function that receives a stub creator and returns the mock * @returns A TestBedBuilder instance for chaining * * @example * ```ts * await TestBed.solitary(MyService) * .mock(Logger) * .impl((stub) => ({ log: stub().mockReturnValue(undefined) })) * .compile(); * ``` */ impl(mockImplementation: (stubFn: Stub<any, ArgsType<TDependency>>) => DeepPartial<TDependency>): TestBedBuilder<TClass>; /** * Provides a final implementation with concrete values or functions. * * Use this when you want to directly provide the mock implementation without stubs, * useful for simple mocks or when providing constant values. * * @see {@link https://suites.dev/docs/api-reference/mock-configuration | Mock Configuration} * @since 3.0.0 * @param finalImplementation - The mock implementation object * @returns A TestBedBuilder instance for chaining * * @example * ```ts * await TestBed.solitary(MyService) * .mock('CONFIG') * .final({ apiUrl: 'http://test.api', timeout: 5000 }) * .compile(); * ``` */ final(finalImplementation: DeepPartial<TDependency>): TestBedBuilder<TClass>; } /** * Provides methods to configure and finalize the `TestBed`. * * @template TClass The class type being tested. * @since 3.0.0 * @see {@link https://suites.dev/docs/api-reference/mock-configuration | Mock Configuration} */ export interface TestBedBuilder<TClass> extends TestBedBuilderCore<TClass> { /** * Declares a dependency to be mocked using its type. * * @since 3.0.0 * @param type - The type of the dependency. * @template TDependency The type of the dependency being mocked. * @returns An instance of MockOverride for further configuration. */ mock<TDependency>(type: Type<TDependency>): MockOverride<TDependency, TClass>; /** * Declares a dependency to be mocked using its type along with a corresponding metadata object. * * @since 3.0.0 * @param type - The type of the dependency. * @param identifierMetadata - the identifier metadata. * @template TDependency The type of the dependency being mocked. * @returns An instance of MockOverride for further configuration. */ mock<TDependency>(type: Type<TDependency>, identifierMetadata: IdentifierMetadata): MockOverride<TDependency, TClass>; /** * Declares a dependency to be mocked using a string-based token. * * @since 3.0.0 * @param token - The token string representing the dependency to be mocked. * @template TDependency The type of the dependency being mocked. * @returns An instance of MockOverride for further configuration. */ mock<TDependency>(token: string): MockOverride<TDependency, TClass>; /** * Declares a dependency to be mocked using a string-based token along with a corresponding * metadata object. * * @since 3.0.0 * @param token - The token string representing the dependency to be mocked. * @param identifierMetadata - the identifier metadata. * @template TDependency The type of the dependency being mocked. * @returns An instance of MockOverride for further configuration. */ mock<TDependency>(token: string, identifierMetadata: IdentifierMetadata): MockOverride<TDependency, TClass>; /** * Declares a dependency to be mocked using a symbol-based token. * * @since 3.0.0 * @param token - The token symbol representing the dependency to be mocked. * @template TDependency The type of the dependency being mocked. * @returns An instance of MockOverride for further configuration. */ mock<TDependency>(token: symbol): MockOverride<TDependency, TClass>; /** * Declares a dependency to be mocked using a symbol-based token along with a corresponding * metadata object. * * @since 3.0.0 * @param token - The token symbol representing the dependency to be mocked. * @param identifierMetadata - the identifier metadata if exists. * @template TDependency The type of the dependency being mocked. * @returns An instance of MockOverride for further configuration. */ mock<TDependency>(token: symbol, identifierMetadata: IdentifierMetadata): MockOverride<TDependency, TClass>; /** * Declares a dependency to be mocked using a flexible identifier. * * @since 3.0.0 * @param identifier - The identifier representing the dependency. It can be of type * `Type<TDependency>`, `string`, or `symbol`. * @param identifierMetadata - the identifier metadata if exists. * @template TDependency The type of the dependency being mocked. * @returns An instance of MockOverride for further configuration. */ mock<TDependency>(identifier: Type<TDependency> | string | symbol, identifierMetadata?: IdentifierMetadata): MockOverride<TDependency, TClass>; /** * Finalizes the test environment configuration and builds the test instance. * * This method completes the builder chain and returns the configured test environment * with the unit under test and references to all mocked dependencies. * * @since 3.0.0 * @returns A Promise resolving to UnitTestBed with unit and unitRef */ compile(): Promise<UnitTestBed<TClass>>; }