This guide defines the JSDoc documentation standards for the Suites project. Following these conventions ensures consistency across the codebase and provides excellent developer experience.
- Core Principles
- JSDoc Tag Order
- Templates by Code Element
- Content Guidelines
- Examples from Suites
- Common Patterns
Document the purpose, benefits, and use cases. Code already shows "what" it does.
Good:
/**
* Initializes a solitary test environment builder for a specified class. In a solitary environment,
* all dependencies are mocked by default, ensuring that tests are isolated to the class under test only.
* This method is ideal for testing the internal logic of the class without external interactions.
*/Avoid:
/**
* Creates a solitary test bed builder.
*/Every public API should have at least one runnable example with imports.
Use @see tags to link to relevant documentation pages on suites.dev.
Always include @since tags to track when features were introduced.
Document generic type parameters with clear explanations of what they represent.
Use this consistent order for all JSDoc blocks:
@description(or start with description text directly)@since@template(for generic type parameters)@param(for function/method parameters)@returns(for return values)@throws(for exceptions that might be thrown)@example(code examples)@see(links to documentation)- Other tags as needed (
@internal,@deprecated,@property, etc.)
/**
* @description
* [Brief description of what the class does and its purpose]
* [Additional context about when/why to use this class]
*
* @class [ClassName]
* @see [link to docs]
* @since [version]
*/
export class ClassName {
// ...
}Example from Suites:
/**
* @description
* Provides a testing framework for unit testing classes in both isolated (solitary) and integrated (sociable)
* environments. This class facilitates building configurable test environments tailored to specific unit tests.
*
* @class TestBed
* @see https://suites.dev/docs/api-reference
* @since 3.0.0
*/
export class TestBed {
// ...
}/**
* [Brief description explaining the interface purpose]
* [Additional context about when this interface is used]
*
* @template [T] [Description of generic parameter if applicable]
* @see [link to docs]
* @since [version]
*
* @example
* import { Interface } from '@suites/package';
*
* const example: Interface<Type> = {
* // usage example
* };
*/
export interface InterfaceName<T> {
// properties...
}Example from Suites:
/**
* Represents the testing environment for a specific class, encapsulating both the instance
* of the class under test and references to its dependencies. This setup is crucial for
* conducting isolated and controlled unit tests.
*
* @template TClass The type of the class being tested. This generic parameter ensures type safety
* and consistency across the testing code.
*/
export interface UnitTestBed<TClass> {
unit: TClass;
unitRef: UnitReference;
}/**
* @description
* [Detailed description of what the method does]
* [Explain the use case and when to use this method]
* [Include any important details about behavior]
*
* @since [version]
* @template [T] [Description of generic parameter]
* @param paramName - [Description of parameter and its purpose]
* @returns [Description of what is returned]
* @throws {@link ErrorType} [Description of when this error is thrown]
*
* @example
* import { Class } from '@suites/package';
* import { Dependency } from './dependency';
*
* // Example usage with context
* const result = await instance.method(param);
*
* @see [link to docs]
*/
public method<T>(param: Type): ReturnType {
// ...
}Example from Suites:
/**
* @description
* Initializes a solitary test environment builder for a specified class. In a solitary environment,
* all dependencies are mocked by default, ensuring that tests are isolated to the class under test only.
* This method is ideal for testing the internal logic of the class without external interactions.
*
* @since 3.0.0
* @template TClass The type of the class to be tested.
* @param targetClass - The class for which the test environment is constructed.
* @returns A builder to configure the solitary test environment.
* @see https://suites.dev/docs/developer-guide/unit-tests
*
* @example
* import { TestBed } from '@suites/unit';
* import { MyService } from './my-service';
*
* const { unit, unitRef } = await TestBed.solitary(MyService).compile();
*/
public static solitary<TClass = any>(targetClass: Type<TClass>): SolitaryTestBedBuilder<TClass> {
// ...
}/**
* [Description of what this type represents]
* [Explain when and how this type should be used]
* [Document any constraints or special behaviors]
*
* @template [T] [Description of generic parameter]
* @since [version]
*
* @example
* import { TypeAlias } from '@suites/package';
*
* const example: TypeAlias<SomeType> = /* ... */;
*/
export type TypeAlias<T> = /* ... */;Good Example:
/**
* Base abstract type for mocked instances. Adapters can augment this with
* library-specific implementations (Jest, Vitest, Sinon) via module augmentation.
*
* @template T The type being mocked
* @since 4.0.0
*/
export type Mocked<T> = StubbedInstance<T>;Needs Improvement:
/**
* @since 3.0.0
*/
export type InjectableIdentifier<TClass = unknown> = Type<TClass> | string | symbol;Should Be:
/**
* Represents an identifier that can be used to inject dependencies in a DI container.
* Can be a class type, a string token, or a symbol token.
*
* @template TClass The type of the class when using class-based injection
* @since 3.0.0
*
* @example
* // Using class type
* const identifier: InjectableIdentifier = MyService;
*
* @example
* // Using string token
* const identifier: InjectableIdentifier = 'API_KEY';
*
* @example
* // Using symbol token
* const TOKEN = Symbol('config');
* const identifier: InjectableIdentifier = TOKEN;
*/
export type InjectableIdentifier<TClass = unknown> = Type<TClass> | string | symbol;interface Example {
/**
* [Description of the property and its purpose]
* [Additional context if needed]
*
* @since [version]
* @template [T] [Description if property is generic]
* @property [propertyName] [Type and description]
*/
propertyName: Type;
}Example from Suites:
interface UnitTestBed<TClass> {
/**
* The instance of the class being tested. This property provides direct access to the class,
* allowing tests to interact with it as needed.
* @since 3.0.0
* @see https://suites.dev/docs/api-reference
* @template TClass The type of the class under test.
* @property {TClass} unit The instance of the class under test.
*/
unit: TClass;
}Error classes need special attention with comprehensive documentation:
/**
* Thrown when [specific condition that triggers this error].
*
* This typically occurs when [common scenario that causes this error].
* [Additional context about what this error means]
*
* @since [version]
* @see [link to error documentation page]
*
* @example
* // Scenario that causes the error
* const result = unitRef.get(NonExistentDependency);
* // throws IdentifierNotFoundError
*
* @example
* // How to prevent/fix the error
* await TestBed.solitary(MyService)
* .mock(SomeDependency)
* .impl(() => ({ method: jest.fn() }))
* .compile();
*/
export class CustomError extends Error {
// ...
}Template Structure:
- When it's thrown - Clear condition
- Common scenarios - Real-world cases
- How to prevent - Show the fix
- Recovery strategies - What to do when it occurs
/**
* [Description of what this constant represents]
* [Explain its purpose in the framework]
*
* @since [version]
* @alias [if aliasing another library's export]
* @see [link to external docs if applicable]
* @see [link to internal docs]
*
* @example
* import { constant } from '@suites/package';
*
* const result = constant();
*/
export const constant = /* ... */;Needs Improvement:
/**
* Represents a stub function
*
* @since 3.0.0
* functions replaced by stubs.
* @alias jest.fn
* @see https://jestjs.io/docs/mock-function-api#jestfnimplementation
* @see https://suites.dev/docs/api-reference
*/
export const stub = jest.fn();Should Be:
/**
* Creates a stub function for mocking method implementations in tests.
* This is an alias for Jest's `jest.fn()`, providing a consistent API across
* different testing frameworks in the Suites ecosystem.
*
* @since 3.0.0
* @alias jest.fn
* @see https://jestjs.io/docs/mock-function-api#jestfnimplementation
* @see https://suites.dev/docs/api-reference
*
* @example
* import { stub } from '@suites/doubles.jest';
*
* const mockFn = stub();
* mockFn.mockReturnValue('mocked value');
*/
export const stub = jest.fn();- Explain the purpose and benefits
- Provide context about when to use
- Mention important behaviors or side effects
- Use clear, concise language
- Write in complete sentences
- Use active voice
- Simply restate the function name
- Use vague descriptions like "handles X"
- Omit important details
- Use overly technical jargon without explanation
- Import statements - Show where the code comes from
- Setup - Any necessary preparation
- Usage - The actual example
- Comments - Explain non-obvious parts
/**
* @example
* import { TestBed } from '@suites/unit';
* import { MyService, DependencyOne, Logger } from './my-service';
*
* const { unit, unitRef } = await TestBed.sociable(MyService)
* .expose(DependencyOne)
* .mock(Logger)
* .impl(stub => ({ log: stub().mockReturnValue('overridden') }))
* .compile();
*//**
* @example
* TestBed.sociable(MyService).compile();
*/- Relevant documentation pages on suites.dev
- Related API methods or interfaces
- External library documentation when aliasing
- Conceptual guides that provide context
@see https://suites.dev/docs/api-reference/api/testbed-api
@see https://suites.dev/docs/developer-guide/unit-testsAlways explain what the generic parameter represents:
Good:
/**
* @template TClass The type of the class to be tested.
* @template TDependency The type of the dependency being retrieved.
*/More Detail When Needed:
/**
* @template TClass The type of the class being tested. This generic parameter ensures type safety
* and consistency across the testing code.
*/For overloaded methods, document each signature:
export interface UnitReference {
/**
* 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 IdentifierNotFoundError} 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 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 IdentifierNotFoundError} If the dependency is not found.
* @returns The mocked object corresponding to the provided string-based token.
*/
get<TDependency>(token: string): StubbedInstance<TDependency>;
}/**
* @description
* Initializes a solitary test environment builder for a specified class. In a solitary environment,
* all dependencies are mocked by default, ensuring that tests are isolated to the class under test only.
* This method is ideal for testing the internal logic of the class without external interactions.
*
* @since 3.0.0
* @template TClass The type of the class to be tested.
* @param targetClass - The class for which the test environment is constructed.
* @returns A builder to configure the solitary test environment.
* @see https://suites.dev/docs/developer-guide/unit-tests
*
* @example
* import { TestBed } from '@suites/unit';
* import { MyService } from './my-service';
*
* const { unit, unitRef } = await TestBed.solitary(MyService).compile();
*/
public static solitary<TClass = any>(targetClass: Type<TClass>): SolitaryTestBedBuilder<TClass>Why this is excellent:
- ✅ Explains the "why" - purpose and benefits
- ✅ Provides context about use case
- ✅ Clear parameter documentation
- ✅ Complete example with imports
- ✅ Links to relevant documentation
- ✅ Version tag present
/**
* Provides methods to define overrides for mocking dependencies within the testing environment.
* This interface allows setting up specific behaviors or responses from the mocked dependencies,
* facilitating precise and controlled testing scenarios.
*
* @template TDependency The type of the dependency being mocked. This generic ensures that
* the mocks are appropriately typed, enhancing the development experience with type safety.
* @template TClass The type of the class under test. This provides context to the TestBedBuilder,
* linking the mock setups directly with the class being tested.
*/
export interface MockOverride<TDependency, TClass>Why this is good:
- ✅ Explains purpose clearly
- ✅ Describes benefits
- ✅ Detailed generic parameter documentation
- ✅ Explains how generics relate to usage
/**
* Defines a custom implementation for a mocked dependency. This method is used to set up
* how the mock should behave when interacted with during tests.
*
* @since 3.0.0
* @param mockImplementation - A function that receives a stub function and returns a partial
* implementation of the dependency. This setup allows testers to specify detailed behavior,
* including how methods should respond when invoked.
* @returns A TestBedBuilder instance, facilitating a fluent interface that allows further
* configuration of the testing environment.
*/
impl(
mockImplementation: (stubFn: Stub<any, ArgsType<TDependency>>) => DeepPartial<TDependency>
): TestBedBuilder<TClass>;Why this is good:
- ✅ Explains what the method does
- ✅ Provides detailed parameter explanation
- ✅ Explains return value purpose (fluent interface)
- ✅ Contextualizes usage
/**
* [What this builder method configures]
* [Why you would use this configuration]
*
* @since [version]
* @param paramName - [What this parameter controls]
* @returns [Next step in builder chain] [What you can do next]
*
* @example
* [Show typical usage in builder chain]
*//**
* Creates [what is created] for [purpose].
* [Additional context about when to use]
*
* @since [version]
* @template [T] [Generic parameter explanation]
* @param params - [Parameter descriptions]
* @returns [What is returned and its state]
*
* @example
* [Show complete usage]
*//**
* Adapter for [library name] to be used with Suites framework.
* [Explain what this adapter enables]
*
* @see [link to Suites docs]
* @see [link to adapted library docs]
* @since [version]
*
* @example
* import { adapter } from '@suites/doubles.[library]';
*
* [Show usage]
*/- Conversational but professional - Match the style of suites.dev/docs
- Developer-friendly - Avoid unnecessary jargon
- Benefit-focused - Explain why, not just what
- Clear and concise - Respect developer's time
- One-line descriptions - For simple utilities and constants
- 2-3 sentences - For most methods and properties
- 1-2 paragraphs - For classes, interfaces, and complex methods
- Multiple paragraphs - For core API entry points and complex patterns
- Use
@descriptiontag for multi-paragraph descriptions - Start with description text directly for single-paragraph docs
- Use proper markdown in examples when needed
- Keep line length reasonable (80-120 characters)
- Use blank lines to separate logical sections
Before committing documentation, verify:
- Description explains "why" and benefits
-
@sinceversion tag is present - Generic type parameters are documented with
@template - Parameters are documented with
@param - Return values are documented with
@returns - Exceptions are documented with
@throws - At least one practical example with imports
- Links to relevant docs with
@see - Examples are runnable and realistic
- Tone matches suites.dev documentation style
- No typos or grammatical errors
- 4.0.0 - Initial JSDoc style guide created based on existing patterns