Skip to content

Commit

Permalink
refactor: Don't return builders from API data (#7584)
Browse files Browse the repository at this point in the history
* refactor: don't return builders from API data

* Update packages/discord.js/src/structures/ActionRow.js

Co-authored-by: Antonio Román <kyradiscord@gmail.com>

* fix: circular dependency

* fix: circular dependency pt.2

* chore: make requested changes

* chore: bump dapi-types

* chore: convert text input

* chore: convert text input

* feat: handle cases of unknown component types better

* refactor: refactor modal to builder

* feat: add #from for easy builder conversions

* refactor: make requested changes

* chore: make requested changes

* style: fix linting error

Co-authored-by: Antonio Román <kyradiscord@gmail.com>
Co-authored-by: almeidx <almeidx@pm.me>
  • Loading branch information
3 people committed Mar 12, 2022
1 parent 230c0c4 commit 549716e
Show file tree
Hide file tree
Showing 44 changed files with 974 additions and 705 deletions.
55 changes: 28 additions & 27 deletions packages/builders/__tests__/components/actionRow.test.ts
@@ -1,13 +1,13 @@
import { APIActionRowComponent, APIMessageActionRowComponent, ButtonStyle, ComponentType } from 'discord-api-types/v9';
import {
APIActionRowComponent,
APIActionRowComponentTypes,
APIMessageActionRowComponent,
ButtonStyle,
ComponentType,
} from 'discord-api-types/v9';
import { ActionRow, ButtonComponent, createComponent, SelectMenuComponent, SelectMenuOption } from '../../src';
ActionRowBuilder,
ButtonBuilder,
createComponentBuilder,
SelectMenuBuilder,
SelectMenuOptionBuilder,
} from '../../src';

