or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-testing.mdindex.mdmock-integration.mdmodule-building.mdmodule-overriding.mdprovider-overriding.md

provider-overriding.mddocs/

0

# Provider Overriding

1

2

System for replacing providers, guards, pipes, filters, and interceptors with test doubles. This enables precise control over dependencies during testing, allowing developers to isolate components and create predictable test scenarios.

3

4

## Capabilities

5

6

### Override Methods

7

8

The TestingModuleBuilder provides specific methods for overriding different types of NestJS components.

9

10

```typescript { .api }

11

class TestingModuleBuilder {

12

/**

13

* Override a provider with a test double

14

* @param typeOrToken - The provider class or injection token to override

15

* @returns OverrideBy interface for specifying the replacement

16

*/

17

overrideProvider<T = any>(typeOrToken: T): OverrideBy;

18

19

/**

20

* Override a pipe with a test double

21

* @param typeOrToken - The pipe class or injection token to override

22

* @returns OverrideBy interface for specifying the replacement

23

*/

24

overridePipe<T = any>(typeOrToken: T): OverrideBy;

25

26

/**

27

* Override a guard with a test double

28

* @param typeOrToken - The guard class or injection token to override

29

* @returns OverrideBy interface for specifying the replacement

30

*/

31

overrideGuard<T = any>(typeOrToken: T): OverrideBy;

32

33

/**

34

* Override a filter with a test double

35

* @param typeOrToken - The filter class or injection token to override

36

* @returns OverrideBy interface for specifying the replacement

37

*/

38

overrideFilter<T = any>(typeOrToken: T): OverrideBy;

39

40

/**

41

* Override an interceptor with a test double

42

* @param typeOrToken - The interceptor class or injection token to override

43

* @returns OverrideBy interface for specifying the replacement

44

*/

45

overrideInterceptor<T = any>(typeOrToken: T): OverrideBy;

46

}

47

```

48

49

### OverrideBy Interface

50

51

Interface providing methods to specify how a component should be overridden.

52

53

```typescript { .api }

54

/**

55

* Interface for specifying component override strategies

56

*/

57

interface OverrideBy {

58

/**

59

* Replace with a specific value or instance

60

* @param value - The value to use as replacement

61

* @returns TestingModuleBuilder for method chaining

62

*/

63

useValue(value: any): TestingModuleBuilder;

64

65

/**

66

* Replace with a factory function result

67

* @param options - Factory configuration including function and dependencies

68

* @returns TestingModuleBuilder for method chaining

69

*/

70

useFactory(options: OverrideByFactoryOptions): TestingModuleBuilder;

71

72

/**

73

* Replace with an instance of a different class

74

* @param metatype - The class to instantiate as replacement

75

* @returns TestingModuleBuilder for method chaining

76

*/

77

useClass(metatype: any): TestingModuleBuilder;

78

}

79

80

/**

81

* Configuration options for factory-based overrides

82

*/

83

interface OverrideByFactoryOptions {

84

/**

85

* Factory function that creates the replacement instance

86

*/

87

factory: (...args: any[]) => any;

88

/**

89

* Optional array of dependencies to inject into the factory

90

*/

91

inject?: any[];

92

}

93

```

94

95

**Usage Examples:**

96

97

