2

I wish to write unit tests for my mongodb datasource in my Loopback 4 project, however I could not find any examples.

Below is my datasource:

import {inject, lifeCycleObserver, LifeCycleObserver} from '@loopback/core';
import {juggler} from '@loopback/repository';

const arrayStr: string[] = [];

const config = {
  name: 'mongodb',
  connector: 'mongodb',
  // url: '',
  host: 'localhost',
  port: 27017,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  authSource: 'admin',
  database: 'testdb',
  ssl: false, // default to false
  sslValidate: false, // default to false
  useNewUrlParser: true,
  allowExtendedOperators: true,
  sslCA: arrayStr,
};


// Observe application's life cycle to disconnect the datasource when
// application is stopped. This allows the application to be shut down
// gracefully. The `stop()` method is inherited from `juggler.DataSource`.
// Learn more at https://loopback.io/doc/en/lb4/Life-cycle.html
@lifeCycleObserver('datasource')
export class MongodbDataSource extends juggler.DataSource
  implements LifeCycleObserver {
  static dataSourceName = 'mongodb';
  static readonly defaultConfig = config;

  constructor(
    @inject('datasources.config.mongodb', {optional: true})
    dsConfig: object = config,
  ) {
    super(dsConfig);
  }
}

I have tried writing a basic constructor test:

import {MongodbDataSource} from '../../../datasources';
import {expect} from '@loopback/testlab';

describe('MongoDB Datasource (unit)', () => {
  // we recommend to group tests by method names
  describe('consturctor()', () => {
    it('basic constructor', () => {
      const ds = new MongodbDataSource();
      expect(ds.name).to.equal('mongodb'); // default name
    });
  });
});

However, tests will hang/stop and not completed. Appreciate any advice.

1 Answers1

1

When you create a new datasource, the underlying connector (in your case loopback-connector-mongodb) will immediately start the process of connecting to the database and will create a connection pool. When your tests finish, the opened connections in this pool are blocking Node.js from exiting.

Personally, I consider this as a bug in LoopBack connector implementations, but that's how things are ‍♂️

You have several options how to address the problem:

  1. Tell Mocha to exit the process after all tests finished using Mocha's exit flag (docs). I believe that recently scaffolded LB4 projects should have this flag enabled by default via .mocharc.json file.

  2. Add an after or afterEach hook to stop the datasource after the test(s).

     describe('MongoDB Datasource (unit)', () => {
       let ds: MongodbDataSource;
       // Setup a hook to stop the datasource created by the test
       afterEach(() => ds && ds.stop());
    
       describe('constructor()', () => {
         it('basic constructor', () => {
           // important: no `const` keyword, use the shared variable
           ds = new MongodbDataSource();
           expect(ds.name).to.equal('mongodb'); // default name
         });
       });
     });
    
  3. Add lazyConnect: true to datasource settings used by your tests. This will prevent the connector from initiating database connections at datasource creation time and defer connecting until a first database request is made.

     const ds = new MongodbDataSource({
       ...MongodbDataSource.defaultConfig,
       lazyConnect: true,
     });
    

These three approaches are independent, you can implement more (or all) of them together.

Miroslav Bajtoš
  • 10,667
  • 1
  • 41
  • 99