I have created a DiscordJS Bot and I am trying to implement automated tests using JestJS. Here's one of the functions I am trying to create tests with:
/**
* @param {Object} client - Discord Client
*/
export const getSpecificGuild = async (client) => {
let guild = await client.guilds.fetch(GUILD_ID).catch(() => { return false });
if (!guild) return false;
return guild;
}
The problem that I can't solve right now is trying to create tests for both scenarios:
Below is the current version of my sample.test.js
file:
describe('Test getSpecificGuild Function', () => {
beforeEach(() => {
jest.clearAllMocks();
});
const mockGuild = {
...
}
const mockClient = {
guilds: {
fetch: jest.fn().mockReturnValueOnce({
catch: jest.fn().mockReturnValueOnce(false)
})
}
}
it(`should return the guild object if the guild doesn't exist.`, async () => {
expect(await getSpecificGuild(mockClient)).toBe(false);
});
it(`should return the guild object if the guild does exist.`, async () => {
expect(await getSpecificGuild(mockClient)).resolves.toBe(mockGuild);
});
});
I found it difficult to mock the fetch/catch
part of the program. Because fetch
ends if the retrieval is successful and doesn't continue to the catch
part unless it runs an error (like a try/catch
would do). Upon running the tests, it displays the following:
✓ should return the guild object if the guild doesn't exist. (1 ms)
✕ should return the guild object if the guild does exist.
TypeError: Cannot read properties of undefined (reading 'catch')
let guild = await client.guilds.fetch(GUILD_ID).catch(() => { return false });
^
Forgive me if my Jest implementation is wrong and would really appreciate everyone's assistance.
That catch
is a method on a Promise instance, you should not mock that. You should only mock guilds.fetch()
.
Also, your getSpecificGuild()
function doesn't accept a guild ID at the moment, so I updated it. And I don't think client.guilds.fetch()
will ever return falsy values, so you can remove that too:
export const getSpecificGuild = async (guildId, client) => {
let guild = await client.guilds.fetch(guildId).catch(() => {
return false;
});
return guild;
};
To mock this, you need to update your mockClient
. You could change the behaviour of the fetch
function based on the provided guild ID and conditionally return either a resolved Promise or a rejected Promise.
describe('Test getSpecificGuild Function', () => {
beforeEach(() => {
jest.clearAllMocks();
});
const mockGuild = { ... };
const VALID_GUILD_ID = '804214837842837';
const mockClient = {
guilds: {
fetch: jest.fn().mockImplementation((guildId) => {
// Valid guild retrieval
if (guildId === VALID_GUILD_ID)
return Promise.resolve(mockGuild);
// Invalid guild retrieval
else
return Promise.reject(new Error('Guild not found'));
}),
},
};
it(`should return the guild object if the guild does exist.`, async () => {
// you don't need "resolves.toBe()"" with await
expect(await getSpecificGuild(VALID_GUILD_ID, mockClient)).toBe(mockGuild);
});
it(`should return false if the guild doesn't exist.`, async () => {
expect(await getSpecificGuild('12345', mockClient)).toBe(false);
});
});