Skip to content

Commit b7e6238

Browse files
authored
test(builders): improve coverage (#8274)
1 parent cafde77 commit b7e6238

File tree

6 files changed

+199
-6
lines changed

6 files changed

+199
-6
lines changed
+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import {
2+
APIActionRowComponent,
3+
APIButtonComponent,
4+
APIMessageActionRowComponent,
5+
APISelectMenuComponent,
6+
APITextInputComponent,
7+
ButtonStyle,
8+
ComponentType,
9+
TextInputStyle,
10+
} from 'discord-api-types/v10';
11+
import { describe, test, expect } from 'vitest';
12+
import {
13+
ActionRowBuilder,
14+
ButtonBuilder,
15+
createComponentBuilder,
16+
SelectMenuBuilder,
17+
TextInputBuilder,
18+
} from '../../src/index';
19+
20+
describe('createComponentBuilder', () => {
21+
test.each([ButtonBuilder, SelectMenuBuilder, TextInputBuilder])(
22+
'passing an instance of %j should return itself',
23+
(Builder) => {
24+
const builder = new Builder();
25+
expect(createComponentBuilder(builder)).toBe(builder);
26+
},
27+
);
28+
29+
test('GIVEN an action row component THEN returns a ActionRowBuilder', () => {
30+
const actionRow: APIActionRowComponent<APIMessageActionRowComponent> = {
31+
components: [],
32+
type: ComponentType.ActionRow,
33+
};
34+
35+
expect(createComponentBuilder(actionRow)).toBeInstanceOf(ActionRowBuilder);
36+
});
37+
38+
test('GIVEN a button component THEN returns a ButtonBuilder', () => {
39+
const button: APIButtonComponent = {
40+
custom_id: 'abc',
41+
style: ButtonStyle.Primary,
42+
type: ComponentType.Button,
43+
};
44+
45+
expect(createComponentBuilder(button)).toBeInstanceOf(ButtonBuilder);
46+
});
47+
48+
test('GIVEN a select menu component THEN returns a SelectMenuBuilder', () => {
49+
const selectMenu: APISelectMenuComponent = {
50+
custom_id: 'abc',
51+
options: [],
52+
type: ComponentType.SelectMenu,
53+
};
54+
55+
expect(createComponentBuilder(selectMenu)).toBeInstanceOf(SelectMenuBuilder);
56+
});
57+
58+
test('GIVEN a text input component THEN returns a TextInputBuilder', () => {
59+
const textInput: APITextInputComponent = {
60+
custom_id: 'abc',
61+
label: 'abc',
62+
style: TextInputStyle.Short,
63+
type: ComponentType.TextInput,
64+
};
65+
66+
expect(createComponentBuilder(textInput)).toBeInstanceOf(TextInputBuilder);
67+
});
68+
69+
test('GIVEN an unknown component type THEN throws error', () => {
70+
// @ts-expect-error
71+
expect(() => createComponentBuilder({ type: 'invalid' })).toThrowError();
72+
});
73+
});

Diff for: packages/builders/__tests__/interactions/ContextMenuCommands.test.ts

+4
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ describe('Context Menu Commands', () => {
8686
test('GIVEN valid builder with defaultPermission false THEN does not throw error', () => {
8787
expect(() => getBuilder().setName('foo').setDefaultPermission(false)).not.toThrowError();
8888
});
89+
90+
test('GIVEN valid builder with dmPermission false THEN does not throw error', () => {
91+
expect(() => getBuilder().setName('foo').setDMPermission(false)).not.toThrowError();
92+
});
8993
});
9094

9195
describe('Context menu command localizations', () => {

Diff for: packages/builders/__tests__/interactions/SlashCommands/Options.test.ts

+14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
APIApplicationCommandAttachmentOption,
23
APIApplicationCommandBooleanOption,
34
APIApplicationCommandChannelOption,
45
APIApplicationCommandIntegerOption,
@@ -12,6 +13,7 @@ import {
1213
} from 'discord-api-types/v10';
1314
import { describe, test, expect } from 'vitest';
1415
import {
16+
SlashCommandAttachmentOption,
1517
SlashCommandBooleanOption,
1618
SlashCommandChannelOption,
1719
SlashCommandIntegerOption,
@@ -58,6 +60,9 @@ const getRoleOption = () => new SlashCommandRoleOption().setName('owo').setDescr
5860
const getMentionableOption = () =>
5961
new SlashCommandMentionableOption().setName('owo').setDescription('Testing 123').setRequired(true);
6062

63+
const getAttachmentOption = () =>
64+
new SlashCommandAttachmentOption().setName('attachment').setDescription('attachment').setRequired(true);
65+
6166
describe('Application Command toJSON() results', () => {
6267
test('GIVEN a boolean option THEN calling toJSON should return a valid JSON', () => {
6368
expect(getBooleanOption().toJSON()).toEqual<APIApplicationCommandBooleanOption>({
@@ -205,4 +210,13 @@ describe('Application Command toJSON() results', () => {
205210
required: true,
206211
});
207212
});
213+
214+
test('GIVEN an attachment option THEN calling toJSON should return a valid JSON', () => {
215+
expect(getAttachmentOption().toJSON()).toEqual<APIApplicationCommandAttachmentOption>({
216+
name: 'attachment',
217+
description: 'attachment',
218+
type: ApplicationCommandOptionType.Attachment,
219+
required: true,
220+
});
221+
});
208222
});

Diff for: packages/builders/__tests__/interactions/SlashCommands/SlashCommands.test.ts

+2
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ describe('Slash Commands', () => {
9393
test('GIVEN valid array of options or choices THEN does not throw error', () => {
9494
expect(() => SlashCommandAssertions.validateMaxOptionsLength([])).not.toThrowError();
9595

96+
expect(() => SlashCommandAssertions.validateChoicesLength(25)).not.toThrowError();
9697
expect(() => SlashCommandAssertions.validateChoicesLength(25, [])).not.toThrowError();
9798
});
9899

@@ -133,6 +134,7 @@ describe('Slash Commands', () => {
133134
getBuilder()
134135
.setName('example')
135136
.setDescription('Example command')
137+
.setDMPermission(false)
136138
.addBooleanOption((boolean) =>
137139
boolean.setName('iscool').setDescription('Are we cool or what?').setRequired(true),
138140
)

Diff for: packages/builders/__tests__/interactions/modal.test.ts

+64-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { APIModalInteractionResponseCallbackData, ComponentType, TextInputStyle } from 'discord-api-types/v10';
1+
import {
2+
APIModalInteractionResponseCallbackData,
3+
APITextInputComponent,
4+
ComponentType,
5+
TextInputStyle,
6+
} from 'discord-api-types/v10';
27
import { describe, test, expect } from 'vitest';
38
import {
49
ActionRowBuilder,
@@ -49,16 +54,18 @@ describe('Modals', () => {
4954

5055
test('GIVEN valid fields THEN builder does not throw', () => {
5156
expect(() =>
52-
modal()
53-
.setTitle('test')
54-
.setCustomId('foobar')
55-
.setComponents(new ActionRowBuilder())
56-
.addComponents([new ActionRowBuilder()]),
57+
modal().setTitle('test').setCustomId('foobar').setComponents(new ActionRowBuilder()),
58+
).not.toThrowError();
59+
60+
expect(() =>
61+
// @ts-expect-error: You can pass a TextInputBuilder and it will add it to an action row
62+
modal().setTitle('test').setCustomId('foobar').addComponents(new TextInputBuilder()),
5763
).not.toThrowError();
5864
});
5965

6066
test('GIVEN invalid fields THEN builder does throw', () => {
6167
expect(() => modal().setTitle('test').setCustomId('foobar').toJSON()).toThrowError();
68+
6269
// @ts-expect-error
6370
expect(() => modal().setTitle('test').setCustomId(42).toJSON()).toThrowError();
6471
});
@@ -112,4 +119,55 @@ describe('Modals', () => {
112119
.toJSON(),
113120
).toEqual(modalData);
114121
});
122+
123+
describe('equals()', () => {
124+
const textInput1 = new TextInputBuilder()
125+
.setCustomId('custom id')
126+
.setLabel('label')
127+
.setStyle(TextInputStyle.Paragraph);
128+
129+
const textInput2: APITextInputComponent = {
130+
type: ComponentType.TextInput,
131+
custom_id: 'custom id',
132+
label: 'label',
133+
style: TextInputStyle.Paragraph,
134+
};
135+
136+
test('GIVEN equal builders THEN returns true', () => {
137+
const equalTextInput = new TextInputBuilder()
138+
.setCustomId('custom id')
139+
.setLabel('label')
140+
.setStyle(TextInputStyle.Paragraph);
141+
142+
expect(textInput1.equals(equalTextInput)).toBeTruthy();
143+
});
144+
145+
test('GIVEN the same builder THEN returns true', () => {
146+
expect(textInput1.equals(textInput1)).toBeTruthy();
147+
});
148+
149+
test('GIVEN equal builder and data THEN returns true', () => {
150+
expect(textInput1.equals(textInput2)).toBeTruthy();
151+
});
152+
153+
test('GIVEN different builders THEN returns false', () => {
154+
const diffTextInput = new TextInputBuilder()
155+
.setCustomId('custom id')
156+
.setLabel('label 2')
157+
.setStyle(TextInputStyle.Paragraph);
158+
159+
expect(textInput1.equals(diffTextInput)).toBeFalsy();
160+
});
161+
162+
test('GIVEN different text input builder and data THEN returns false', () => {
163+
const diffTextInputData: APITextInputComponent = {
164+
type: ComponentType.TextInput,
165+
custom_id: 'custom id',
166+
label: 'label 2',
167+
style: TextInputStyle.Short,
168+
};
169+
170+
expect(textInput1.equals(diffTextInputData)).toBeFalsy();
171+
});
172+
});
115173
});

Diff for: packages/builders/__tests__/util.test.ts

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { describe, test, expect } from 'vitest';
2+
import {
3+
isJSONEncodable,
4+
isEquatable,
5+
ActionRowBuilder,
6+
enableValidators,
7+
disableValidators,
8+
isValidationEnabled,
9+
} from '../src/index';
10+
11+
describe('isEquatable', () => {
12+
test('returns true if the object is equatable', () => {
13+
expect(isEquatable({ equals: () => true })).toBeTruthy();
14+
});
15+
16+
test('returns false if the object is not equatable', () => {
17+
expect(isEquatable({})).toBeFalsy();
18+
});
19+
});
20+
21+
describe('isJSONEncodable', () => {
22+
test('returns true if the object is JSON encodable', () => {
23+
expect(isJSONEncodable({ toJSON: () => ({}) })).toBeTruthy();
24+
expect(isJSONEncodable(new ActionRowBuilder())).toBeTruthy();
25+
});
26+
27+
test('returns false if the object is not JSON encodable', () => {
28+
expect(isJSONEncodable({})).toBeFalsy();
29+
});
30+
});
31+
32+
describe('validation', () => {
33+
test('enables validation', () => {
34+
enableValidators();
35+
expect(isValidationEnabled()).toBeTruthy();
36+
});
37+
38+
test('disables validation', () => {
39+
disableValidators();
40+
expect(isValidationEnabled()).toBeFalsy();
41+
});
42+
});

0 commit comments

Comments
 (0)