feat: add components to /builders (#7195)

Co-authored-by: SpaceEEC <spaceeec@yahoo.com>
This commit is contained in:
Suneet Tipirneni
2022-01-12 14:50:08 -05:00
committed by GitHub
parent 37a22e04c2
commit 2bb40fd767
11 changed files with 777 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
import { APIActionRowComponent, ButtonStyle, ComponentType } from 'discord-api-types/v9';
import { ActionRow, ButtonComponent, createComponent, SelectMenuComponent, SelectMenuOption } from '../../src';
describe('Action Row Components', () => {
describe('Assertion Tests', () => {
test('GIVEN valid components THEN do not throw', () => {
expect(() => new ActionRow().addComponents(new ButtonComponent())).not.toThrowError();
expect(() => new ActionRow().setComponents([new ButtonComponent()])).not.toThrowError();
});
test('GIVEN valid JSON input THEN valid JSON output is given', () => {
const actionRowData: APIActionRowComponent = {
type: ComponentType.ActionRow,
components: [
{
type: ComponentType.Button,
label: 'button',
style: ButtonStyle.Primary,
custom_id: 'test',
},
{
type: ComponentType.Button,
label: 'link',
style: ButtonStyle.Link,
url: 'https://google.com',
},
{
type: ComponentType.SelectMenu,
placeholder: 'test',
custom_id: 'test',
options: [
{
label: 'option',
value: 'option',
},
],
},
],
};
expect(new ActionRow(actionRowData).toJSON()).toEqual(actionRowData);
expect(new ActionRow().toJSON()).toEqual({ type: ComponentType.ActionRow, components: [] });
expect(() => createComponent({ type: ComponentType.ActionRow, components: [] })).not.toThrowError();
// @ts-expect-error
expect(() => createComponent({ type: 42, components: [] })).toThrowError();
});
test('GIVEN valid builder options THEN valid JSON output is given', () => {
const rowWithButtonData: APIActionRowComponent = {
type: ComponentType.ActionRow,
components: [
{
type: ComponentType.Button,
label: 'test',
custom_id: '123',
style: ButtonStyle.Primary,
},
],
};
const rowWithSelectMenuData: APIActionRowComponent = {
type: ComponentType.ActionRow,
components: [
{
type: ComponentType.SelectMenu,
custom_id: '1234',
options: [
{
label: 'one',
value: 'one',
},
{
label: 'two',
value: 'two',
},
],
max_values: 10,
min_values: 12,
},
],
};
const button = new ButtonComponent().setLabel('test').setStyle(ButtonStyle.Primary).setCustomId('123');
const selectMenu = new SelectMenuComponent()
.setCustomId('1234')
.setMaxValues(10)
.setMinValues(12)
.setOptions([
new SelectMenuOption().setLabel('one').setValue('one'),
new SelectMenuOption().setLabel('two').setValue('two'),
]);
expect(new ActionRow().addComponents(button).toJSON()).toEqual(rowWithButtonData);
expect(new ActionRow().addComponents(selectMenu).toJSON()).toEqual(rowWithSelectMenuData);
});
});
});

View File

@@ -0,0 +1,146 @@
import {
APIButtonComponentWithCustomId,
APIButtonComponentWithURL,
ButtonStyle,
ComponentType,
} from 'discord-api-types/v9';
import { buttonLabelValidator, buttonStyleValidator } from '../../src/components/Assertions';
import { ButtonComponent } from '../../src/components/Button';
const buttonComponent = () => new ButtonComponent();
const longStr =
'looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong';
describe('Button Components', () => {
describe('Assertion Tests', () => {
test('GIVEN valid label THEN validator does not throw', () => {
expect(() => buttonLabelValidator.parse('foobar')).not.toThrowError();
});
test('GIVEN invalid label THEN validator does throw', () => {
expect(() => buttonLabelValidator.parse(null)).toThrowError();
expect(() => buttonLabelValidator.parse('')).toThrowError();
expect(() => buttonLabelValidator.parse(longStr)).toThrowError();
});
test('GIVEN valid style THEN validator does not throw', () => {
expect(() => buttonStyleValidator.parse(3)).not.toThrowError();
expect(() => buttonStyleValidator.parse(ButtonStyle.Secondary)).not.toThrowError();
});
test('GIVEN invalid style THEN validator does not throw', () => {
expect(() => buttonStyleValidator.parse(7)).toThrowError();
});
test('GIVEN valid fields THEN builder does not throw', () => {
expect(() =>
buttonComponent().setCustomId('custom').setStyle(ButtonStyle.Primary).setLabel('test'),
).not.toThrowError();
expect(() => {
const button = buttonComponent()
.setCustomId('custom')
.setStyle(ButtonStyle.Primary)
.setDisabled(true)
.setEmoji({ name: 'test' });
button.toJSON();
}).not.toThrowError();
expect(() => buttonComponent().setURL('https://google.com')).not.toThrowError();
});
test('GIVEN invalid fields THEN build does throw', () => {
expect(() => {
buttonComponent().setCustomId(longStr);
}).toThrowError();
expect(() => {
const button = buttonComponent()
.setCustomId('custom')
.setStyle(ButtonStyle.Primary)
.setDisabled(true)
.setLabel('test')
.setURL('https://google.com')
.setEmoji({ name: 'test' });
button.toJSON();
}).toThrowError();
expect(() => {
// @ts-expect-error
const button = buttonComponent().setEmoji('test');
button.toJSON();
}).toThrowError();
expect(() => {
const button = buttonComponent().setStyle(ButtonStyle.Primary);
button.toJSON();
}).toThrowError();
expect(() => {
const button = buttonComponent().setStyle(ButtonStyle.Primary).setCustomId('test');
button.toJSON();
}).toThrowError();
expect(() => {
const button = buttonComponent().setStyle(ButtonStyle.Link);
button.toJSON();
}).toThrowError();
expect(() => {
const button = buttonComponent().setStyle(ButtonStyle.Primary).setLabel('test').setURL('https://google.com');
button.toJSON();
}).toThrowError();
expect(() => {
const button = buttonComponent().setStyle(ButtonStyle.Link).setLabel('test');
button.toJSON();
}).toThrowError();
expect(() => buttonComponent().setStyle(24)).toThrowError();
expect(() => buttonComponent().setLabel(longStr)).toThrowError();
// @ts-expect-error
expect(() => buttonComponent().setDisabled(0)).toThrowError();
// @ts-expect-error
expect(() => buttonComponent().setEmoji('foo')).toThrowError();
expect(() => buttonComponent().setURL('foobar')).toThrowError();
});
test('GiVEN valid input THEN valid JSON outputs are given', () => {
const interactionData: APIButtonComponentWithCustomId = {
type: ComponentType.Button,
custom_id: 'test',
label: 'test',
style: ButtonStyle.Primary,
disabled: true,
};
expect(new ButtonComponent(interactionData).toJSON()).toEqual(interactionData);
expect(
buttonComponent()
.setCustomId(interactionData.custom_id)
.setLabel(interactionData.label)
.setStyle(interactionData.style)
.setDisabled(interactionData.disabled)
.toJSON(),
).toEqual(interactionData);
const linkData: APIButtonComponentWithURL = {
type: ComponentType.Button,
label: 'test',
style: ButtonStyle.Link,
disabled: true,
url: 'https://google.com',
};
expect(new ButtonComponent(linkData).toJSON()).toEqual(linkData);
expect(buttonComponent().setLabel(linkData.label).setDisabled(true).setURL(linkData.url));
});
});
});

View File

@@ -0,0 +1,72 @@
import { APISelectMenuComponent, APISelectMenuOption, ComponentType } from 'discord-api-types/v9';
import { SelectMenuComponent, SelectMenuOption } from '../../src/index';
const selectMenu = () => new SelectMenuComponent();
const selectMenuOption = () => new SelectMenuOption();
const longStr =
'looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong';
describe('Button Components', () => {
describe('Assertion Tests', () => {
test('GIVEN valid inputs THEN Select Menu does not throw', () => {
expect(() => selectMenu().setCustomId('foo')).not.toThrowError();
expect(() => selectMenu().setMaxValues(10)).not.toThrowError();
expect(() => selectMenu().setMinValues(3)).not.toThrowError();
expect(() => selectMenu().setDisabled(true)).not.toThrowError();
expect(() => selectMenu().setPlaceholder('description')).not.toThrowError();
const option = selectMenuOption()
.setLabel('test')
.setValue('test')
.setDefault(true)
.setEmoji({ name: 'test' })
.setDescription('description');
expect(() => selectMenu().addOptions(option)).not.toThrowError();
expect(() => selectMenu().setOptions([option])).not.toThrowError();
});
test('GIVEN invalid inputs THEN Select Menu does throw', () => {
expect(() => selectMenu().setCustomId(longStr)).toThrowError();
expect(() => selectMenu().setMaxValues(30)).toThrowError();
expect(() => selectMenu().setMinValues(-20)).toThrowError();
// @ts-expect-error
expect(() => selectMenu().setDisabled(0)).toThrowError();
expect(() => selectMenu().setPlaceholder(longStr)).toThrowError();
expect(() => {
selectMenuOption()
.setLabel(longStr)
.setValue(longStr)
// @ts-expect-error
.setDefault(-1)
// @ts-expect-error
.setEmoji({ name: 1 })
.setDescription(longStr);
}).toThrowError();
});
test('GIVEN valid JSON input THEN valid JSON history is correct', () => {
const selectMenuOptionData: APISelectMenuOption = {
label: 'test',
value: 'test',
emoji: { name: 'test' },
default: true,
description: 'test',
};
const selectMenuData: APISelectMenuComponent = {
type: ComponentType.SelectMenu,
custom_id: 'test',
max_values: 10,
min_values: 3,
disabled: true,
options: [selectMenuOptionData],
placeholder: 'test',
};
expect(new SelectMenuComponent(selectMenuData).toJSON()).toEqual(selectMenuData);
expect(new SelectMenuOption(selectMenuOptionData).toJSON()).toEqual(selectMenuOptionData);
});
});
});