An Angular testing library for creating mock services, components, directives, pipes and modules in unit tests.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Runtime mock instance customization with MockInstance for modifying behavior during test execution. Supports method stubbing, property overrides, and lifecycle management for fine-grained control over mock behavior.
Customizes mock instances at runtime with support for methods, properties, getters, and setters.
/**
* Customizes a getter property on a mock class
* @param instance - Mock class to customize
* @param name - Property name to customize
* @param stub - Getter function implementation
* @param encapsulation - Must be 'get' for getter
* @returns The stub function
*/
function MockInstance<T extends object, K extends keyof T, S extends () => T[K]>(
instance: AnyType<T>,
name: K,
stub: S,
encapsulation: 'get'
): S;
/**
* Customizes a setter property on a mock class
* @param instance - Mock class to customize
* @param name - Property name to customize
* @param stub - Setter function implementation
* @param encapsulation - Must be 'set' for setter
* @returns The stub function
*/
function MockInstance<T extends object, K extends keyof T, S extends (value: T[K]) => void>(
instance: AnyType<T>,
name: K,
stub: S,
encapsulation: 'set'
): S;
/**
* Customizes a method or property on a mock class
* @param instance - Mock class to customize
* @param name - Method/property name to customize
* @param stub - Implementation function or value
* @returns The stub function or value
*/
function MockInstance<T extends object, K extends keyof T, S extends T[K]>(
instance: AnyType<T>,
name: K,
stub: S
): S;
/**
* Applies multiple customizations to a mock class
* @param instance - Mock class to customize
* @param overrides - Object with property overrides
* @returns The overrides object
*/
function MockInstance<T extends object>(
instance: AnyType<T>,
overrides: Partial<T>
): typeof overrides;
/**
* Sets up automatic initialization for mock instances
* @param instance - Mock class to customize
* @param init - Initialization function called when instance is created
* @returns The initialization function
*/
function MockInstance<T extends object>(
instance: AnyType<T>,
init?: (instance: T, injector: Injector) => Partial<T>
): typeof init;Usage Examples:
import { MockInstance } from "ng-mocks";
// Customize a method
MockInstance(AuthService, 'login', jasmine.createSpy('login')
.and.returnValue(of({ success: true })));
// Customize a property getter
MockInstance(ConfigService, 'apiUrl', () => 'http://test-api.com', 'get');
// Customize a property setter
MockInstance(UserService, 'currentUser', (user) => {
console.log('Setting user:', user);
}, 'set');
// Apply multiple customizations
MockInstance(DataService, {
getData: jasmine.createSpy('getData').and.returnValue(of([])),
isLoading: false,
errorMessage: null
});
// Automatic initialization
MockInstance(AuthService, (instance, injector) => ({
isAuthenticated: true,
user: { id: 1, name: 'Test User' },
login: jasmine.createSpy('login').and.returnValue(of({ success: true }))
}));Resets MockInstance customizations for specified classes.
/**
* Resets MockInstance customizations for one or more classes
* @param instances - Classes to reset MockInstance customizations for
*/
function MockReset(...instances: Array<AnyType<any>>): void;Usage Examples:
import { MockInstance, MockReset } from "ng-mocks";
// Set up customizations
MockInstance(AuthService, 'isAuthenticated', true);
MockInstance(DataService, 'getData', () => of(mockData));
// Reset specific services
MockReset(AuthService, DataService);
// In test cleanup
afterEach(() => {
MockReset(AuthService, DataService, ConfigService);
});Common patterns for using MockInstance effectively in tests.
Service Method Stubbing:
import { MockInstance, MockReset } from "ng-mocks";
describe('UserComponent', () => {
beforeEach(() => {
// Customize service behavior for all tests
MockInstance(UserService, 'getUsers', jasmine.createSpy('getUsers')
.and.returnValue(of([
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' }
])));
MockInstance(AuthService, 'isAuthenticated', true);
});
afterEach(() => {
// Clean up customizations
MockReset(UserService, AuthService);
});
it('should load users on init', () => {
const fixture = MockRender(UserComponent);
const userService = ngMocks.get(UserService);
expect(userService.getUsers).toHaveBeenCalled();
});
});Property Access Control:
// Control property access
MockInstance(ConfigService, 'environment', () => 'test', 'get');
MockInstance(ConfigService, 'debug', (value) => {
console.log('Debug mode set to:', value);
}, 'set');
// Use in test
const config = ngMocks.get(ConfigService);
expect(config.environment).toBe('test');
config.debug = true; // Logs: "Debug mode set to: true"Dynamic Behavior Based on Test Context:
describe('Component with different service states', () => {
beforeEach(() => {
MockInstance(DataService, (instance) => {
// Different behavior based on test context
if (jasmine.currentSpec.description.includes('loading')) {
return { isLoading: true, data: null };
} else if (jasmine.currentSpec.description.includes('error')) {
return {
isLoading: false,
data: null,
error: 'Network error'
};
} else {
return {
isLoading: false,
data: [{ id: 1, name: 'Test' }],
error: null
};
}
});
});
it('should show loading state', () => {
const fixture = MockRender(MyComponent);
const service = ngMocks.get(DataService);
expect(service.isLoading).toBe(true);
});
it('should show error state', () => {
const fixture = MockRender(MyComponent);
const service = ngMocks.get(DataService);
expect(service.error).toBe('Network error');
});
});Chained Method Calls:
// Mock fluent interface
MockInstance(QueryBuilder, 'where', function(this: any, condition: string) {
this.conditions = this.conditions || [];
this.conditions.push(condition);
return this;
});
MockInstance(QueryBuilder, 'orderBy', function(this: any, field: string) {
this.orderField = field;
return this;
});
MockInstance(QueryBuilder, 'execute', function(this: any) {
return of({
conditions: this.conditions,
orderField: this.orderField
});
});
// Use in test
const queryBuilder = ngMocks.get(QueryBuilder);
const result = queryBuilder
.where('active = true')
.where('role = "admin"')
.orderBy('name')
.execute();Lifecycle Management:
describe('Component lifecycle', () => {
let serviceSpies: { [key: string]: jasmine.Spy };
beforeEach(() => {
serviceSpies = {
init: jasmine.createSpy('init'),
destroy: jasmine.createSpy('destroy'),
load: jasmine.createSpy('load').and.returnValue(of({}))
};
MockInstance(LifecycleService, serviceSpies);
});
afterEach(() => {
MockReset(LifecycleService);
});
it('should call init on component creation', () => {
const fixture = MockRender(MyComponent);
expect(serviceSpies.init).toHaveBeenCalled();
});
it('should call destroy on component destruction', () => {
const fixture = MockRender(MyComponent);
fixture.destroy();
expect(serviceSpies.destroy).toHaveBeenCalled();
});
});Integration with MockBuilder:
// Combine MockInstance with MockBuilder
describe('Integration test', () => {
beforeEach(() => {
// Set up MockInstance customizations
MockInstance(AuthService, 'user', { id: 1, role: 'admin' });
MockInstance(ConfigService, 'features', ['feature1', 'feature2']);
// Configure test environment
return MockBuilder(MyComponent, MyModule)
.keep(AuthService) // Keep real AuthService, but with MockInstance customizations
.mock(HttpClient)
.build();
});
afterEach(() => {
MockReset(AuthService, ConfigService);
});
it('should work with customized services', () => {
const fixture = MockRender(MyComponent);
const auth = ngMocks.get(AuthService);
expect(auth.user.role).toBe('admin');
});
});Conditional Stubbing:
MockInstance(ApiService, 'request', (url: string) => {
if (url.includes('/users')) {
return of({ users: [{ id: 1, name: 'Test' }] });
} else if (url.includes('/error')) {
return throwError({ status: 500, message: 'Server Error' });
} else {
return of({ data: 'default' });
}
});State-Dependent Behavior:
let serviceState = { authenticated: false, user: null };
MockInstance(AuthService, 'isAuthenticated', () => serviceState.authenticated, 'get');
MockInstance(AuthService, 'user', () => serviceState.user, 'get');
MockInstance(AuthService, 'login', (credentials: any) => {
serviceState.authenticated = true;
serviceState.user = { id: 1, name: 'Test User' };
return of({ success: true });
});
MockInstance(AuthService, 'logout', () => {
serviceState.authenticated = false;
serviceState.user = null;
return of({ success: true });
});Spy Integration:
// Create comprehensive spy setup
const createServiceSpy = (methodName: string) => {
return jasmine.createSpy(methodName).and.callThrough();
};
MockInstance(DataService, {
load: createServiceSpy('load').and.returnValue(of([])),
save: createServiceSpy('save').and.returnValue(of({ success: true })),
delete: createServiceSpy('delete').and.returnValue(of({ success: true }))
});