const rowWithButtonData: APIActionRowComponent<APIMessageComponent> = {
const rowWithButtonData: APIActionRowComponent<APIMessageActionRowComponent> = {
type: ComponentType.ActionRow,
components: [
{
Expand All @@ -19,7 +19,7 @@ const rowWithButtonData: APIActionRowComponent<APIMessageComponent> = {
],
};

const rowWithSelectMenuData: APIActionRowComponent<APIMessageComponent> = {
const rowWithSelectMenuData: APIActionRowComponent<APIMessageActionRowComponent> = {
type: ComponentType.ActionRow,
components: [
{
Expand All @@ -44,8 +44,8 @@ const rowWithSelectMenuData: APIActionRowComponent<APIMessageComponent> = {
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();
expect(() => new ActionRowBuilder().addComponents(new ButtonBuilder())).not.toThrowError();
expect(() => new ActionRowBuilder().setComponents(new ButtonBuilder())).not.toThrowError();
});

test('GIVEN valid JSON input THEN valid JSON output is given', () => {
Expand Down Expand Up @@ -78,13 +78,12 @@ describe('Action Row Components', () => {
],
};

expect(new ActionRow(actionRowData).toJSON()).toEqual(actionRowData);
expect(new ActionRow().toJSON()).toEqual({ type: ComponentType.ActionRow, components: [] });
expect(() => createComponent({ type: ComponentType.ActionRow, components: [] })).not.toThrowError();
expect(() => createComponent({ type: 42, components: [] })).toThrowError();
expect(new ActionRowBuilder(actionRowData).toJSON()).toEqual(actionRowData);
expect(new ActionRowBuilder().toJSON()).toEqual({ type: ComponentType.ActionRow, components: [] });
expect(() => createComponentBuilder({ type: ComponentType.ActionRow, components: [] })).not.toThrowError();
});
test('GIVEN valid builder options THEN valid JSON output is given', () => {
const rowWithButtonData: APIActionRowComponent<APIActionRowComponentTypes> = {
const rowWithButtonData: APIActionRowComponent<APIMessageActionRowComponent> = {
type: ComponentType.ActionRow,
components: [
{
Expand All @@ -96,7 +95,7 @@ describe('Action Row Components', () => {
],
};

const rowWithSelectMenuData: APIActionRowComponent<APIActionRowComponentTypes> = {
const rowWithSelectMenuData: APIActionRowComponent<APIMessageActionRowComponent> = {
type: ComponentType.ActionRow,
components: [
{
Expand All @@ -118,22 +117,24 @@ describe('Action Row Components', () => {
],
};

const button = new ButtonComponent().setLabel('test').setStyle(ButtonStyle.Primary).setCustomId('123');
const selectMenu = new SelectMenuComponent()
expect(new ActionRowBuilder(rowWithButtonData).toJSON()).toEqual(rowWithButtonData);
expect(new ActionRowBuilder(rowWithSelectMenuData).toJSON()).toEqual(rowWithSelectMenuData);
expect(new ActionRowBuilder().toJSON()).toEqual({ type: ComponentType.ActionRow, components: [] });
expect(() => createComponentBuilder({ type: ComponentType.ActionRow, components: [] })).not.toThrowError();
});
test('GIVEN valid builder options THEN valid JSON output is given', () => {
const button = new ButtonBuilder().setLabel('test').setStyle(ButtonStyle.Primary).setCustomId('123');
const selectMenu = new SelectMenuBuilder()
.setCustomId('1234')
.setMaxValues(10)
.setMinValues(12)
.setOptions(
new SelectMenuOption().setLabel('one').setValue('one'),
new SelectMenuOption().setLabel('two').setValue('two'),
new SelectMenuOptionBuilder().setLabel('one').setValue('one'),
new SelectMenuOptionBuilder().setLabel('two').setValue('two'),
);

expect(new ActionRow().addComponents(button).toJSON()).toEqual(rowWithButtonData);
expect(new ActionRow().addComponents(selectMenu).toJSON()).toEqual(rowWithSelectMenuData);
});
test('Given JSON data THEN builder is equal to it and itself', () => {
expect(new ActionRow(rowWithSelectMenuData).equals(rowWithSelectMenuData)).toBeTruthy();
expect(new ActionRow(rowWithButtonData).equals(new ActionRow(rowWithButtonData))).toBeTruthy();
expect(new ActionRowBuilder().addComponents(button).toJSON()).toEqual(rowWithButtonData);
expect(new ActionRowBuilder().addComponents(selectMenu).toJSON()).toEqual(rowWithSelectMenuData);
});
});
});
20 changes: 4 additions & 16 deletions packages/builders/__tests__/components/button.test.ts
Expand Up @@ -5,9 +5,9 @@ import {
ComponentType,
} from 'discord-api-types/v9';
import { buttonLabelValidator, buttonStyleValidator } from '../../src/components/Assertions';
import { ButtonComponent } from '../../src/components/button/Button';
import { ButtonBuilder } from '../../src/components/button/Button';

const buttonComponent = () => new ButtonComponent();
const buttonComponent = () => new ButtonBuilder();

const longStr =
'looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong';
Expand Down Expand Up @@ -119,7 +119,7 @@ describe('Button Components', () => {
disabled: true,
};

expect(new ButtonComponent(interactionData).toJSON()).toEqual(interactionData);
expect(new ButtonBuilder(interactionData).toJSON()).toEqual(interactionData);

expect(
buttonComponent()
Expand All @@ -138,21 +138,9 @@ describe('Button Components', () => {
url: 'https://google.com',
};

expect(new ButtonComponent(linkData).toJSON()).toEqual(linkData);
expect(new ButtonBuilder(linkData).toJSON()).toEqual(linkData);

expect(buttonComponent().setLabel(linkData.label).setDisabled(true).setURL(linkData.url));
});
test('Given JSON data THEN builder is equal to it and itself', () => {
const buttonData: APIButtonComponentWithCustomId = {
type: ComponentType.Button,
custom_id: 'test',
label: 'test',
style: ButtonStyle.Primary,
disabled: true,
};

expect(new ButtonComponent(buttonData).equals(buttonData)).toBeTruthy();
expect(new ButtonComponent(buttonData).equals(new ButtonComponent(buttonData))).toBeTruthy();
});
});
});
21 changes: 8 additions & 13 deletions packages/builders/__tests__/components/selectMenu.test.ts
@@ -1,8 +1,8 @@
import { APISelectMenuComponent, APISelectMenuOption, ComponentType } from 'discord-api-types/v9';
import { SelectMenuComponent, SelectMenuOption } from '../../src/index';
import { SelectMenuBuilder, SelectMenuOptionBuilder } from '../../src/index';

const selectMenu = () => new SelectMenuComponent();
const selectMenuOption = () => new SelectMenuOption();
const selectMenu = () => new SelectMenuBuilder();
const selectMenuOption = () => new SelectMenuOptionBuilder();

const longStr = 'a'.repeat(256);

Expand Down Expand Up @@ -44,8 +44,8 @@ describe('Select Menu Components', () => {
.setEmoji({ name: 'test' })
.setDescription('description');
expect(() => selectMenu().addOptions(option)).not.toThrowError();
expect(() => selectMenu().setOptions([option])).not.toThrowError();
expect(() => selectMenu().setOptions([{ label: 'test', value: 'test' }])).not.toThrowError();
expect(() => selectMenu().setOptions(option)).not.toThrowError();
expect(() => selectMenu().setOptions({ label: 'test', value: 'test' })).not.toThrowError();
});

test('GIVEN invalid inputs THEN Select Menu does throw', () => {
Expand All @@ -70,16 +70,11 @@ describe('Select Menu Components', () => {

test('GIVEN valid JSON input THEN valid JSON history is correct', () => {
expect(
new SelectMenuComponent(selectMenuDataWithoutOptions)
.addOptions(new SelectMenuOption(selectMenuOptionData))
new SelectMenuBuilder(selectMenuDataWithoutOptions)
.addOptions(new SelectMenuOptionBuilder(selectMenuOptionData))
.toJSON(),
).toEqual(selectMenuData);
expect(new SelectMenuOption(selectMenuOptionData).toJSON()).toEqual(selectMenuOptionData);
});

test('Given JSON data THEN builder is equal to it and itself', () => {
expect(new SelectMenuComponent(selectMenuData).equals(selectMenuData)).toBeTruthy();
expect(new SelectMenuComponent(selectMenuData).equals(new SelectMenuComponent(selectMenuData))).toBeTruthy();
expect(new SelectMenuOptionBuilder(selectMenuOptionData).toJSON()).toEqual(selectMenuOptionData);
});
});
});
6 changes: 3 additions & 3 deletions packages/builders/__tests__/components/textInput.test.ts
Expand Up @@ -7,11 +7,11 @@ import {
valueValidator,
textInputStyleValidator,
} from '../../src/components/textInput/Assertions';
import { TextInputComponent } from '../../src/components/textInput/TextInput';
import { TextInputBuilder } from '../../src/components/textInput/TextInput';

const superLongStr = 'a'.repeat(5000);

const textInputComponent = () => new TextInputComponent();
const textInputComponent = () => new TextInputBuilder();

describe('Text Input Components', () => {
describe('Assertion Tests', () => {
Expand Down Expand Up @@ -109,7 +109,7 @@ describe('Text Input Components', () => {
style: TextInputStyle.Paragraph,
};

expect(new TextInputComponent(textInputData).toJSON()).toEqual(textInputData);
expect(new TextInputBuilder(textInputData).toJSON()).toEqual(textInputData);
expect(
textInputComponent()
.setCustomId(textInputData.custom_id)
Expand Down
32 changes: 21 additions & 11 deletions packages/builders/__tests__/interactions/modal.test.ts
@@ -1,12 +1,18 @@
import { APIModalInteractionResponseCallbackData, ComponentType, TextInputStyle } from 'discord-api-types/v9';
import { ActionRow, ButtonComponent, Modal, ModalActionRowComponent, TextInputComponent } from '../../src';
import {
ActionRowBuilder,
ButtonBuilder,
ModalBuilder,
ModalActionRowComponentBuilder,
TextInputBuilder,
} from '../../src';
import {
componentsValidator,
titleValidator,
validateRequiredParameters,
} from '../../src/interactions/modals/Assertions';

const modal = () => new Modal();
const modal = () => new ModalBuilder();

describe('Modals', () => {
describe('Assertion Tests', () => {
Expand All @@ -19,33 +25,37 @@ describe('Modals', () => {
});

test('GIVEN valid components THEN validator does not throw', () => {
expect(() => componentsValidator.parse([new ActionRow(), new ActionRow()])).not.toThrowError();
expect(() => componentsValidator.parse([new ActionRowBuilder(), new ActionRowBuilder()])).not.toThrowError();
});

test('GIVEN invalid components THEN validator does throw', () => {
expect(() => componentsValidator.parse([new ButtonComponent(), new TextInputComponent()])).toThrowError();
expect(() => componentsValidator.parse([new ButtonBuilder(), new TextInputBuilder()])).toThrowError();
});

test('GIVEN valid required parameters THEN validator does not throw', () => {
expect(() => validateRequiredParameters('123', 'title', [new ActionRow(), new ActionRow()])).not.toThrowError();
expect(() =>
validateRequiredParameters('123', 'title', [new ActionRowBuilder(), new ActionRowBuilder()]),
).not.toThrowError();
});

test('GIVEN invalid required parameters THEN validator does throw', () => {
expect(() =>
// @ts-expect-error
validateRequiredParameters('123', undefined, [new ActionRow(), new ButtonComponent()]),
validateRequiredParameters('123', undefined, [new ActionRowBuilder(), new ButtonBuilder()]),
).toThrowError();
});
});

test('GIVEN valid fields THEN builder does not throw', () => {
expect(() => modal().setTitle('test').setCustomId('foobar').setComponents(new ActionRow())).not.toThrowError();
expect(() =>
modal().setTitle('test').setCustomId('foobar').setComponents(new ActionRowBuilder()),
).not.toThrowError();
});

test('GIVEN invalid fields THEN builder does throw', () => {
expect(() =>
// @ts-expect-error
modal().setTitle('test').setCustomId('foobar').setComponents([new ActionRow()]).toJSON(),
modal().setTitle('test').setCustomId('foobar').setComponents([new ActionRowBuilder()]).toJSON(),
).toThrowError();
expect(() => modal().setTitle('test').setCustomId('foobar').toJSON()).toThrowError();
// @ts-expect-error
Expand All @@ -71,15 +81,15 @@ describe('Modals', () => {
],
};

expect(new Modal(modalData).toJSON()).toEqual(modalData);
expect(new ModalBuilder(modalData).toJSON()).toEqual(modalData);

expect(
modal()
.setTitle(modalData.title)
.setCustomId('custom id')
.setComponents(
new ActionRow<ModalActionRowComponent>().addComponents(
new TextInputComponent().setCustomId('custom id').setLabel('label').setStyle(TextInputStyle.Paragraph),
new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(
new TextInputBuilder().setCustomId('custom id').setLabel('label').setStyle(TextInputStyle.Paragraph),
),
)
.toJSON(),
Expand Down

0 comments on commit 549716e

Please sign in to comment.