throw together some scuffed integration testing infra
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
"lint": "eslint --ext js,ts,tsx .",
|
"lint": "eslint --ext js,ts,tsx .",
|
||||||
"lint-fix": "pnpm lint -- --fix",
|
"lint-fix": "pnpm lint -- --fix",
|
||||||
"test": "vitest --coverage --no-watch",
|
"test": "vitest --coverage --no-watch",
|
||||||
"test-dev": "vitest",
|
"test-dev": "vitest --ui",
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
"build": "pnpm -r run build",
|
"build": "pnpm -r run build",
|
||||||
"start": "pnpm -C packages/website run start",
|
"start": "pnpm -C packages/website run start",
|
||||||
@@ -16,11 +16,12 @@
|
|||||||
"@itsmapleleaf/configs": "^1.1.5",
|
"@itsmapleleaf/configs": "^1.1.5",
|
||||||
"@rushstack/eslint-patch": "^1.1.4",
|
"@rushstack/eslint-patch": "^1.1.4",
|
||||||
"@types/eslint": "^8.4.5",
|
"@types/eslint": "^8.4.5",
|
||||||
|
"@vitest/ui": "^0.21.0",
|
||||||
|
"c8": "^7.12.0",
|
||||||
"eslint": "^8.20.0",
|
"eslint": "^8.20.0",
|
||||||
"node": "^16.16.0",
|
"node": "^16.16.0",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"typescript": "^4.7.4",
|
"typescript": "^4.7.4",
|
||||||
"c8": "^7.12.0",
|
|
||||||
"vitest": "^0.20.3"
|
"vitest": "^0.20.3"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
|||||||
@@ -74,6 +74,7 @@
|
|||||||
"@reacord/helpers": "workspace:*",
|
"@reacord/helpers": "workspace:*",
|
||||||
"@types/lodash-es": "^4.17.6",
|
"@types/lodash-es": "^4.17.6",
|
||||||
"@types/prettier": "^2.6.4",
|
"@types/prettier": "^2.6.4",
|
||||||
|
"date-fns": "^2.29.1",
|
||||||
"discord.js": "^14.1.2",
|
"discord.js": "^14.1.2",
|
||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.0.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
|||||||
@@ -1,60 +1,17 @@
|
|||||||
import { raise } from "@reacord/helpers/raise"
|
import { ComponentType } from "discord.js"
|
||||||
import type { TextBasedChannel } from "discord.js"
|
|
||||||
import {
|
|
||||||
CategoryChannel,
|
|
||||||
ChannelType,
|
|
||||||
ComponentType,
|
|
||||||
GatewayIntentBits,
|
|
||||||
} from "discord.js"
|
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { beforeAll, expect, test } from "vitest"
|
import { beforeAll, expect, test } from "vitest"
|
||||||
import { createDiscordClient } from "../library/create-discord-client"
|
import { ActionRow, Button, Option, Select } from "../library/main"
|
||||||
import {
|
import { ReacordTester } from "./tester"
|
||||||
ActionRow,
|
|
||||||
Button,
|
|
||||||
Option,
|
|
||||||
ReacordClient,
|
|
||||||
Select,
|
|
||||||
} from "../library/main"
|
|
||||||
import { testEnv } from "./test-env"
|
|
||||||
|
|
||||||
let channel: TextBasedChannel
|
let tester: ReacordTester
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const client = await createDiscordClient(testEnv.TEST_BOT_TOKEN, {
|
tester = await ReacordTester.create()
|
||||||
intents: GatewayIntentBits.Guilds | GatewayIntentBits.GuildMessages,
|
|
||||||
})
|
|
||||||
|
|
||||||
const category =
|
|
||||||
client.channels.cache.get(testEnv.TEST_CATEGORY_ID) ??
|
|
||||||
(await client.channels.fetch(testEnv.TEST_CATEGORY_ID))
|
|
||||||
|
|
||||||
if (!(category instanceof CategoryChannel)) {
|
|
||||||
throw new TypeError("Category channel not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
const channelName = "test-channel"
|
|
||||||
|
|
||||||
let existing = category.children.cache.find((the) => the.name === channelName)
|
|
||||||
if (!existing || !existing.isTextBased()) {
|
|
||||||
existing = await category.children.create({
|
|
||||||
type: ChannelType.GuildText,
|
|
||||||
name: channelName,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
channel = existing
|
|
||||||
|
|
||||||
for (const [, message] of await channel.messages.fetch()) {
|
|
||||||
await message.delete()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test("action row", async () => {
|
test("action row", async () => {
|
||||||
const reacord = new ReacordClient({
|
const { message } = await tester.render(
|
||||||
token: testEnv.TEST_BOT_TOKEN,
|
"action row",
|
||||||
})
|
|
||||||
|
|
||||||
reacord.send(
|
|
||||||
channel.id,
|
|
||||||
<>
|
<>
|
||||||
<Button label="outside button" onClick={() => {}} />
|
<Button label="outside button" onClick={() => {}} />
|
||||||
<ActionRow>
|
<ActionRow>
|
||||||
@@ -68,10 +25,6 @@ test("action row", async () => {
|
|||||||
</>,
|
</>,
|
||||||
)
|
)
|
||||||
|
|
||||||
const message = await channel
|
|
||||||
.awaitMessages({ max: 1 })
|
|
||||||
.then((result) => result.first() ?? raise("message not found"))
|
|
||||||
|
|
||||||
expect(message.components.map((c) => c.toJSON())).toEqual([
|
expect(message.components.map((c) => c.toJSON())).toEqual([
|
||||||
{
|
{
|
||||||
type: ComponentType.ActionRow,
|
type: ComponentType.ActionRow,
|
||||||
@@ -109,4 +62,4 @@ test("action row", async () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
}, 15_000)
|
})
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import { test } from "vitest"
|
import { beforeAll, expect, test } from "vitest"
|
||||||
import {
|
import {
|
||||||
Embed,
|
Embed,
|
||||||
EmbedAuthor,
|
EmbedAuthor,
|
||||||
@@ -9,14 +9,18 @@ import {
|
|||||||
EmbedThumbnail,
|
EmbedThumbnail,
|
||||||
EmbedTitle,
|
EmbedTitle,
|
||||||
} from "../library/main"
|
} from "../library/main"
|
||||||
import { ReacordTester } from "./test-adapter"
|
import { ReacordTester } from "./tester"
|
||||||
|
|
||||||
const testing = new ReacordTester()
|
let tester: ReacordTester
|
||||||
|
beforeAll(async () => {
|
||||||
|
tester = await ReacordTester.create()
|
||||||
|
})
|
||||||
|
|
||||||
test("kitchen sink", async () => {
|
test("kitchen sink", async () => {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
|
|
||||||
await testing.assertRender(
|
const { message } = await tester.render(
|
||||||
|
"kitchen sink",
|
||||||
<>
|
<>
|
||||||
<Embed color={0xfe_ee_ef}>
|
<Embed color={0xfe_ee_ef}>
|
||||||
<EmbedAuthor name="author" iconUrl="https://example.com/author.png" />
|
<EmbedAuthor name="author" iconUrl="https://example.com/author.png" />
|
||||||
@@ -33,85 +37,83 @@ test("kitchen sink", async () => {
|
|||||||
/>
|
/>
|
||||||
</Embed>
|
</Embed>
|
||||||
</>,
|
</>,
|
||||||
[
|
|
||||||
{
|
|
||||||
actionRows: [],
|
|
||||||
content: "",
|
|
||||||
embeds: [
|
|
||||||
{
|
|
||||||
description: "description text",
|
|
||||||
author: {
|
|
||||||
icon_url: "https://example.com/author.png",
|
|
||||||
name: "author",
|
|
||||||
},
|
|
||||||
color: 0xfe_ee_ef,
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
inline: true,
|
|
||||||
name: "field name",
|
|
||||||
value: "field value",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "block field",
|
|
||||||
value: "block field value",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
footer: {
|
|
||||||
icon_url: "https://example.com/footer.png",
|
|
||||||
text: "footer text",
|
|
||||||
},
|
|
||||||
image: {
|
|
||||||
url: "https://example.com/image.png",
|
|
||||||
},
|
|
||||||
thumbnail: {
|
|
||||||
url: "https://example.com/thumbnail.png",
|
|
||||||
},
|
|
||||||
timestamp: now.toISOString(),
|
|
||||||
title: "title text",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
expect(message.embeds.map((e) => e.toJSON())).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
description: "description text",
|
||||||
|
author: expect.objectContaining({
|
||||||
|
icon_url: "https://example.com/author.png",
|
||||||
|
name: "author",
|
||||||
|
}),
|
||||||
|
color: 0xfe_ee_ef,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
inline: true,
|
||||||
|
name: "field name",
|
||||||
|
value: "field value",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
inline: false,
|
||||||
|
name: "block field",
|
||||||
|
value: "block field value",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
footer: expect.objectContaining({
|
||||||
|
icon_url: "https://example.com/footer.png",
|
||||||
|
text: "footer text",
|
||||||
|
}),
|
||||||
|
image: expect.objectContaining({
|
||||||
|
url: "https://example.com/image.png",
|
||||||
|
}),
|
||||||
|
thumbnail: expect.objectContaining({
|
||||||
|
url: "https://example.com/thumbnail.png",
|
||||||
|
}),
|
||||||
|
title: "title text",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
// the timestamp format from Discord is not the same one that JS makes
|
||||||
|
expect(new Date(message.embeds[0]!.timestamp!)).toEqual(now)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("author variants", async () => {
|
test("author variants", async () => {
|
||||||
await testing.assertRender(
|
const { message } = await tester.render(
|
||||||
|
"author variants",
|
||||||
<>
|
<>
|
||||||
<Embed>
|
<Embed>
|
||||||
<EmbedAuthor iconUrl="https://example.com/author.png">
|
<EmbedAuthor iconUrl="https://example.com/author.png">
|
||||||
author name
|
author name 1
|
||||||
</EmbedAuthor>
|
</EmbedAuthor>
|
||||||
</Embed>
|
</Embed>
|
||||||
<Embed>
|
<Embed>
|
||||||
<EmbedAuthor iconUrl="https://example.com/author.png" />
|
<EmbedAuthor
|
||||||
|
name="author name 2"
|
||||||
|
iconUrl="https://example.com/author.png"
|
||||||
|
/>
|
||||||
</Embed>
|
</Embed>
|
||||||
</>,
|
</>,
|
||||||
[
|
|
||||||
{
|
|
||||||
content: "",
|
|
||||||
actionRows: [],
|
|
||||||
embeds: [
|
|
||||||
{
|
|
||||||
author: {
|
|
||||||
icon_url: "https://example.com/author.png",
|
|
||||||
name: "author name",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
author: {
|
|
||||||
icon_url: "https://example.com/author.png",
|
|
||||||
name: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
})
|
|
||||||
|
expect(message.embeds.map((e) => e.toJSON())).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
author: expect.objectContaining({
|
||||||
|
name: "author name 1",
|
||||||
|
icon_url: "https://example.com/author.png",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
author: expect.objectContaining({
|
||||||
|
name: "author name 2",
|
||||||
|
icon_url: "https://example.com/author.png",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
}, 20_000)
|
||||||
|
|
||||||
test("field variants", async () => {
|
test("field variants", async () => {
|
||||||
await testing.assertRender(
|
const { message } = await tester.render(
|
||||||
|
"field variants",
|
||||||
<>
|
<>
|
||||||
<Embed>
|
<Embed>
|
||||||
<EmbedField name="field name" value="field value" />
|
<EmbedField name="field name" value="field value" />
|
||||||
@@ -122,43 +124,41 @@ test("field variants", async () => {
|
|||||||
<EmbedField name="field name" />
|
<EmbedField name="field name" />
|
||||||
</Embed>
|
</Embed>
|
||||||
</>,
|
</>,
|
||||||
[
|
|
||||||
{
|
|
||||||
content: "",
|
|
||||||
actionRows: [],
|
|
||||||
embeds: [
|
|
||||||
{
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: "field name",
|
|
||||||
value: "field value",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
inline: true,
|
|
||||||
name: "field name",
|
|
||||||
value: "field value",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
inline: true,
|
|
||||||
name: "field name",
|
|
||||||
value: "field value",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "field name",
|
|
||||||
value: "",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
expect(message.embeds.map((e) => e.toJSON())).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "field name",
|
||||||
|
value: "field value",
|
||||||
|
inline: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "field name",
|
||||||
|
value: "field value",
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "field name",
|
||||||
|
value: "field value",
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "field name",
|
||||||
|
value: "_ _",
|
||||||
|
inline: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
test("footer variants", async () => {
|
test("footer variants", async () => {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
|
|
||||||
await testing.assertRender(
|
const { message } = await tester.render(
|
||||||
|
"footer variants",
|
||||||
<>
|
<>
|
||||||
<Embed>
|
<Embed>
|
||||||
<EmbedFooter text="footer text" />
|
<EmbedFooter text="footer text" />
|
||||||
@@ -176,45 +176,37 @@ test("footer variants", async () => {
|
|||||||
<EmbedFooter iconUrl="https://example.com/footer.png" timestamp={now} />
|
<EmbedFooter iconUrl="https://example.com/footer.png" timestamp={now} />
|
||||||
</Embed>
|
</Embed>
|
||||||
</>,
|
</>,
|
||||||
[
|
|
||||||
{
|
|
||||||
content: "",
|
|
||||||
actionRows: [],
|
|
||||||
embeds: [
|
|
||||||
{
|
|
||||||
footer: {
|
|
||||||
text: "footer text",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
footer: {
|
|
||||||
icon_url: "https://example.com/footer.png",
|
|
||||||
text: "footer text",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
footer: {
|
|
||||||
text: "footer text",
|
|
||||||
},
|
|
||||||
timestamp: now.toISOString(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
footer: {
|
|
||||||
icon_url: "https://example.com/footer.png",
|
|
||||||
text: "",
|
|
||||||
},
|
|
||||||
timestamp: now.toISOString(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
expect(message.embeds.map((e) => e.toJSON())).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
footer: {
|
||||||
|
text: "footer text",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
footer: expect.objectContaining({
|
||||||
|
icon_url: "https://example.com/footer.png",
|
||||||
|
text: "footer text",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
timestamp: expect.stringContaining(""),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
timestamp: expect.stringContaining(""),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(new Date(message.embeds[2]!.timestamp!)).toEqual(now)
|
||||||
|
expect(new Date(message.embeds[3]!.timestamp!)).toEqual(now)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("embed props", async () => {
|
test.only("embed props", async () => {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
|
|
||||||
await testing.assertRender(
|
const { message } = await tester.render(
|
||||||
|
"embed props",
|
||||||
<Embed
|
<Embed
|
||||||
title="title text"
|
title="title text"
|
||||||
description="description text"
|
description="description text"
|
||||||
@@ -241,35 +233,33 @@ test("embed props", async () => {
|
|||||||
{ name: "block field", value: "block field value" },
|
{ name: "block field", value: "block field value" },
|
||||||
]}
|
]}
|
||||||
/>,
|
/>,
|
||||||
[
|
|
||||||
{
|
|
||||||
content: "",
|
|
||||||
actionRows: [],
|
|
||||||
embeds: [
|
|
||||||
{
|
|
||||||
title: "title text",
|
|
||||||
description: "description text",
|
|
||||||
url: "https://example.com/",
|
|
||||||
color: 0xfe_ee_ef,
|
|
||||||
timestamp: now.toISOString(),
|
|
||||||
author: {
|
|
||||||
name: "author name",
|
|
||||||
url: "https://example.com/author",
|
|
||||||
icon_url: "https://example.com/author.png",
|
|
||||||
},
|
|
||||||
thumbnail: { url: "https://example.com/thumbnail.png" },
|
|
||||||
image: { url: "https://example.com/image.png" },
|
|
||||||
footer: {
|
|
||||||
text: "footer text",
|
|
||||||
icon_url: "https://example.com/footer.png",
|
|
||||||
},
|
|
||||||
fields: [
|
|
||||||
{ name: "field name", value: "field value", inline: true },
|
|
||||||
{ name: "block field", value: "block field value" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
expect(message.embeds.map((e) => e.toJSON())).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
title: "title text",
|
||||||
|
description: "description text",
|
||||||
|
url: "https://example.com/",
|
||||||
|
color: 0xfe_ee_ef,
|
||||||
|
author: expect.objectContaining({
|
||||||
|
name: "author name",
|
||||||
|
url: "https://example.com/author",
|
||||||
|
icon_url: "https://example.com/author.png",
|
||||||
|
}),
|
||||||
|
thumbnail: expect.objectContaining({
|
||||||
|
url: "https://example.com/thumbnail.png",
|
||||||
|
}),
|
||||||
|
image: expect.objectContaining({ url: "https://example.com/image.png" }),
|
||||||
|
footer: expect.objectContaining({
|
||||||
|
text: "footer text",
|
||||||
|
icon_url: "https://example.com/footer.png",
|
||||||
|
}),
|
||||||
|
fields: [
|
||||||
|
{ name: "field name", value: "field value", inline: true },
|
||||||
|
{ name: "block field", value: "block field value", inline: false },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(new Date(message.embeds[0]!.timestamp!)).toEqual(now)
|
||||||
})
|
})
|
||||||
|
|||||||
5
packages/reacord/test/global-setup.ts
Normal file
5
packages/reacord/test/global-setup.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { ReacordTester } from "./tester"
|
||||||
|
|
||||||
|
export async function setup() {
|
||||||
|
await ReacordTester.removeChannels()
|
||||||
|
}
|
||||||
85
packages/reacord/test/tester.ts
Normal file
85
packages/reacord/test/tester.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import { raise } from "@reacord/helpers/raise"
|
||||||
|
import type { Client } from "discord.js"
|
||||||
|
import { CategoryChannel, ChannelType, GatewayIntentBits } from "discord.js"
|
||||||
|
import { kebabCase } from "lodash-es"
|
||||||
|
import { randomBytes } from "node:crypto"
|
||||||
|
import type { ReactNode } from "react"
|
||||||
|
import { createDiscordClient } from "../library/create-discord-client"
|
||||||
|
import { ReacordClient } from "../library/reacord-client"
|
||||||
|
import { testEnv } from "./test-env"
|
||||||
|
|
||||||
|
export class ReacordTester {
|
||||||
|
private static client?: Client
|
||||||
|
|
||||||
|
static async removeChannels() {
|
||||||
|
const client = await ReacordTester.getClient()
|
||||||
|
const category = await ReacordTester.getCategory(client)
|
||||||
|
for (const [, channel] of category.children.cache) {
|
||||||
|
await channel.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async create() {
|
||||||
|
const client = await ReacordTester.getClient()
|
||||||
|
const category = await ReacordTester.getCategory(client)
|
||||||
|
return new ReacordTester(client, category)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async getClient() {
|
||||||
|
return (this.client ??= await createDiscordClient(testEnv.TEST_BOT_TOKEN, {
|
||||||
|
intents: GatewayIntentBits.Guilds | GatewayIntentBits.GuildMessages,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async getCategory(client: Client<true>) {
|
||||||
|
const category =
|
||||||
|
client.channels.cache.get(testEnv.TEST_CATEGORY_ID) ??
|
||||||
|
(await client.channels.fetch(testEnv.TEST_CATEGORY_ID))
|
||||||
|
|
||||||
|
if (!(category instanceof CategoryChannel)) {
|
||||||
|
throw new TypeError("Category channel not found")
|
||||||
|
}
|
||||||
|
return category
|
||||||
|
}
|
||||||
|
|
||||||
|
private reacord?: ReacordClient
|
||||||
|
|
||||||
|
constructor(readonly client: Client, readonly category: CategoryChannel) {}
|
||||||
|
|
||||||
|
private async getTestChannel(testName: string) {
|
||||||
|
const hash = randomBytes(16).toString("hex").slice(0, 6)
|
||||||
|
const channelName = `${kebabCase(testName)}-${hash}`
|
||||||
|
|
||||||
|
let channel = this.category.children.cache.find(
|
||||||
|
(the) => the.name === channelName,
|
||||||
|
)
|
||||||
|
if (!channel || !channel.isTextBased()) {
|
||||||
|
channel = await this.category.children.create({
|
||||||
|
type: ChannelType.GuildText,
|
||||||
|
name: channelName,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [, message] of await channel.messages.fetch()) {
|
||||||
|
await message.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
return channel
|
||||||
|
}
|
||||||
|
|
||||||
|
async render(testName: string, content?: ReactNode) {
|
||||||
|
this.reacord ??= new ReacordClient({
|
||||||
|
token: testEnv.TEST_BOT_TOKEN,
|
||||||
|
})
|
||||||
|
|
||||||
|
const channel = await this.getTestChannel(testName)
|
||||||
|
await channel.sendTyping()
|
||||||
|
|
||||||
|
const instance = this.reacord.send(channel.id, content)
|
||||||
|
|
||||||
|
const result = await channel.awaitMessages({ max: 1 })
|
||||||
|
const message = result.first() ?? raise("failed to send message")
|
||||||
|
|
||||||
|
return { message, instance }
|
||||||
|
}
|
||||||
|
}
|
||||||
33
pnpm-lock.yaml
generated
33
pnpm-lock.yaml
generated
@@ -11,6 +11,7 @@ importers:
|
|||||||
'@itsmapleleaf/configs': ^1.1.5
|
'@itsmapleleaf/configs': ^1.1.5
|
||||||
'@rushstack/eslint-patch': ^1.1.4
|
'@rushstack/eslint-patch': ^1.1.4
|
||||||
'@types/eslint': ^8.4.5
|
'@types/eslint': ^8.4.5
|
||||||
|
'@vitest/ui': ^0.21.0
|
||||||
c8: ^7.12.0
|
c8: ^7.12.0
|
||||||
eslint: ^8.20.0
|
eslint: ^8.20.0
|
||||||
node: ^16.16.0
|
node: ^16.16.0
|
||||||
@@ -22,12 +23,13 @@ importers:
|
|||||||
'@itsmapleleaf/configs': 1.1.5_he2ccbldppg44uulnyq4rwocfa
|
'@itsmapleleaf/configs': 1.1.5_he2ccbldppg44uulnyq4rwocfa
|
||||||
'@rushstack/eslint-patch': 1.1.4
|
'@rushstack/eslint-patch': 1.1.4
|
||||||
'@types/eslint': 8.4.5
|
'@types/eslint': 8.4.5
|
||||||
|
'@vitest/ui': 0.21.0
|
||||||
c8: 7.12.0
|
c8: 7.12.0
|
||||||
eslint: 8.20.0
|
eslint: 8.20.0
|
||||||
node: 16.16.0
|
node: 16.16.0
|
||||||
prettier: 2.7.1
|
prettier: 2.7.1
|
||||||
typescript: 4.7.4
|
typescript: 4.7.4
|
||||||
vitest: 0.20.3_c8@7.12.0
|
vitest: 0.20.3_y7ksokcqbrho27xsbc2olnpwva
|
||||||
|
|
||||||
packages/helpers:
|
packages/helpers:
|
||||||
specifiers:
|
specifiers:
|
||||||
@@ -47,6 +49,7 @@ importers:
|
|||||||
'@types/prettier': ^2.6.4
|
'@types/prettier': ^2.6.4
|
||||||
'@types/react': '*'
|
'@types/react': '*'
|
||||||
'@types/react-reconciler': '*'
|
'@types/react-reconciler': '*'
|
||||||
|
date-fns: ^2.29.1
|
||||||
discord-api-types: ^0.36.3
|
discord-api-types: ^0.36.3
|
||||||
discord.js: ^14.1.2
|
discord.js: ^14.1.2
|
||||||
dotenv: ^16.0.1
|
dotenv: ^16.0.1
|
||||||
@@ -74,6 +77,7 @@ importers:
|
|||||||
'@reacord/helpers': link:../helpers
|
'@reacord/helpers': link:../helpers
|
||||||
'@types/lodash-es': 4.17.6
|
'@types/lodash-es': 4.17.6
|
||||||
'@types/prettier': 2.6.4
|
'@types/prettier': 2.6.4
|
||||||
|
date-fns: 2.29.1
|
||||||
discord.js: 14.1.2
|
discord.js: 14.1.2
|
||||||
dotenv: 16.0.1
|
dotenv: 16.0.1
|
||||||
lodash-es: 4.17.21
|
lodash-es: 4.17.21
|
||||||
@@ -2033,6 +2037,10 @@ packages:
|
|||||||
config-chain: 1.1.13
|
config-chain: 1.1.13
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@polka/url/1.0.0-next.21:
|
||||||
|
resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@reach/observe-rect/1.2.0:
|
/@reach/observe-rect/1.2.0:
|
||||||
resolution: {integrity: sha512-Ba7HmkFgfQxZqqaeIWWkNK0rEhpxVQHIoVyW1YDSkGsGIXzcaW4deC8B0pZrNSSyLTdIk7y+5olKt5+g0GmFIQ==}
|
resolution: {integrity: sha512-Ba7HmkFgfQxZqqaeIWWkNK0rEhpxVQHIoVyW1YDSkGsGIXzcaW4deC8B0pZrNSSyLTdIk7y+5olKt5+g0GmFIQ==}
|
||||||
dev: false
|
dev: false
|
||||||
@@ -2731,6 +2739,12 @@ packages:
|
|||||||
eslint-visitor-keys: 3.3.0
|
eslint-visitor-keys: 3.3.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@vitest/ui/0.21.0:
|
||||||
|
resolution: {integrity: sha512-xhMSwxsuaygIWn1jcTHbAVfNty6D2+hFVq+tvqNuSBE0WI3CWyeSOT1ISQ5urt3j5qoRbEXrZxWLC2dN3QeBSA==}
|
||||||
|
dependencies:
|
||||||
|
sirv: 2.0.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@web3-storage/multipart-parser/1.0.0:
|
/@web3-storage/multipart-parser/1.0.0:
|
||||||
resolution: {integrity: sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw==}
|
resolution: {integrity: sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw==}
|
||||||
|
|
||||||
@@ -9635,6 +9649,15 @@ packages:
|
|||||||
semver: 7.0.0
|
semver: 7.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/sirv/2.0.2:
|
||||||
|
resolution: {integrity: sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
dependencies:
|
||||||
|
'@polka/url': 1.0.0-next.21
|
||||||
|
mrmime: 1.0.1
|
||||||
|
totalist: 3.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/slash/3.0.0:
|
/slash/3.0.0:
|
||||||
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -10259,6 +10282,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==}
|
resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/totalist/3.0.0:
|
||||||
|
resolution: {integrity: sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/touch/3.1.0:
|
/touch/3.1.0:
|
||||||
resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==}
|
resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -10872,7 +10900,7 @@ packages:
|
|||||||
fsevents: 2.3.2
|
fsevents: 2.3.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vitest/0.20.3_c8@7.12.0:
|
/vitest/0.20.3_y7ksokcqbrho27xsbc2olnpwva:
|
||||||
resolution: {integrity: sha512-cXMjTbZxBBUUuIF3PUzEGPLJWtIMeURBDXVxckSHpk7xss4JxkiiWh5cnIlfGyfJne2Ii3QpbiRuFL5dMJtljw==}
|
resolution: {integrity: sha512-cXMjTbZxBBUUuIF3PUzEGPLJWtIMeURBDXVxckSHpk7xss4JxkiiWh5cnIlfGyfJne2Ii3QpbiRuFL5dMJtljw==}
|
||||||
engines: {node: '>=v14.16.0'}
|
engines: {node: '>=v14.16.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -10900,6 +10928,7 @@ packages:
|
|||||||
'@types/chai': 4.3.1
|
'@types/chai': 4.3.1
|
||||||
'@types/chai-subset': 1.3.3
|
'@types/chai-subset': 1.3.3
|
||||||
'@types/node': 18.6.3
|
'@types/node': 18.6.3
|
||||||
|
'@vitest/ui': 0.21.0
|
||||||
c8: 7.12.0
|
c8: 7.12.0
|
||||||
chai: 4.3.6
|
chai: 4.3.6
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
|
|||||||
@@ -5,4 +5,11 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
},
|
},
|
||||||
|
test: {
|
||||||
|
globalSetup: ["packages/reacord/test/global-setup.ts"],
|
||||||
|
threads: false,
|
||||||
|
isolate: false,
|
||||||
|
hookTimeout: 20_000,
|
||||||
|
testTimeout: 20_000,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user