Skip to content
Draft
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
ab0ac16
test(structures): add tests for Emoji and Entitlement
AsadHumayun Jan 26, 2026
9150192
test: address review feedback
AsadHumayun Jan 29, 2026
0076364
test(structures): add tests for AutoModeration structures
AsadHumayun Jan 29, 2026
796cc30
docs: remove qjuh ://
AsadHumayun Jan 29, 2026
3358806
test: remove duplicate test on Entitlement
AsadHumayun Jan 30, 2026
8cfd831
test(structures): add Webhook tests
AsadHumayun Feb 7, 2026
b490868
test(entitlement): cover end/start dates
AsadHumayun Feb 11, 2026
72e530d
test(structures): add tests for Embed substructures
AsadHumayun Feb 11, 2026
4070470
test(structures): test Poll and substructures
AsadHumayun Feb 11, 2026
d90aef7
fix: add `createdDate` and `createdTimestamp` to SKU struct
AsadHumayun Feb 11, 2026
594fd3e
test(structures): add tests for SKU structure
AsadHumayun Feb 11, 2026
fd322ea
fix(tests): test missed getters on webhook tests
AsadHumayun Feb 11, 2026
3e2d411
test(structures): add test skeletons for message component structures
AsadHumayun Feb 12, 2026
ce7288f
test(structures): add missed getters for testing
AsadHumayun Feb 12, 2026
066c274
chore: use `isFieldSet` on `ButtonComponent` for consistency
AsadHumayun Feb 12, 2026
a6e5c24
fix: export missing class not exported in lib
AsadHumayun Feb 12, 2026
40c8eb9
test(structures): add tests for message components
AsadHumayun Feb 12, 2026
a328ab4
chore: rename for consistency
AsadHumayun Feb 13, 2026
7298cdd
test(structures): add tests for `SoundboardSound` structure
AsadHumayun Feb 16, 2026
0966e7a
fix(structures): add missing `requestToSpeakAt` getter on `VoiceState`
AsadHumayun Feb 18, 2026
a3b18d9
Merge remote-tracking branch 'upstream/main' into feat/add-tests-seve…
AsadHumayun Feb 20, 2026
b40214a
Merge remote-tracking branch 'upstream/main' into feat/add-tests-seve…
AsadHumayun Feb 26, 2026
fc71f99
test: add tests for attachment tests
AsadHumayun Feb 26, 2026
84fb36b
test: rm unnecessary test
AsadHumayun Feb 26, 2026
6a6eb07
fix: failing ci
AsadHumayun Feb 26, 2026
ff425f1
chore: tidy up
AsadHumayun Feb 27, 2026
1b19c9c
test: add tests for remaining messages structures
AsadHumayun Feb 27, 2026
2e9c8fc
test(structures): add Stage Instance tests
AsadHumayun Feb 27, 2026
f9f1abd
test(structures): add tests for sticker structures
AsadHumayun Feb 27, 2026
f66b194
test(structures): add tests for Subscription
AsadHumayun Feb 27, 2026
c700ecb
test(structures): add Teams tests
AsadHumayun Feb 27, 2026
e3dc077
test(structures): add tests for User structures
AsadHumayun Feb 28, 2026
ebb37ab
test(structures): add tests for Voice structures
AsadHumayun Feb 28, 2026
130850e
ci: comment out bad test until toJSON is added in #11431
AsadHumayun Feb 28, 2026
fea8e7b
Merge remote-tracking branch 'upstream/main' into feat/add-tests-seve…
AsadHumayun Mar 3, 2026
822acd1
Revert "ci: comment out bad test until toJSON is added in #11431"
AsadHumayun Mar 3, 2026
c767a89
Merge remote-tracking branch 'upstream/main' into feat/add-tests-seve…
AsadHumayun Mar 6, 2026
edaa3ea
Merge remote-tracking branch 'upstream/main' into feat/add-tests-seve…
AsadHumayun Mar 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions packages/structures/__tests__/automoderation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import {
type APIAutoModerationAction,
type APIAutoModerationActionMetadata,
type APIAutoModerationRule,
type APIAutoModerationRuleTriggerMetadata,
AutoModerationActionType,
AutoModerationRuleEventType,
AutoModerationRuleTriggerType,
} from 'discord-api-types/v10';
import { describe, expect, test } from 'vitest';
import {
AutoModerationAction,
AutoModerationActionMetadata,
AutoModerationRule,
AutoModerationRuleTriggerMetadata,
} from '../src/automoderation/index.js';
import { kPatch } from '../src/utils/symbols';