```typescript

98

import { Test, TestingModule } from "@nestjs/testing";

99

import { UsersService } from "./users.service";

100

import { DatabaseService } from "./database.service";

101

import { AuthGuard } from "./auth.guard";

102

import { LoggingInterceptor } from "./logging.interceptor";

103

104

describe("Provider Overriding", () => {

105

let module: TestingModule;

106

107

beforeEach(async () => {

108

// Override with useValue

109

const mockDatabaseService = {

110

findUser: jest.fn().mockResolvedValue({ id: 1, name: "Test User" }),

111

saveUser: jest.fn().mockResolvedValue({ id: 1 }),

112

};

113

114

module = await Test.createTestingModule({

115

providers: [UsersService, DatabaseService],

116

controllers: [UsersController],

117

})

118

.overrideProvider(DatabaseService)

119

.useValue(mockDatabaseService)

120

.compile();

121

});

122

123

it("should use mocked database service", async () => {

124

const usersService = module.get<UsersService>(UsersService);

125

const user = await usersService.findUser(1);

126

expect(user.name).toBe("Test User");

127

});

128

});

129

130

// Override with useClass

131

class MockAuthGuard {

132

canActivate() {

133

return true;

134

}

135

}

136

137

const moduleWithClassOverride = await Test.createTestingModule({

138

providers: [UsersService],

139

controllers: [UsersController],

140

})

141

.overrideGuard(AuthGuard)

142

.useClass(MockAuthGuard)

143

.compile();

144

145

// Override with useFactory

146

const moduleWithFactory = await Test.createTestingModule({

147

providers: [UsersService, DatabaseService, ConfigService],

148

})

149

.overrideProvider(DatabaseService)

150

.useFactory({

151

factory: (config: ConfigService) => ({

152

findUser: jest.fn(),

153

connection: config.getDatabaseUrl(),

154

}),

155

inject: [ConfigService],

156

})

157

.compile();

158

159

// Override interceptor

160

const moduleWithInterceptor = await Test.createTestingModule({

161

providers: [UsersService],

162

controllers: [UsersController],

163

})

164

.overrideInterceptor(LoggingInterceptor)

165

.useValue({

166

intercept: jest.fn((context, next) => next.handle()),

167

})

168

.compile();

169

```

170

171

### Advanced Override Patterns

172

173

**Partial Mocking:**

174

175

```typescript

176

// Override with partial implementation

177

const partialMockService = {

178

findUser: jest.fn().mockResolvedValue({ id: 1, name: "Test" }),

179

// Other methods will use original implementation or throw

180

};

181

182

const module = await Test.createTestingModule({

183

providers: [UsersService, DatabaseService],

184

})

185

.overrideProvider(DatabaseService)

186

.useValue(partialMockService)

187

.compile();

188

```

189

190

**Spy Integration:**

191

192

```typescript

193

// Create spy-enabled mock

194

const databaseServiceSpy = {

195

findUser: jest.fn(),

196

saveUser: jest.fn(),

197

deleteUser: jest.fn(),

198

};

199

200

const module = await Test.createTestingModule({

201

providers: [UsersService, DatabaseService],

202

})

203

.overrideProvider(DatabaseService)

204

.useValue(databaseServiceSpy)

205

.compile();

206

207

// Verify interactions

208

expect(databaseServiceSpy.findUser).toHaveBeenCalledWith(1);

209

```

210

211

**Token-based Overrides:**

212

213

```typescript

214

const DATABASE_TOKEN = Symbol("DATABASE_TOKEN");

215

216

const module = await Test.createTestingModule({

217

providers: [

218

UsersService,

219

{

220

provide: DATABASE_TOKEN,

221

useClass: DatabaseService,

222

},

223

],

224

})

225

.overrideProvider(DATABASE_TOKEN)

226

.useValue(mockDatabase)

227

.compile();

228

```

229

230

## Error Handling

231

232

Common override scenarios and error handling:

233

234

```typescript

235

// Handle missing dependencies

236

try {

237

const module = await Test.createTestingModule({

238

providers: [ServiceWithDependencies],

239

})

240

.overrideProvider(MissingDependency)

241

.useValue(mockDependency)

242

.compile();

243

} catch (error) {

244

// Handle compilation errors

245

}

246

247

// Override non-existent provider (will be ignored)

248

const module = await Test.createTestingModule({

249

providers: [UsersService],

250

})

251

.overrideProvider(NonExistentService) // This won't cause an error

252

.useValue(mockService)

253

.compile();

254

```

255

256

## Types

257

258

```typescript { .api }

259

import { TestingModuleBuilder } from "./testing-module.builder";

260

261

interface OverrideBy {

262

useValue: (value: any) => TestingModuleBuilder;

263

useFactory: (options: OverrideByFactoryOptions) => TestingModuleBuilder;

264

useClass: (metatype: any) => TestingModuleBuilder;

265

}

266

267

interface OverrideByFactoryOptions {

268

factory: (...args: any[]) => any;

269

inject?: any[];

270

}

271

```