How to mock mysql2 `getConnection`

128 Views Asked by At

I can't properly mock getConnection method from pool in mysql2 lib. My setup is next:

"ts-mockito": "^2.6.1"
"typescript": "^4.8.4"
"mocha": "^10.1.0",
"mysql2": "^2.3.3",

Test:

import { Pool, PoolConnection } from "mysql2/promise";
import { mock, instance, verify, when} from "ts-mockito";
import Service from './'


describe("Conn test", function() {
  const connPool = mock<Pool>();
  const connection = mock<PoolConnection>();

  when(connPool.getConnection()).thenResolve(instance(connection));

  const service = new Service(
    instance(connPool)
  )

  it("Should save info", async function() {
    const res = await service.saveInfo(command);
    expect(res).to.not.throw;
  });
}

Code:

class Service {
  constructor(readonly pool: Pool) {}

  async saveInfo(txt: string) {
    const conn = await this.pool.getConnection();
    ...
  }
}

Test halts on line await this.pool.getConnection() and timeouts after 2 seconds and outputs error:

Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.

Increasing timeout did not help.

1

There are 1 best solutions below

0
On BEST ANSWER

It seems ts-mockito does not work well with JS promise. But there is a workaround, reference: https://github.com/NagRock/ts-mockito/issues/191#issuecomment-708743761

index.ts:

import { Pool } from 'mysql2/promise';

export default class Service {
    constructor(readonly pool: Pool) {}

    async saveInfo() {
        const conn = await this.pool.getConnection();
        return conn;
    }
}

index.test.ts:

import { Pool, PoolConnection } from 'mysql2/promise';
import { instance, mock, verify, when } from 'ts-mockito';
import Service from './';

const resolvableInstance = <T extends {}>(mock: T) =>
    new Proxy<T>(instance(mock), {
        get(target, name: PropertyKey) {
            if (['Symbol(Symbol.toPrimitive)', 'then', 'catch'].includes(name.toString())) {
                return undefined;
            }

            return (target as any)[name];
        },
    });

describe('Conn test', function () {
    it('Should save info', async function () {
        const connPool = mock<Pool>();
        const connection = mock<PoolConnection>();

        const connectionInstance = resolvableInstance(connection);
        when(connPool.getConnection()).thenResolve(connectionInstance);

        const connPoolInstance = instance(connPool);
        const service = new Service(connPoolInstance);

        const conn = await service.saveInfo();
        expect(conn).toBe(connectionInstance);
        verify(connPool.getConnection()).called();
    });
});

Test result:

 PASS  stackoverflow/76771580/index.test.ts (8.678 s)
  Conn test
    ✓ Should save info (2 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |                   
 index.ts |     100 |      100 |     100 |     100 |                   
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        8.725 s, estimated 9 s

package versions:

"ts-mockito": "^2.6.1",
"mysql2": "^3.5.2",