Skip to content

Commit

Permalink
refactor: builders
Browse files Browse the repository at this point in the history
Co-authored-by: Vlad Frangu <[email protected]>
Co-authored-by: Almeida <[email protected]>
  • Loading branch information
3 people committed Sep 23, 2024
1 parent 8a74f14 commit 680cc5f
Show file tree
Hide file tree
Showing 91 changed files with 3,724 additions and 3,891 deletions.
72 changes: 41 additions & 31 deletions packages/builders/__tests__/components/actionRow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
ActionRowBuilder,
ButtonBuilder,
createComponentBuilder,
CustomIdButtonBuilder,
StringSelectMenuBuilder,
StringSelectMenuOptionBuilder,
} from '../../src/index.js';
Expand Down Expand Up @@ -41,21 +42,14 @@ const rowWithSelectMenuData: APIActionRowComponent<APIMessageActionRowComponent>
value: 'two',
},
],
max_values: 10,
min_values: 12,
max_values: 2,
min_values: 2,
},
],
};

describe('Action Row Components', () => {
describe('Assertion Tests', () => {
test('GIVEN valid components THEN do not throw', () => {
expect(() => new ActionRowBuilder().addComponents(new ButtonBuilder())).not.toThrowError();
expect(() => new ActionRowBuilder().setComponents(new ButtonBuilder())).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', () => {
const actionRowData: APIActionRowComponent<APIMessageActionRowComponent> = {
type: ComponentType.ActionRow,
Expand All @@ -72,22 +66,10 @@ describe('Action Row Components', () => {
style: ButtonStyle.Link,
url: 'https://google.com',
},
{
type: ComponentType.StringSelect,
placeholder: 'test',
custom_id: 'test',
options: [
{
label: 'option',
value: 'option',
},
],
},
],
};

expect(new ActionRowBuilder(actionRowData).toJSON()).toEqual(actionRowData);
expect(new ActionRowBuilder().toJSON()).toEqual({ type: ComponentType.ActionRow, components: [] });
expect(() => createComponentBuilder({ type: ComponentType.ActionRow, components: [] })).not.toThrowError();
});

Expand Down Expand Up @@ -120,24 +102,23 @@ describe('Action Row Components', () => {
value: 'two',
},
],
max_values: 10,
min_values: 12,
max_values: 1,
min_values: 1,
},
],
};

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 2', () => {
const button = new ButtonBuilder().setLabel('test').setStyle(ButtonStyle.Primary).setCustomId('123');
const button = new CustomIdButtonBuilder().setLabel('test').setStyle(ButtonStyle.Primary).setCustomId('123');
const selectMenu = new StringSelectMenuBuilder()
.setCustomId('1234')
.setMaxValues(10)
.setMinValues(12)
.setMaxValues(2)
.setMinValues(2)
.setOptions(
new StringSelectMenuOptionBuilder().setLabel('one').setValue('one'),
new StringSelectMenuOptionBuilder().setLabel('two').setValue('two'),
Expand All @@ -147,10 +128,39 @@ describe('Action Row Components', () => {
new StringSelectMenuOptionBuilder().setLabel('two').setValue('two'),
]);

expect(new ActionRowBuilder().addComponents(button).toJSON()).toEqual(rowWithButtonData);
expect(new ActionRowBuilder().addComponents(selectMenu).toJSON()).toEqual(rowWithSelectMenuData);
expect(new ActionRowBuilder().addComponents([button]).toJSON()).toEqual(rowWithButtonData);
expect(new ActionRowBuilder().addComponents([selectMenu]).toJSON()).toEqual(rowWithSelectMenuData);
expect(new ActionRowBuilder().addCustomIdButtonComponents(button).toJSON()).toEqual(rowWithButtonData);
expect(new ActionRowBuilder().addStringSelectMenuComponent(selectMenu).toJSON()).toEqual(rowWithSelectMenuData);
expect(new ActionRowBuilder().addCustomIdButtonComponents([button]).toJSON()).toEqual(rowWithButtonData);
});

test('GIVEN 2 select menus THEN it throws', () => {
const selectMenu = new StringSelectMenuBuilder()
.setCustomId('1234')
.setOptions(
new StringSelectMenuOptionBuilder().setLabel('one').setValue('one'),
new StringSelectMenuOptionBuilder().setLabel('two').setValue('two'),
);

expect(() =>
new ActionRowBuilder()
.addStringSelectMenuComponent(selectMenu)
.addStringSelectMenuComponent(selectMenu)
.toJSON(),
).toThrowError();
});

test('GIVEN a button and a select menu THEN it throws', () => {
const button = new CustomIdButtonBuilder().setLabel('test').setStyle(ButtonStyle.Primary).setCustomId('123');
const selectMenu = new StringSelectMenuBuilder()
.setCustomId('1234')
.setOptions(
new StringSelectMenuOptionBuilder().setLabel('one').setValue('one'),
new StringSelectMenuOptionBuilder().setLabel('two').setValue('two'),
);

expect(() =>
new ActionRowBuilder().addStringSelectMenuComponent(selectMenu).addCustomIdButtonComponents(button).toJSON(),
).toThrowError();
});
});
});
127 changes: 17 additions & 110 deletions packages/builders/__tests__/components/button.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,23 @@ import {
type APIButtonComponentWithURL,
} from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import { buttonLabelValidator, buttonStyleValidator } from '../../src/components/Assertions.js';
import { ButtonBuilder } from '../../src/components/button/Button.js';

