2025-02-02 14:10:51 -05:00
|
|
|
const { createMockInteraction } = require('../utils/testUtils');
|
|
|
|
|
|
|
|
|
|
// Mock the discord.js module
|
|
|
|
|
jest.mock('discord.js', () => ({
|
|
|
|
|
SlashCommandBuilder: jest.fn().mockReturnValue({
|
|
|
|
|
setName: jest.fn().mockReturnThis(),
|
|
|
|
|
setDescription: jest.fn().mockReturnThis(),
|
|
|
|
|
addUserOption: jest.fn().mockImplementation(callback => {
|
|
|
|
|
const option = {
|
|
|
|
|
setName: jest.fn().mockReturnThis(),
|
|
|
|
|
setDescription: jest.fn().mockReturnThis(),
|
|
|
|
|
setRequired: jest.fn().mockReturnThis(),
|
|
|
|
|
};
|
|
|
|
|
callback(option);
|
|
|
|
|
return {
|
2025-12-25 10:28:44 -05:00
|
|
|
addStringOption: jest.fn().mockImplementation(cb => {
|
|
|
|
|
const strOption = {
|
2025-02-02 14:10:51 -05:00
|
|
|
setName: jest.fn().mockReturnThis(),
|
|
|
|
|
setDescription: jest.fn().mockReturnThis(),
|
2025-12-25 10:28:44 -05:00
|
|
|
setRequired: jest.fn().mockReturnThis(),
|
2025-02-02 14:10:51 -05:00
|
|
|
};
|
2025-12-25 10:28:44 -05:00
|
|
|
cb(strOption);
|
2025-02-02 14:10:51 -05:00
|
|
|
return {
|
|
|
|
|
setDefaultMemberPermissions: jest.fn().mockReturnThis(),
|
|
|
|
|
toJSON: jest.fn().mockReturnValue({
|
|
|
|
|
name: 'kick',
|
|
|
|
|
description: 'Kick a user from the server',
|
|
|
|
|
options: [
|
|
|
|
|
{
|
|
|
|
|
name: 'target',
|
|
|
|
|
description: 'The user to kick',
|
|
|
|
|
type: 6,
|
|
|
|
|
required: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'reason',
|
|
|
|
|
description: 'Reason for kicking',
|
|
|
|
|
type: 3,
|
|
|
|
|
required: false,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
};
|
|
|
|
|
}),
|
|
|
|
|
};
|
|
|
|
|
}),
|
|
|
|
|
toJSON: jest.fn(),
|
|
|
|
|
}),
|
|
|
|
|
PermissionFlagsBits: {
|
2025-12-25 10:28:44 -05:00
|
|
|
KickMembers: 0x0000000000000002n,
|
2025-02-02 14:10:51 -05:00
|
|
|
},
|
|
|
|
|
}));
|
|
|
|
|
|
2025-12-25 10:28:44 -05:00
|
|
|
const KickCommand = require('../../commands/kick').default;
|
|
|
|
|
const kickCommand = new KickCommand();
|
2025-02-02 14:10:51 -05:00
|
|
|
|
|
|
|
|
describe('Kick Command', () => {
|
|
|
|
|
describe('Command Structure', () => {
|
|
|
|
|
it('should have correct name and description', () => {
|
|
|
|
|
const commandData = kickCommand.data.toJSON();
|
|
|
|
|
expect(commandData.name).toBe('kick');
|
|
|
|
|
expect(commandData.description).toBe('Kick a user from the server');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should have required command properties', () => {
|
|
|
|
|
expect(kickCommand).toHaveProperty('data');
|
|
|
|
|
expect(kickCommand).toHaveProperty('execute');
|
|
|
|
|
expect(typeof kickCommand.execute).toBe('function');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should have correct option configuration', () => {
|
|
|
|
|
const commandData = kickCommand.data.toJSON();
|
|
|
|
|
const [targetOption, reasonOption] = commandData.options;
|
|
|
|
|
|
|
|
|
|
expect(targetOption.name).toBe('target');
|
|
|
|
|
expect(targetOption.description).toBe('The user to kick');
|
|
|
|
|
expect(targetOption.required).toBe(true);
|
|
|
|
|
|
|
|
|
|
expect(reasonOption.name).toBe('reason');
|
|
|
|
|
expect(reasonOption.description).toBe('Reason for kicking');
|
|
|
|
|
expect(reasonOption.required).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('Command Execution', () => {
|
|
|
|
|
let interaction;
|
|
|
|
|
const mockKick = jest.fn();
|
|
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
mockKick.mockReset();
|
|
|
|
|
|
|
|
|
|
const mockTarget = {
|
|
|
|
|
kickable: true,
|
|
|
|
|
kick: mockKick,
|
|
|
|
|
user: {
|
|
|
|
|
tag: 'TestUser#1234',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
interaction = createMockInteraction({
|
|
|
|
|
commandName: 'kick',
|
|
|
|
|
memberOptions: {
|
|
|
|
|
target: mockTarget,
|
|
|
|
|
},
|
|
|
|
|
stringOptions: {
|
|
|
|
|
reason: 'Test reason',
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should successfully kick a user with reason', async () => {
|
|
|
|
|
await kickCommand.execute(interaction);
|
|
|
|
|
|
|
|
|
|
expect(mockKick).toHaveBeenCalledWith('Test reason');
|
|
|
|
|
expect(interaction.reply).toHaveBeenCalledWith({
|
|
|
|
|
content: expect.stringContaining('Successfully kicked TestUser#1234'),
|
|
|
|
|
ephemeral: true,
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should use default reason when none provided', async () => {
|
|
|
|
|
interaction = createMockInteraction({
|
|
|
|
|
commandName: 'kick',
|
|
|
|
|
memberOptions: {
|
|
|
|
|
target: {
|
|
|
|
|
kickable: true,
|
|
|
|
|
kick: mockKick,
|
|
|
|
|
user: { tag: 'TestUser#1234' },
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
stringOptions: {
|
|
|
|
|
reason: null,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await kickCommand.execute(interaction);
|
|
|
|
|
|
|
|
|
|
expect(mockKick).toHaveBeenCalledWith('No reason provided');
|
|
|
|
|
expect(interaction.reply).toHaveBeenCalledWith({
|
|
|
|
|
content: expect.stringContaining('No reason provided'),
|
|
|
|
|
ephemeral: true,
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should handle non-existent target', async () => {
|
|
|
|
|
interaction = createMockInteraction({
|
|
|
|
|
commandName: 'kick',
|
|
|
|
|
memberOptions: {
|
|
|
|
|
target: null,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await kickCommand.execute(interaction);
|
|
|
|
|
|
|
|
|
|
expect(mockKick).not.toHaveBeenCalled();
|
|
|
|
|
expect(interaction.reply).toHaveBeenCalledWith({
|
2025-12-25 10:28:44 -05:00
|
|
|
content: 'Command failed: That user is not in this server!',
|
2025-02-02 14:10:51 -05:00
|
|
|
ephemeral: true,
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should handle non-kickable target', async () => {
|
|
|
|
|
interaction = createMockInteraction({
|
|
|
|
|
commandName: 'kick',
|
|
|
|
|
memberOptions: {
|
|
|
|
|
target: {
|
|
|
|
|
kickable: false,
|
|
|
|
|
user: { tag: 'Admin#1234' },
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await kickCommand.execute(interaction);
|
|
|
|
|
|
|
|
|
|
expect(mockKick).not.toHaveBeenCalled();
|
|
|
|
|
expect(interaction.reply).toHaveBeenCalledWith({
|
|
|
|
|
content:
|
2025-12-25 10:28:44 -05:00
|
|
|
'Command failed: I cannot kick this user! They may have higher permissions than me.',
|
2025-02-02 14:10:51 -05:00
|
|
|
ephemeral: true,
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should handle kick failure', async () => {
|
|
|
|
|
const mockTarget = {
|
|
|
|
|
kickable: true,
|
|
|
|
|
kick: jest.fn().mockRejectedValueOnce(new Error('Failed to kick user')),
|
|
|
|
|
user: { tag: 'TestUser#1234' },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
interaction = createMockInteraction({
|
|
|
|
|
commandName: 'kick',
|
|
|
|
|
memberOptions: {
|
|
|
|
|
target: mockTarget,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await kickCommand.execute(interaction);
|
|
|
|
|
|
|
|
|
|
expect(interaction.reply).toHaveBeenCalledWith({
|
2025-12-25 10:28:44 -05:00
|
|
|
content: 'Command failed: Failed to kick user',
|
2025-02-02 14:10:51 -05:00
|
|
|
ephemeral: true,
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should handle interaction reply failure', async () => {
|
|
|
|
|
interaction = createMockInteraction({
|
|
|
|
|
commandName: 'kick',
|
|
|
|
|
memberOptions: {
|
|
|
|
|
target: {
|
|
|
|
|
kickable: true,
|
|
|
|
|
kick: mockKick,
|
|
|
|
|
user: { tag: 'TestUser#1234' },
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
replyFails: true,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await expect(kickCommand.execute(interaction)).rejects.toThrow(
|
|
|
|
|
'Failed to reply',
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|