Search code examples
node.jstypescriptmocha.jsmysql2ts-mockito

How to mock mysql2 `getConnection`


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.


Solution

  • 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",