const buttonComponent = () => new ButtonBuilder();
import { CustomIdButtonBuilder, SKUIdButtonBuilder, URLButtonBuilder } from '../../src/index.js';

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 throw', () => {
expect(() => buttonStyleValidator.parse(7)).toThrowError();
});

test('GIVEN valid fields THEN builder does not throw', () => {
expect(() =>
buttonComponent().setCustomId('custom').setStyle(ButtonStyle.Primary).setLabel('test'),
new CustomIdButtonBuilder().setCustomId('custom').setStyle(ButtonStyle.Primary).setLabel('test'),
).not.toThrowError();

expect(() => {
const button = buttonComponent()
const button = new CustomIdButtonBuilder()
.setCustomId('custom')
.setLabel('test')
.setStyle(ButtonStyle.Primary)
.setDisabled(true)
.setEmoji({ name: 'test' });
Expand All @@ -51,111 +30,41 @@ describe('Button Components', () => {
}).not.toThrowError();

expect(() => {
const button = buttonComponent().setSKUId('123456789012345678').setStyle(ButtonStyle.Premium);
const button = new SKUIdButtonBuilder().setSKUId('123456789012345678');
button.toJSON();
}).not.toThrowError();

expect(() => buttonComponent().setURL('https://google.com')).not.toThrowError();
expect(() => new URLButtonBuilder().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();
new CustomIdButtonBuilder().setCustomId(longStr).toJSON();
}).toThrowError();

expect(() => {
// @ts-expect-error: Invalid emoji
const button = buttonComponent().setEmoji('test');
const button = new CustomIdButtonBuilder().setEmoji('test');
button.toJSON();
}).toThrowError();

expect(() => {
const button = buttonComponent().setStyle(ButtonStyle.Primary);
const button = new CustomIdButtonBuilder().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(() => {
const button = buttonComponent().setStyle(ButtonStyle.Primary).setSKUId('123456789012345678');
button.toJSON();
}).toThrowError();

expect(() => {
const button = buttonComponent()
.setStyle(ButtonStyle.Secondary)
.setLabel('button')
.setSKUId('123456789012345678');

button.toJSON();
}).toThrowError();

expect(() => {
const button = buttonComponent()
.setStyle(ButtonStyle.Success)
.setEmoji({ name: '😇' })
.setSKUId('123456789012345678');

button.toJSON();
}).toThrowError();

expect(() => {
const button = buttonComponent()
.setStyle(ButtonStyle.Danger)
.setCustomId('test')
.setSKUId('123456789012345678');

button.toJSON();
}).toThrowError();

expect(() => {
const button = buttonComponent()
.setStyle(ButtonStyle.Link)
.setURL('https://google.com')
.setSKUId('123456789012345678');

const button = new CustomIdButtonBuilder().setStyle(ButtonStyle.Primary).setCustomId('test');
button.toJSON();
}).toThrowError();

// @ts-expect-error: Invalid style
expect(() => buttonComponent().setStyle(24)).toThrowError();
expect(() => buttonComponent().setLabel(longStr)).toThrowError();
expect(() => new CustomIdButtonBuilder().setCustomId('hi').setStyle(24).toJSON()).toThrowError();
expect(() => new CustomIdButtonBuilder().setCustomId('hi').setLabel(longStr).toJSON()).toThrowError();
// @ts-expect-error: Invalid parameter for disabled
expect(() => buttonComponent().setDisabled(0)).toThrowError();
expect(() => new CustomIdButtonBuilder().setCustomId('hi').setDisabled(0).toJSON()).toThrowError();
// @ts-expect-error: Invalid emoji
expect(() => buttonComponent().setEmoji('foo')).toThrowError();

expect(() => buttonComponent().setURL('foobar')).toThrowError();
expect(() => new CustomIdButtonBuilder().setCustomId('hi').setEmoji('foo').toJSON()).toThrowError();
});

test('GiVEN valid input THEN valid JSON outputs are given', () => {
Expand All @@ -167,10 +76,10 @@ describe('Button Components', () => {
disabled: true,
};

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

expect(
buttonComponent()
new CustomIdButtonBuilder()
.setCustomId(interactionData.custom_id)
.setLabel(interactionData.label!)
.setStyle(interactionData.style)
Expand All @@ -186,9 +95,7 @@ describe('Button Components', () => {
url: 'https://google.com',
};

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

expect(buttonComponent().setLabel(linkData.label!).setDisabled(true).setURL(linkData.url));
expect(new URLButtonBuilder(linkData).toJSON()).toEqual(linkData);
});
});
});
6 changes: 3 additions & 3 deletions packages/builders/__tests__/components/components.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import {
import { describe, test, expect } from 'vitest';
import {
ActionRowBuilder,
ButtonBuilder,
createComponentBuilder,
CustomIdButtonBuilder,
StringSelectMenuBuilder,
TextInputBuilder,
} from '../../src/index.js';

describe('createComponentBuilder', () => {
test.each([ButtonBuilder, StringSelectMenuBuilder, TextInputBuilder])(
test.each([StringSelectMenuBuilder, TextInputBuilder])(
'passing an instance of %j should return itself',
(Builder) => {
const builder = new Builder();
Expand All @@ -42,7 +42,7 @@ describe('createComponentBuilder', () => {
type: ComponentType.Button,
};

expect(createComponentBuilder(button)).toBeInstanceOf(ButtonBuilder);
expect(createComponentBuilder(button)).toBeInstanceOf(CustomIdButtonBuilder);
});

test('GIVEN a select menu component THEN returns a StringSelectMenuBuilder', () => {
Expand Down
Loading

0 comments on commit 680cc5f

Please sign in to comment.