Files
FemScoreboard/discord/__tests__/tts.test.ts

199 lines
7.1 KiB
TypeScript

/**
* Tests for commands/tts/tts.ts
*/
jest.mock('discord.js', () => {
const actual = jest.requireActual('discord.js');
return {
...actual,
SlashCommandBuilder: jest.fn().mockImplementation(() => ({
setName: jest.fn().mockReturnThis(),
setDescription: jest.fn().mockReturnThis(),
addStringOption: jest.fn().mockReturnThis(),
addIntegerOption: jest.fn().mockReturnThis(),
})),
EmbedBuilder: jest.fn().mockImplementation(() => ({
setColor: jest.fn().mockReturnThis(),
setAuthor: jest.fn().mockReturnThis(),
setDescription: jest.fn().mockReturnThis(),
setFooter: jest.fn().mockReturnThis(),
setTimestamp: jest.fn().mockReturnThis(),
})),
AttachmentBuilder: jest.fn().mockImplementation((buffer, options) => {
const file = { buffer, name: options?.name };
return {
...file,
setName: jest.fn().mockReturnThis(),
};
}),
};
});
jest.mock('../util', () => {
const actual = jest.requireActual('../util');
return {
...actual,
requestTTSResponse: jest.fn(),
};
});
jest.mock('../../logging', () => ({
logError: jest.fn(),
logInfo: jest.fn(),
logWarn: jest.fn(),
}));
const ttsCommand = require('../commands/tts/tts');
const { requestTTSResponse } = require('../util');
describe('tts command', () => {
let mockInteraction: {
options: { getString: jest.Mock; getInteger: jest.Mock };
reply: jest.Mock;
editReply: jest.Mock;
};
beforeEach(() => {
jest.clearAllMocks();
mockInteraction = {
options: { getString: jest.fn(), getInteger: jest.fn() },
reply: jest.fn(),
editReply: jest.fn(),
};
});
it('should have correct command data structure', () => {
expect(ttsCommand.data).toBeDefined();
expect(ttsCommand.data.setName).toBeDefined();
expect(ttsCommand.execute).toBeDefined();
expect(ttsCommand.config).toBeDefined();
});
it('should generate TTS audio for valid text with default options', async () => {
mockInteraction.options.getString.mockImplementation((name: string) => {
if (name === 'text') return 'Hello world';
if (name === 'speaker') return null;
if (name === 'instruct') return null;
return null;
});
mockInteraction.options.getInteger.mockReturnValue(null);
requestTTSResponse.mockResolvedValue({
arrayBuffer: jest.fn().mockResolvedValue(new ArrayBuffer(100)),
});
await ttsCommand.execute(mockInteraction);
// Should reply with loading embed
expect(mockInteraction.reply).toHaveBeenCalledWith({
embeds: [expect.anything()],
});
expect(requestTTSResponse).toHaveBeenCalledWith('Hello world', 'Ono_Anna', 0, null);
// Should edit with final embed and audio file
expect(mockInteraction.editReply).toHaveBeenCalledTimes(1);
const editCall = mockInteraction.editReply.mock.calls[0][0];
expect(editCall.embeds).toBeDefined();
expect(editCall.files).toBeDefined();
expect(editCall.files.length).toBeGreaterThan(0);
});
it('should generate TTS audio with custom speaker', async () => {
mockInteraction.options.getString.mockImplementation((name: string) => {
if (name === 'text') return 'Hello world';
if (name === 'speaker') return 'Miku';
if (name === 'instruct') return null;
return null;
});
mockInteraction.options.getInteger.mockReturnValue(null);
requestTTSResponse.mockResolvedValue({
arrayBuffer: jest.fn().mockResolvedValue(new ArrayBuffer(100)),
});
await ttsCommand.execute(mockInteraction);
expect(requestTTSResponse).toHaveBeenCalledWith('Hello world', 'Miku', 0, null);
});
it('should generate TTS audio with custom pitch', async () => {
mockInteraction.options.getString.mockImplementation((name: string) => {
if (name === 'text') return 'Hello world';
if (name === 'speaker') return null;
if (name === 'instruct') return null;
return null;
});
mockInteraction.options.getInteger.mockReturnValue(12);
requestTTSResponse.mockResolvedValue({
arrayBuffer: jest.fn().mockResolvedValue(new ArrayBuffer(100)),
});
await ttsCommand.execute(mockInteraction);
expect(requestTTSResponse).toHaveBeenCalledWith('Hello world', 'Ono_Anna', 12, null);
});
it('should generate TTS audio with instruction', async () => {
mockInteraction.options.getString.mockImplementation((name: string) => {
if (name === 'text') return 'Hello world';
if (name === 'speaker') return null;
if (name === 'instruct') return 'speak softly';
return null;
});
mockInteraction.options.getInteger.mockReturnValue(null);
requestTTSResponse.mockResolvedValue({
arrayBuffer: jest.fn().mockResolvedValue(new ArrayBuffer(100)),
});
await ttsCommand.execute(mockInteraction);
expect(requestTTSResponse).toHaveBeenCalledWith(
'Hello world',
'Ono_Anna',
0,
'speak softly'
);
});
it('should generate TTS audio with all custom options', async () => {
mockInteraction.options.getString.mockImplementation((name: string) => {
if (name === 'text') return 'Hello world';
if (name === 'speaker') return 'Miku';
if (name === 'instruct') return 'speak softly';
return null;
});
mockInteraction.options.getInteger.mockReturnValue(0);
requestTTSResponse.mockResolvedValue({
arrayBuffer: jest.fn().mockResolvedValue(new ArrayBuffer(100)),
});
await ttsCommand.execute(mockInteraction);
expect(requestTTSResponse).toHaveBeenCalledWith('Hello world', 'Miku', 0, 'speak softly');
});
it('should handle TTS generation errors', async () => {
mockInteraction.options.getString.mockImplementation((name: string) => {
if (name === 'text') return 'Hello world';
return null;
});
mockInteraction.options.getInteger.mockReturnValue(null);
requestTTSResponse.mockRejectedValue(new Error('TTS failed'));
await ttsCommand.execute(mockInteraction);
// Should reply with loading embed
expect(mockInteraction.reply).toHaveBeenCalledWith({
embeds: [expect.anything()],
});
// Should edit with error embed
expect(mockInteraction.editReply).toHaveBeenCalledWith({
embeds: [expect.anything()],
});
});
it('should include TTS configuration', () => {
expect(ttsCommand.config).toBeDefined();
expect(ttsCommand.config.ttsSettings).toBeDefined();
expect(ttsCommand.config.ttsSettings.speaker).toBeDefined();
expect(ttsCommand.config.ttsSettings.pitch_change_sem).toBeDefined();
});
});