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

module-overriding.mddocs/

0

# Module Overriding

1

2

Capability to replace entire modules with alternative implementations for testing scenarios with complex module dependencies. This is particularly useful for testing applications that depend on external modules or when you need to replace entire feature modules with simplified test versions.

3

4

## Capabilities

5

6

### Module Override Method

7

8

The TestingModuleBuilder provides a method to override entire modules with alternative implementations.

9

10

```typescript { .api }

11

class TestingModuleBuilder {

12

/**

13

* Override an entire module with a replacement module

14

* @param moduleToOverride - The module definition to replace

15

* @returns OverrideModule interface for specifying the replacement module

16

*/

17

overrideModule(moduleToOverride: ModuleDefinition): OverrideModule;

18

}

19

```

20

21

### OverrideModule Interface

22

23

Interface for specifying module replacement strategies.

24

25

```typescript { .api }

26

/**

27

* Interface for replacing modules in testing scenarios

28

*/

29

interface OverrideModule {

30

/**

31

* Replace the target module with a new module implementation

32

* @param newModule - The module definition to use as replacement

33

* @returns TestingModuleBuilder for method chaining

34

*/

35

useModule(newModule: ModuleDefinition): TestingModuleBuilder;

36

}

37

```

38

39

**Usage Examples:**

40

41

```typescript

42

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

43

import { Module } from "@nestjs/common";

44

import { DatabaseModule } from "./database.module";

45

import { UsersModule } from "./users.module";

46

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

47

48

// Create a test replacement for DatabaseModule

49

@Module({

50

providers: [

51

{

52

provide: "DATABASE_CONNECTION",

53

useValue: {

54

query: jest.fn(),

55

close: jest.fn(),

56

},

57

},

58

],

59

exports: ["DATABASE_CONNECTION"],

60

})

61

class TestDatabaseModule {}

62

63

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

64

let module: TestingModule;

65

66

beforeEach(async () => {

67

module = await Test.createTestingModule({

68

imports: [UsersModule], // UsersModule depends on DatabaseModule

69

})

70

.overrideModule(DatabaseModule)

71

.useModule(TestDatabaseModule)

72

.compile();

73

});

74

75

it("should use test database module", async () => {

76

const connection = module.get("DATABASE_CONNECTION");

77

expect(connection.query).toBeDefined();

78

expect(typeof connection.query).toBe("function");

79

});

80

});

81

```

82

83

### Advanced Module Override Patterns

84

85

**Dynamic Module Overriding:**

86

87

```typescript

88

import { DynamicModule } from "@nestjs/common";

89

90

// Original dynamic module

91

@Module({})

92

class ConfigModule {

93

static forRoot(options: ConfigOptions): DynamicModule {

94

return {

95

module: ConfigModule,

96

providers: [

97

{

98

provide: "CONFIG_OPTIONS",

99

useValue: options,

100

},

101

ConfigService,

102

],

103

exports: [ConfigService],

104

};

105

}

106

}

107

108

// Test replacement

109

@Module({})

110

class TestConfigModule {

111

static forRoot(): DynamicModule {

112

return {

113

module: TestConfigModule,

114

providers: [

115

{

116

provide: "CONFIG_OPTIONS",

117

useValue: { env: "test" },

118

},

119

{

120

provide: ConfigService,

121

useValue: {

122

get: jest.fn().mockReturnValue("test-value"),

123

},

124

},

125

],

126

exports: [ConfigService],

127

};

128

}

129

}

130

131

const module = await Test.createTestingModule({

132

imports: [AppModule], // AppModule imports ConfigModule.forRoot()

133

})

134

.overrideModule(ConfigModule)

135

.useModule(TestConfigModule.forRoot())

136

.compile();

137

```

138

139

**Third-party Module Overriding:**

140

141

