Config Unit test with dynamoose, NESTJS, jest

263 Views Asked by At

I'm trying to write a unit test, but I had some trouble when I defined TestingModule.

i cannot create testing module in unit test because the module which i using in a 3rd library https://github.com/hardyscc/nestjs-dynamoose

Here now, it cannot support me defining modules in unit tests.

Please, someone can give me a solution.

P/s: Error in the end of the post

Thank you a lot.

here is my spect.ts file

describe('MissionService', () => {
  let service: MissionService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [MissionService],
    }).compile();

    service = module.get<MissionService>(MissionService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });
});

here is my module

@Module({
  imports: [DynamooseModule.forFeature([MissionModel])],
  controllers: [MissionControllerAdmin],
  providers: [MissionService, MissionRepository],
  exports: [MissionService, MissionRepository],
})
export class MissionModule {}

here is my DynamooseModule

@Module({})
export class DynamooseModule {
  static forRoot(options: DynamooseModuleOptions = {}): DynamicModule {
    return {
      module: DynamooseModule,
      imports: [DynamooseCoreModule.forRoot(options)],
    };
  }

  static forRootAsync(options: DynamooseModuleAsyncOptions): DynamicModule {
    return {
      module: DynamooseModule,
      imports: [DynamooseCoreModule.forRootAsync(options)],
    };
  }

  static forFeature(models: ModelDefinition[] = []): DynamicModule {
    const providers = createDynamooseProviders(models);
    return {
      module: DynamooseModule,
      providers: providers,
      exports: providers,
    };
  }

  static forFeatureAsync(factories: AsyncModelFactory[] = []): DynamicModule {
    const providers = createDynamooseAsyncProviders(factories);
    const imports = factories.map((factory) => factory.imports || []);
    const uniqImports = new Set(flatten(imports));
    return {
      module: DynamooseModule,
      imports: [...uniqImports],
      providers: providers,
      exports: providers,
    };
  }
}
export function createDynamooseProviders(models: ModelDefinition[] = []) {
  const providers = (models || []).map((model) => ({
    provide: getModelToken(model.name),
    useFactory: () => {
      const modelInstance = dynamoose.model(
        model.name,
        model.schema,
        model.options,
      );
      if (model.serializers) {
        Object.entries(model.serializers).forEach(([key, value]) => {
          modelInstance.serializer.add(key, value);
        });
      }
      return modelInstance;
    },
    inject: [DYNAMOOSE_INITIALIZATION],
  }));
  return providers;
}

dynamoose-core.module

async function initialization(options: DynamooseModuleOptions) {
  if (options.ddb) {
    aws.ddb.set(options.ddb);
  } else if (options.aws) {
    aws.ddb.set(new aws.ddb.DynamoDB(options.aws));
  }
  if (options.local) {
    if (typeof options.local === 'boolean') {
      aws.ddb.local();
    } else {
      aws.ddb.local(options.local);
    }
  }
  if (options.table) {
    Table.defaults.set(options.table);
  }
  if (options.logger) {
    (await logger()).providers.add(
      new LoggerProvider(
        typeof options.logger === 'boolean'
          ? new Logger(DynamooseModule.name)
          : options.logger,
      ),
    );
  }
}

@Global()
@Module({})
export class DynamooseCoreModule {
  static forRoot(options: DynamooseModuleOptions = {}): DynamicModule {
    const initialProvider = {
      provide: DYNAMOOSE_INITIALIZATION,
      useFactory: () => initialization(options),
    };
    return {
      module: DynamooseCoreModule,
      providers: [initialProvider],
      exports: [initialProvider],
    };
  }

  static forRootAsync(options: DynamooseModuleAsyncOptions): DynamicModule {
    const initialProvider = {
      provide: DYNAMOOSE_INITIALIZATION,
      useFactory: (dynamoooseModuleOptions: DynamooseModuleOptions) =>
        initialization(dynamoooseModuleOptions),
      inject: [DYNAMOOSE_MODULE_OPTIONS],
    };

    const asyncProviders = this.createAsyncProviders(options);
    return {
      module: DynamooseCoreModule,
      imports: options.imports,
      providers: [...asyncProviders, initialProvider],
      exports: [initialProvider],
    };
  }

  private static createAsyncProviders(
    options: DynamooseModuleAsyncOptions,
  ): Provider[] {
    if (options.useExisting || options.useFactory) {
      return [this.createAsyncOptionsProvider(options)];
    }
    const useClass = options.useClass as Type<DynamooseOptionsFactory>;
    return [
      this.createAsyncOptionsProvider(options),
      {
        provide: useClass,
        useClass,
      },
    ];
  }

  private static createAsyncOptionsProvider(
    options: DynamooseModuleAsyncOptions,
  ): Provider {
    if (options.useFactory) {
      return {
        provide: DYNAMOOSE_MODULE_OPTIONS,
        useFactory: options.useFactory,
        inject: options.inject || [],
      };
    }

    const inject = [
      (options.useClass ||
        options.useExisting) as Type<DynamooseOptionsFactory>,
    ];

    return {
      provide: DYNAMOOSE_MODULE_OPTIONS,
      useFactory: async (optionsFactory: DynamooseOptionsFactory) =>
        await optionsFactory.createDynamooseOptions(),
      inject,
    };
  }
}
async function initialization(options: DynamooseModuleOptions) {
  if (options.ddb) {
    aws.ddb.set(options.ddb);
  } else if (options.aws) {
    aws.ddb.set(new aws.ddb.DynamoDB(options.aws));
  }
  if (options.local) {
    if (typeof options.local === 'boolean') {
      aws.ddb.local();
    } else {
      aws.ddb.local(options.local);
    }
  }
  if (options.table) {
    Table.defaults.set(options.table);
  }
  if (options.logger) {
    (await logger()).providers.add(
      new LoggerProvider(
        typeof options.logger === 'boolean'
          ? new Logger(DynamooseModule.name)
          : options.logger,
      ),
    );
  }
}

i tried import like i used in module. but it seem not work

import { DynamooseModule } from './../configuration/dynamoose/dynamoose.module';
import { Test, TestingModule } from '@nestjs/testing';

import { MissionService } from './mission.service';
import { MissionModel } from './entities/mission.entity';

describe('MissionService', () => {
  let service: MissionService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      imports: [DynamooseModule.forFeature([MissionModel])],
      providers: [MissionService],
    }).compile();

    service = module.get<MissionService>(MissionService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });
});

most common error i got

 FAIL  src/mission/mission.service.spec.ts
  MissionService
    ✕ should be defined (7 ms)

  ● MissionService › should be defined

    Nest can't resolve dependencies of the missionsModel (?). Please make sure that the argument DynamooseInitialiation at index [0] is available in the DynamooseModule context.

    Potential solutions:
    - Is DynamooseModule a valid NestJS module?
    - If DynamooseInitialiation is a provider, is it part of the current DynamooseModule?
    - If DynamooseInitialiation is exported from a separate @Module, is that module imported within DynamooseModule?
      @Module({
        imports: [ /* the Module containing DynamooseInitialiation */ ]
      })

       9 |
      10 |   beforeEach(async () => {
    > 11 |     const module: TestingModule = await Test.createTestingModule({
         |                                   ^
      12 |       imports: [DynamooseModule.forFeature([MissionModel])],
      13 |       providers: [MissionService],
      14 |     }).compile();
0

There are 0 best solutions below