0

In my app I have a process that involves CRUD operations on a mssql database.

For the connection to the db I'm using node-mssql and for establishing the connection itself I'm basically following the official documentation at https://tediousjs.github.io/node-mssql/ under the section Advanced Pool Management

The TS code for getting the Connection Pool, therefore, looks like this:

import {ConnectionPool, config} from 'mssql';

const pools = new Map();

  /**
   * Get or create a pool. If a pool doesn't exist the config must be provided.
   * If the pool does exist the config is ignored (even if it was different to the one provided
   * when creating the pool)
   *
   * @param {string} name
   * @param  [config]
   * @return {Promise.<ConnectionPool>}
   */
export function getAc3ConnectionPool (name:string, config:config) {
    if (!pools.has(name)) {
      if (!config) {
        throw new Error('Pool does not exist');
      }
      const pool = new ConnectionPool(config);
      // automatically remove the pool from the cache if `pool.close()` is called
      const close = pool.close.bind(pool);
      pool.close = () => {
        pools.delete(name);
        return close();
      };
      pools.set(name, pool.connect());
    }
    return pools.get(name);
}
  /**
   * Closes all the pools and removes them from the store
   *
   * @return {Promise<ConnectionPool[]>}
   */
export function closeAll() {
  return Promise.all(Array.from(pools.values()).map((connect) => {
      return connect.then((pool: ConnectionPool) => pool.close());
    }));
}

Now, I like to write a test with sinon where I stub the connection (ac3Connection) and everything that comes afterwards. To be honest, I don't have much or any expierence in writing tests or using sinon let alone.

This is what I came up with based on this example for jest (https://stackoverflow.com/a/69399560/3856569) trying to convert it.

For spacing reasons, I'm skipping all the other imports.

import * as ac3Connection from '../../../util/connectionsManagers/ac3/ac3Connection';

describe('EmployeeDiscountController', function () {
  let sequelize!: Sequelize;
  let user!: User;
  let mockUIRequest!: Request<any, any, EmployeeDiscountMasterViewDataRequestBody>;
  let mockUIResponse!: any;
  let mockDBConnect!: any;
  let mockDBRequest!: any;
  let redirectCalled: boolean | string = false;
  let dao!: EmployeeDiscountDao;
  let service!: EmployeeDiscountService;
  let controller!: EmployeeDiscountController;
  let renderResultPromise!: Promise<any>;

  beforeEach(async function() {
    const models: ModelCtor[] = [User, JobPostingsMarket];
    sequelize = sequelizeFor(...models);
    await sequelize.sync();

    user = await User.create({
      provider: 'foo',
      googleId: 'foo',
      emailAdress: 'foo@foo.foo',
      name: 'foo',
      lastLogin: new Date()
    });
    mockUIRequest = {user} as Request<any, any, EmployeeDiscountMasterViewDataRequestBody>;
    mockUIResponse = {
      redirect: (target: string) => {
        redirectCalled = target;
      }
    } as any;
    mockDBConnect = sinon.stub().callsFake(() => {
      return Promise.resolve({transaction: this._mockTransaction});
    });
    mockDBRequest = sinon.stub().returns({
      input: this._mockInput,
      query: this._mockQuery
    });

    renderResultPromise = new Promise<any>((resolve, reject) => {
      mockUIResponse.render = (url: string, data: any) => {
        resolve(data);
      };
    });

    dao = new EmployeeDiscountDao();
    service = new EmployeeDiscountService();
    controller = new EmployeeDiscountController();

    sinon.stub(ac3Connection, 'getAc3ConnectionPool').returns({
      ConnectionPool: sinon.stub().returns({
        request: mockDBRequest,
        connect: mockDBConnect
      })
    });
  });

  afterEach(async function () {
    sinon.restore();
  });


  it('can create an employee discount', async function () {
    const body: EmployeeDiscountMasterViewDataRequestBody = {
      firstname: 'foo',
      cardNumber: '99900000101',
      organization: 'foo' as unknown as readonly String[],
      currentOrganization: undefined,
      surname: 'foo'
    };
    mockUIRequest.body = body;
    await controller.create(mockUIRequest, mockUIResponse);
    const result = await renderResultPromise;
    expect(result).to.have.property('employeeId');
    //expect(redirectCalled).to.eq(getMasterDataViewPath(createResponse.employeeId.toString()));
  });
});

Unfortunately, I'm getting the following error:

ConnectionError: Failed to connect to :1433 - Could not connect (sequence)
    at Connection.<anonymous> (C:\xxx\node_modules\mssql\lib\tedious\connection-pool.js:68:17)
    at Object.onceWrapper (node:events:628:26)
    at Connection.emit (node:events:513:28)
    at Connection.emit (node:domain:489:12)
    at Connection.socketError (C:\Users\xxx\node_modules\tedious\lib\connection.js:1290:12)
    at C:\Users\xxx\node_modules\tedious\lib\connection.js:1116:21
    at SequentialConnectionStrategy.connect (C:\Users\xxx\node_modules\tedious\lib\connector.js:87:14)
    at C:\Users\xxx\node_modules\tedious\lib\connector.js:164:67
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  code: 'ESOCKET',

I suppose it is not mocking the establishment of the connection but I don't know at which place to change the code.

Thanks for your help!

TheDude
  • 1,205
  • 2
  • 13
  • 21

0 Answers0