-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add Modals and Text Inputs (#7023)
Co-authored-by: Vlad Frangu <[email protected]> Co-authored-by: Jiralite <[email protected]> Co-authored-by: Ryan Munro <[email protected]> Co-authored-by: Vitor <[email protected]>
- Loading branch information
1 parent
53defb8
commit ed92015
Showing
31 changed files
with
1,075 additions
and
115 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
126 changes: 126 additions & 0 deletions
126
packages/builders/__tests__/components/textInput.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import { APITextInputComponent, ComponentType, TextInputStyle } from 'discord-api-types/v9'; | ||
import { | ||
labelValidator, | ||
maxLengthValidator, | ||
minLengthValidator, | ||
placeholderValidator, | ||
valueValidator, | ||
textInputStyleValidator, | ||
} from '../../src/components/textInput/Assertions'; | ||
import { TextInputComponent } from '../../src/components/textInput/TextInput'; | ||
|
||
const superLongStr = 'a'.repeat(5000); | ||
|
||
const textInputComponent = () => new TextInputComponent(); | ||
|
||
describe('Text Input Components', () => { | ||
describe('Assertion Tests', () => { | ||
test('GIVEN valid label THEN validator does not throw', () => { | ||
expect(() => labelValidator.parse('foobar')).not.toThrowError(); | ||
}); | ||
|
||
test('GIVEN invalid label THEN validator does throw', () => { | ||
expect(() => labelValidator.parse(24)).toThrowError(); | ||
expect(() => labelValidator.parse(undefined)).toThrowError(); | ||
}); | ||
|
||
test('GIVEN valid style THEN validator does not throw', () => { | ||
expect(() => textInputStyleValidator.parse(TextInputStyle.Paragraph)).not.toThrowError(); | ||
expect(() => textInputStyleValidator.parse(TextInputStyle.Short)).not.toThrowError(); | ||
}); | ||
|
||
test('GIVEN invalid style THEN validator does throw', () => { | ||
expect(() => textInputStyleValidator.parse(24)).toThrowError(); | ||
}); | ||
|
||
test('GIVEN valid min length THEN validator does not throw', () => { | ||
expect(() => minLengthValidator.parse(10)).not.toThrowError(); | ||
}); | ||
|
||
test('GIVEN invalid min length THEN validator does throw', () => { | ||
expect(() => minLengthValidator.parse(-1)).toThrowError(); | ||
}); | ||
|
||
test('GIVEN valid max length THEN validator does not throw', () => { | ||
expect(() => maxLengthValidator.parse(10)).not.toThrowError(); | ||
}); | ||
|
||
test('GIVEN invalid min length THEN validator does throw', () => { | ||
expect(() => maxLengthValidator.parse(4001)).toThrowError(); | ||
}); | ||
|
||
test('GIVEN valid value THEN validator does not throw', () => { | ||
expect(() => valueValidator.parse('foobar')).not.toThrowError(); | ||
}); | ||
|
||
test('GIVEN invalid value THEN validator does throw', () => { | ||
expect(() => valueValidator.parse(superLongStr)).toThrowError(); | ||
}); | ||
|
||
test('GIVEN valid placeholder THEN validator does not throw', () => { | ||
expect(() => placeholderValidator.parse('foobar')).not.toThrowError(); | ||
}); | ||
|
||
test('GIVEN invalid value THEN validator does throw', () => { | ||
expect(() => placeholderValidator.parse(superLongStr)).toThrowError(); | ||
}); | ||
|
||
test('GIVEN valid fields THEN builder does not throw', () => { | ||
expect(() => { | ||
textInputComponent().setCustomId('foobar').setLabel('test').setStyle(TextInputStyle.Paragraph).toJSON(); | ||
}).not.toThrowError(); | ||
|
||
expect(() => { | ||
textInputComponent() | ||
.setCustomId('foobar') | ||
.setLabel('test') | ||
.setMaxLength(100) | ||
.setMinLength(1) | ||
.setPlaceholder('bar') | ||
.setRequired(true) | ||
.setStyle(TextInputStyle.Paragraph) | ||
.toJSON(); | ||
}).not.toThrowError(); | ||
}); | ||
}); | ||
|
||
test('GIVEN invalid fields THEN builder throws', () => { | ||
expect(() => textInputComponent().toJSON()).toThrowError(); | ||
expect(() => { | ||
textInputComponent() | ||
.setCustomId('test') | ||
.setMaxLength(100) | ||
.setPlaceholder('hello') | ||
.setStyle(TextInputStyle.Paragraph) | ||
.toJSON(); | ||
}).toThrowError(); | ||
}); | ||
|
||
test('GIVEN valid input THEN valid JSON outputs are given', () => { | ||
const textInputData: APITextInputComponent = { | ||
type: ComponentType.TextInput, | ||
label: 'label', | ||
custom_id: 'custom id', | ||
placeholder: 'placeholder', | ||
max_length: 100, | ||
min_length: 10, | ||
value: 'value', | ||
required: false, | ||
style: TextInputStyle.Paragraph, | ||
}; | ||
|
||
expect(new TextInputComponent(textInputData).toJSON()).toEqual(textInputData); | ||
expect( | ||
textInputComponent() | ||
.setCustomId(textInputData.custom_id) | ||
.setLabel(textInputData.label) | ||
.setPlaceholder(textInputData.placeholder) | ||
.setMaxLength(textInputData.max_length) | ||
.setMinLength(textInputData.min_length) | ||
.setValue(textInputData.value) | ||
.setRequired(textInputData.required) | ||
.setStyle(textInputData.style) | ||
.toJSON(), | ||
).toEqual(textInputData); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { APIModalInteractionResponseCallbackData, ComponentType, TextInputStyle } from 'discord-api-types/v9'; | ||
import { ActionRow, ButtonComponent, Modal, ModalActionRowComponent, TextInputComponent } from '../../src'; | ||
import { | ||
componentsValidator, | ||
titleValidator, | ||
validateRequiredParameters, | ||
} from '../../src/interactions/modals/Assertions'; | ||
|
||
const modal = () => new Modal(); | ||
|
||
describe('Modals', () => { | ||
describe('Assertion Tests', () => { | ||
test('GIVEN valid title THEN validator does not throw', () => { | ||
expect(() => titleValidator.parse('foobar')).not.toThrowError(); | ||
}); | ||
|
||
test('GIVEN invalid title THEN validator does throw', () => { | ||
expect(() => titleValidator.parse(42)).toThrowError(); | ||
}); | ||
|
||
test('GIVEN valid components THEN validator does not throw', () => { | ||
expect(() => componentsValidator.parse([new ActionRow(), new ActionRow()])).not.toThrowError(); | ||
}); | ||
|
||
test('GIVEN invalid components THEN validator does throw', () => { | ||
expect(() => componentsValidator.parse([new ButtonComponent(), new TextInputComponent()])).toThrowError(); | ||
}); | ||
|
||
test('GIVEN valid required parameters THEN validator does not throw', () => { | ||
expect(() => validateRequiredParameters('123', 'title', [new ActionRow(), new ActionRow()])).not.toThrowError(); | ||
}); | ||
|
||
test('GIVEN invalid required parameters THEN validator does throw', () => { | ||
expect(() => | ||
// @ts-expect-error | ||
validateRequiredParameters('123', undefined, [new ActionRow(), new ButtonComponent()]), | ||
).toThrowError(); | ||
}); | ||
}); | ||
|
||
test('GIVEN valid fields THEN builder does not throw', () => { | ||
expect(() => modal().setTitle('test').setCustomId('foobar').setComponents(new ActionRow())).not.toThrowError(); | ||
}); | ||
|
||
test('GIVEN invalid fields THEN builder does throw', () => { | ||
expect(() => | ||
// @ts-expect-error | ||
modal().setTitle('test').setCustomId('foobar').setComponents([new ActionRow()]).toJSON(), | ||
).toThrowError(); | ||
expect(() => modal().setTitle('test').setCustomId('foobar').toJSON()).toThrowError(); | ||
// @ts-expect-error | ||
expect(() => modal().setTitle('test').setCustomId(42).toJSON()).toThrowError(); | ||
}); | ||
|
||
test('GIVEN valid input THEN valid JSON outputs are given', () => { | ||
const modalData: APIModalInteractionResponseCallbackData = { | ||
title: 'title', | ||
custom_id: 'custom id', | ||
components: [ | ||
{ | ||
type: ComponentType.ActionRow, | ||
components: [ | ||
{ | ||
type: ComponentType.TextInput, | ||
label: 'label', | ||
style: TextInputStyle.Paragraph, | ||
custom_id: 'custom id', | ||
}, | ||
], | ||
}, | ||
], | ||
}; | ||
|
||
expect(new Modal(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), | ||
), | ||
) | ||
.toJSON(), | ||
).toEqual(modalData); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.