const ruleTriggerMetadataData: APIAutoModerationRuleTriggerMetadata = {
mention_total_limit: 5,
};

const actionMetadataData: APIAutoModerationActionMetadata = {
channel_id: '1',
custom_message: 'go away.',
};

const actions: APIAutoModerationAction[] = [
{
type: AutoModerationActionType.BlockMessage,
metadata: actionMetadataData,
},
];

const ruleData: APIAutoModerationRule = {
id: '1',
guild_id: '2',
name: 'ruleName',
creator_id: '1',
event_type: AutoModerationRuleEventType.MessageSend,
trigger_metadata: ruleTriggerMetadataData,
trigger_type: AutoModerationRuleTriggerType.MentionSpam,
enabled: true,
actions,
exempt_channels: ['1'],
exempt_roles: [],
};

describe('AutoModerationRule structure', () => {
const instance = new AutoModerationRule(ruleData);
const data = ruleData;

test('correct value for all getters', () => {
expect(instance.id).toBe(data.id);
expect(instance.guildId).toBe(data.guild_id);
expect(instance.name).toBe(data.name);
expect(instance.creatorId).toBe(data.creator_id);
expect(instance.eventType).toBe(data.event_type);
expect(instance.enabled).toBe(data.enabled);
expect(instance.triggerType).toBe(data.trigger_type);
});

test('toJSON() correctly mirrors API data', () => {
expect(instance.toJSON()).toStrictEqual(data);
});

test('Patching the AutoModerationRule works in place', () => {
const patched = instance[kPatch]({
exempt_channels: ['2'],
exempt_roles: ['1', '2', '3'],
});

expect(patched.toJSON()).not.toEqual(data);
expect(instance.toJSON()).toEqual(patched.toJSON());
});

describe('AutoModerationRuleTriggerMetadata sub-structure', () => {
const instance = new AutoModerationRuleTriggerMetadata(ruleTriggerMetadataData);
const data = ruleTriggerMetadataData;

test('getters return correct values', () => {
expect(instance.allowList).toBe(data.allow_list);
expect(instance.keywordFilter).toBe(data.keyword_filter);
expect(instance.mentionRaidProtectionEnabled).toBe(data.mention_raid_protection_enabled);
expect(instance.mentionTotalLimit).toBe(data.mention_total_limit);
expect(instance.presets).toBe(data.presets);
expect(instance.regexPatterns).toBe(data.regex_patterns);
});

test('toJSON() returns expected API data', () => {
expect(instance.toJSON()).toStrictEqual(data);
});

test('patching the structure works in place', () => {
const patched = instance[kPatch]({
mention_total_limit: 10,
});

expect(patched.mentionTotalLimit).toBe(patched.mentionTotalLimit);

expect(patched.toJSON()).toEqual(instance.toJSON());
});
});

describe('AutoModerationAction structure', () => {
const instance = new AutoModerationAction(actions[0] as APIAutoModerationAction);
const data = actions[0];

test('correct value for all getters', () => {
expect(instance.type).toBe(data!.type);
});

test('toJSON() returns expected API data', () => {
expect(instance.toJSON()).toStrictEqual(data);
});

test('patching the structure works in place', () => {
const patched = instance[kPatch]({
type: AutoModerationActionType.Timeout,
});

expect(instance.type).toBe(patched.type);

expect(patched.toJSON()).toEqual(instance.toJSON());
});
});

describe('AutoModerationActionMetadata sub-structure', () => {
const instance = new AutoModerationActionMetadata(actionMetadataData);
const data = actionMetadataData;

test('all getters working as expected', () => {
expect(instance.channelId).toBe(data.channel_id);
expect(instance.customMessage).toBe(data.custom_message);
expect(instance.durationSeconds).toBe(data.duration_seconds);
});

test('toJSON() returns expected results', () => {
expect(instance.toJSON()).toStrictEqual(data);
});

test('patching the structure works in place', () => {
const patched = instance[kPatch]({
custom_message: 'noo come back',
duration_seconds: 100,
});

expect(patched.toJSON()).toStrictEqual(instance.toJSON());
expect(patched.customMessage).toBe(instance.customMessage);
expect(patched.durationSeconds).toBe(instance.durationSeconds);
});
});
});
3 changes: 3 additions & 0 deletions packages/structures/__tests__/channels.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DiscordSnowflake } from '@sapphire/snowflake';
import type {
APIAnnouncementThreadChannel,
APIDMChannel,
Expand Down Expand Up @@ -85,6 +86,8 @@ describe('text channel', () => {
expect(instance.topic).toBe(data.topic);
expect(instance.type).toBe(ChannelType.GuildText);
expect(instance.url).toBe('https://discord.com/channels/2/1');
expect(instance.createdTimestamp).toBe(DiscordSnowflake.timestampFrom(instance.id!));
expect(instance.createdAt).toEqual(new Date(instance.createdTimestamp!));
Comment on lines +89 to +90
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
expect(instance.createdTimestamp).toBe(DiscordSnowflake.timestampFrom(instance.id!));
expect(instance.createdAt).toEqual(new Date(instance.createdTimestamp!));
const createdTimestamp = DiscordSnowflake.timestampFrom(data.id!);
expect(instance.createdTimestamp).toBe(createdTimestamp);
expect(instance.createdDate.valueOf()).toBe(createdTimestamp);

expect(instance.toJSON()).toEqual(data);
});

Expand Down
55 changes: 55 additions & 0 deletions packages/structures/__tests__/emoji.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { DiscordSnowflake } from '@sapphire/snowflake';
import type { APIEmoji, APIUser } from 'discord-api-types/v10';
import { describe, expect, test } from 'vitest';
import { Emoji } from '../src/emojis/Emoji.js';
import { kPatch } from '../src/utils/symbols.js';

describe('Emoji structure', () => {
const user: APIUser = {
id: '1',
username: 'username',
discriminator: '0000',
global_name: 'djs.structures.user.global_name',
avatar: 'djs.structures.user.avatar',
};

const data: APIEmoji = {
id: '1',
name: 'name',
roles: ['1', '2', '3'],
user,
require_colons: true,
managed: true,
animated: true,
available: true,
};

const instance = new Emoji(data);

test('Emoji has all properties', () => {
expect(instance.id).toBe(data.id);
expect(instance.name).toBe(data.name);
expect(instance.requireColons).toBe(data.require_colons);
expect(instance.managed).toBe(data.managed);
expect(instance.animated).toBe(data.animated);
expect(instance.available).toBe(data.available);

expect(instance.createdTimestamp).toBe(DiscordSnowflake.timestampFrom(instance.id!));
expect(instance.createdAt).toEqual(new Date(instance.createdTimestamp!));
Comment on lines +37 to +38
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
expect(instance.createdTimestamp).toBe(DiscordSnowflake.timestampFrom(instance.id!));
expect(instance.createdAt).toEqual(new Date(instance.createdTimestamp!));
const createdTimestamp = DiscordSnowflake.timestampFrom(data.id!);
expect(instance.createdTimestamp).toBe(createdTimestamp);
expect(instance.createdDate.valueOf()).toBe(createdTimestamp);

});

test('toJSON() is accurate', () => {
expect(instance.toJSON()).toStrictEqual(data);
});

test('Patching the Emoji works in place', () => {
const patched = instance[kPatch]({
available: false,
});

expect(patched.available).toEqual(false);

expect(patched.toJSON()).not.toEqual(data);
expect(patched).toBe(instance);
});
});
62 changes: 62 additions & 0 deletions packages/structures/__tests__/entitlement.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { DiscordSnowflake } from '@sapphire/snowflake';
import { type APIEntitlement, EntitlementType } from 'discord-api-types/v10';
import { describe, expect, test } from 'vitest';
import { Entitlement } from '../src/entitlements/Entitlement.js';
import { kPatch } from '../src/utils/symbols.js';

describe('Entitlement structure', () => {
const data: APIEntitlement = {
id: '1',
sku_id: '1',
application_id: '1',
user_id: '1',
type: EntitlementType.Purchase,
deleted: false,
starts_at: '2020-10-10T13:50:17.209000+00:00',
ends_at: '2020-10-10T15:50:17.209000+00:00',
consumed: false,
// note guild_id is missing (to test kPatch)
};

const instance = new Entitlement(data);

test('Entitlement has all properties', () => {
expect(instance.id).toBe(data.id);
expect(instance.skuId).toBe(data.sku_id);
expect(instance.applicationId).toBe(data.application_id);
expect(instance.userId).toBe(data.user_id);
expect(instance.type).toBe(data.type);
expect(instance.consumed).toBe(data.consumed);
expect(instance.deleted).toBe(data.deleted);
expect(instance.guildId).toBeUndefined();

expect(instance.createdTimestamp).toBe(DiscordSnowflake.timestampFrom(instance.id!));
expect(instance.createdAt).toEqual(new Date(instance.createdTimestamp!));

expect(instance.startsTimestamp).toBe(new Date(data.starts_at!).getTime());
expect(instance.startsAt).toEqual(new Date(instance.startsTimestamp!));

expect(instance.endsTimestamp).toBe(new Date(data.ends_at!).getTime());
expect(instance.endsAt).toEqual(new Date(instance.endsTimestamp!));
Comment on lines +33 to +40
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
expect(instance.createdTimestamp).toBe(DiscordSnowflake.timestampFrom(instance.id!));
expect(instance.createdAt).toEqual(new Date(instance.createdTimestamp!));
expect(instance.startsTimestamp).toBe(new Date(data.starts_at!).getTime());
expect(instance.startsAt).toEqual(new Date(instance.startsTimestamp!));
expect(instance.endsTimestamp).toBe(new Date(data.ends_at!).getTime());
expect(instance.endsAt).toEqual(new Date(instance.endsTimestamp!));
const createdTimestamp = DiscordSnowflake.timestampFrom(instance.id!);
expect(instance.createdTimestamp).toBe(createdTimestamp);
expect(instance.createdAt.valueOf()).toBecreatedTimestamp);
const startsTimestamp = Date.parse(data.starts_at!);
expect(instance.startsTimestamp).toBe(startsTimestamp);
expect(instance.startsDate.valueOf()).toBe(startsTimestamp);
const endsTimestamp = Date.parse(data.ends_at!);
expect(instance.endsTimestamp).toBe(endsTimestamp);
expect(instance.endsDate.valueOf()).toBe(endsTimestamp);

});

test('toJSON() is accurate', () => {
expect(instance.toJSON()).toStrictEqual(data);
});

test('Patching the Entitlement works in place', () => {
const guildId = '111111';
const consumed = true;

const patched = instance[kPatch]({
guild_id: guildId,
consumed,
});

expect(patched.guildId).toEqual(guildId);
expect(patched.consumed).toEqual(consumed);

expect(patched.toJSON()).not.toEqual(data);
expect(patched).toBe(instance);
});
});
Loading