```typescript

142

// Override external modules like TypeORM, Mongoose, etc.

143

import { TypeOrmModule } from "@nestjs/typeorm";

144

import { getRepositoryToken } from "@nestjs/typeorm";

145

import { User } from "./user.entity";

146

147

@Module({

148

providers: [

149

{

150

provide: getRepositoryToken(User),

151

useValue: {

152

find: jest.fn(),

153

findOne: jest.fn(),

154

save: jest.fn(),

155

delete: jest.fn(),

156

},

157

},

158

],

159

exports: [getRepositoryToken(User)],

160

})

161

class TestTypeOrmModule {}

162

163

const module = await Test.createTestingModule({

164

imports: [UsersModule], // UsersModule imports TypeOrmModule.forFeature([User])

165

})

166

.overrideModule(TypeOrmModule)

167

.useModule(TestTypeOrmModule)

168

.compile();

169

```

170

171

**Feature Module Simplification:**

172

173

```typescript

174

// Original complex feature module

175

@Module({

176

imports: [

177

DatabaseModule,

178

RedisModule,

179

EventEmitterModule,

180

HttpModule,

181

],

182

providers: [

183

ComplexService,

184

BackgroundProcessor,

185

ExternalApiClient,

186

],

187

exports: [ComplexService],

188

})

189

class FeatureModule {}

190

191

// Simplified test version

192

@Module({

193

providers: [

194

{

195

provide: ComplexService,

196

useValue: {

197

processData: jest.fn().mockResolvedValue("processed"),

198

validateInput: jest.fn().mockReturnValue(true),

199

},

200

},

201

],

202

exports: [ComplexService],

203

})

204

class TestFeatureModule {}

205

206

const module = await Test.createTestingModule({

207

imports: [AppModule],

208

})

209

.overrideModule(FeatureModule)

210

.useModule(TestFeatureModule)

211

.compile();

212

```

213

214

### Module Override with Providers

215

216

```typescript

217

// Override module and add additional test providers

218

@Module({

219

providers: [

220

// Mock the original module's providers

221

{

222

provide: OriginalService,

223

useValue: mockOriginalService,

224

},

225

// Add test-specific utilities

226

TestUtilityService,

227

],

228

exports: [OriginalService, TestUtilityService],

229

})

230

class TestReplacementModule {}

231

232

const module = await Test.createTestingModule({

233

imports: [MainModule],

234

})

235

.overrideModule(OriginalModule)

236

.useModule(TestReplacementModule)

237

.compile();

238

239

// Access both original and test utilities

240

const originalService = module.get<OriginalService>(OriginalService);

241

const testUtility = module.get<TestUtilityService>(TestUtilityService);

242

```

243

244

### Nested Module Overriding

245

246

```typescript

247

// When modules have nested dependencies

248

const module = await Test.createTestingModule({

249

imports: [AppModule],

250

})

251

// Override multiple modules in the dependency chain

252

.overrideModule(DatabaseModule)

253

.useModule(TestDatabaseModule)

254

.overrideModule(CacheModule)

255

.useModule(TestCacheModule)

256

.overrideModule(EventModule)

257

.useModule(TestEventModule)

258

.compile();

259

```

260

261

## Error Handling

262

263

Common scenarios and error handling when overriding modules:

264

265

```typescript

266

// Handle circular dependencies

267

try {

268

const module = await Test.createTestingModule({

269

imports: [ModuleWithCircularDep],

270

})

271

.overrideModule(CircularModule)

272

.useModule(TestCircularModule)

273

.compile();

274

} catch (error) {

275

// Handle circular dependency errors

276

console.error("Circular dependency detected:", error.message);

277

}

278

279

// Handle missing module dependencies

280

@Module({

281

imports: [MissingDependency], // This might cause issues

282

providers: [TestService],

283

})

284

class ProblematicTestModule {}

285

286

// Better approach - provide all necessary dependencies

287

@Module({

288

providers: [

289

TestService,

290

{

291

provide: "MISSING_DEPENDENCY",

292

useValue: mockDependency,

293

},

294

],

295

})

296

class WellFormedTestModule {}

297

```

298

299

## Types

300

301

```typescript { .api }

302

import { ModuleDefinition } from "@nestjs/core/interfaces/module-definition.interface";

303

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

304

305

interface OverrideModule {

306

useModule: (newModule: ModuleDefinition) => TestingModuleBuilder;

307

}

308

309

// ModuleDefinition is typically a class decorated with @Module()

310

type ModuleDefinition = Function;

311

```