How to Mock query Method of MariaDB using spyOn on Vitest
Akira Kashihara
Posted on June 3, 2022
I faced a problem to mock query
of MariaDB on Vitest. I share the problem and its solution here.
I appreciate that you point out my mistakes if you find them.
The Method to Be Test
You might have a way to mock query
of MariaDB that is in the mocked class in __mocks__
directory according to "ES6 Class Mocks" on Jest official website. However, I want to quickly mock query
method using spyOn
because I just want to test whether the parent method can get the error query
method throws.
The Method to Be Tested
This section indicates the method to be tested, which is called checkCardName
.
import mariadb, { Connection, Pool } from "mariadb";
export default class OperateMariadb {
pool: Pool;
connection: Connection | undefined;
constructor() {
this.pool = mariadb.createPool({
host: process.env.MARIADB_HOST,
user: process.env.MARIADB_USER,
password: process.env.MARIADB_PASSWORD,
database: process.env.MARIADB_DATABASE,
});
}
async getConnection(): Promise<void> {
try {
this.connection = await this.pool.getConnection();
} catch (err: any) {
throw new Error(err);
}
}
async disconnection(): Promise<boolean> {
if (this.connection) {
try {
await this.connection.end()
return true;
} catch (err: any) {
throw new Error(err);
}
} else {
throw new Error("The connection has not been established.")
}
}
poolEnd() {
this.pool.end();
}
// This method to be tested.
async checkCardName(cardName: string): Promise<boolean> {
try {
if (this.connection) {
const result = await this.connection.query(
"select * from cards where card_name = ?",
[cardName]
);
delete result.meta;
const lengthObj = Object.keys(result).length;
if (lengthObj > 0) {
return true;
} else if (lengthObj === 0) {
return false;
} else {
throw new Error("Object length is invalid in checkCardName.");
}
} else {
throw new Error("The database connection does not exist.");
}
} catch (err: any) {
throw new Error(err);
}
}
}
The Code on My Idea (This code is not good)
The following is my idea but it is not good.
it("con.query throws error", async () => {
const operateMariadb = new OperateMariadb();
await operateMariadb.getConnection();
vi.spyOn(operateMariadb.connection, "query").mockImplementation(() =>
Promise.reject(new Error("Query Error."))
);
expect(operateMariadb.checkCardName("king")).rejects.toThrow(
"Query Error."
);
operateMariadb.disconnection();
operateMariadb.poolEnd();
});
I'm not sure that this spyOn
usage to mock await this.connection.query("select * from cards where card_name = ?",[cardName]);
in checkCardName
. It runs and passes correctly, but it is not good because it gets an error as the following.
What's Wrong with This Code?
Vitest only gives us a brief error message, and I do not have any idea what's wrong with this code, so I run the testing on Jest. Jest gives us the following.
I guess Jest told me operateMariadb.connection
can be undefined
, which is wrong.
I insert if (operateMariadb.connection)
before the error, and this testing runs without any errors.
The following is the final test code.
describe("Error handling testing.", () => {
it("con.query throws error", async () => {
const operateMariadb = new OperateMariadb();
await operateMariadb.getConnection();
if (operateMariadb.connection) { //Vitest and Jest throws an error on "query" in the line after this without this if statement.
vi.spyOn(operateMariadb.connection, "query").mockImplementation(() =>
Promise.reject(new Error("Query Error."))
);
expect(operateMariadb.checkCardName("king")).rejects.toThrow(
"Query Error."
);
operateMariadb.poolEnd();
}
});
it("this.connection is undefined.", () => {
const operateMariadb = new OperateMariadb();
expect(operateMariadb.checkCardName("king")).rejects.toThrow(
"The database connection does not exist."
);
operateMariadb.poolEnd();
});
});
You can check the execution result of this code in the following URL to the Github Actions page.
https://github.com/KASHIHARAAkira/vitest-playground/actions/runs/2432378503
This original article is the following that is written by me. This is a translation of a portion of this original article from Japanese to English.
Posted on June 3, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.