add a manual tester in favor of playground
This commit is contained in:
@@ -39,8 +39,8 @@
|
|||||||
"build-watch": "pnpm build -- --watch",
|
"build-watch": "pnpm build -- --watch",
|
||||||
"test": "vitest --coverage --no-watch",
|
"test": "vitest --coverage --no-watch",
|
||||||
"test-dev": "vitest",
|
"test-dev": "vitest",
|
||||||
|
"test-manual": "nodemon --exec tsx --ext ts,tsx ./scripts/discordjs-manual-test.tsx",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"playground": "nodemon --exec esmo --ext ts,tsx --inspect=5858 --enable-source-maps ./playground/main.tsx",
|
|
||||||
"release": "bash scripts/release.sh"
|
"release": "bash scripts/release.sh"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -65,9 +65,6 @@
|
|||||||
"c8": "^7.11.2",
|
"c8": "^7.11.2",
|
||||||
"discord.js": "^14.0.3",
|
"discord.js": "^14.0.3",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.0",
|
||||||
"esbuild": "latest",
|
|
||||||
"esbuild-jest": "^0.5.0",
|
|
||||||
"esmo": "^0.14.1",
|
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"nodemon": "^2.0.15",
|
"nodemon": "^2.0.15",
|
||||||
"prettier": "^2.6.2",
|
"prettier": "^2.6.2",
|
||||||
@@ -75,6 +72,7 @@
|
|||||||
"react": "^18.0.0",
|
"react": "^18.0.0",
|
||||||
"release-it": "^14.14.2",
|
"release-it": "^14.14.2",
|
||||||
"tsup": "^5.12.6",
|
"tsup": "^5.12.6",
|
||||||
|
"tsx": "^3.8.0",
|
||||||
"type-fest": "^2.12.2",
|
"type-fest": "^2.12.2",
|
||||||
"typescript": "^4.6.3",
|
"typescript": "^4.6.3",
|
||||||
"vite": "^2.9.5",
|
"vite": "^2.9.5",
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
import type { Client, CommandInteraction } from "discord.js"
|
|
||||||
|
|
||||||
type Command = {
|
|
||||||
name: string
|
|
||||||
description: string
|
|
||||||
run: (interaction: CommandInteraction) => unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createCommandHandler(client: Client, commands: Command[]) {
|
|
||||||
client.on("ready", async () => {
|
|
||||||
for (const command of commands) {
|
|
||||||
for (const guild of client.guilds.cache.values()) {
|
|
||||||
await client.application?.commands.create(
|
|
||||||
{
|
|
||||||
name: command.name,
|
|
||||||
description: command.description,
|
|
||||||
},
|
|
||||||
guild.id,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
client.on("interactionCreate", async (interaction) => {
|
|
||||||
if (!interaction.isChatInputCommand()) return
|
|
||||||
|
|
||||||
const command = commands.find(
|
|
||||||
(command) => command.name === interaction.commandName,
|
|
||||||
)
|
|
||||||
if (command) {
|
|
||||||
try {
|
|
||||||
await command.run(interaction)
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
import * as React from "react"
|
|
||||||
import { Button, Embed, EmbedField, EmbedTitle } from "../library/main"
|
|
||||||
|
|
||||||
export function Counter(props: { onDeactivate: () => void }) {
|
|
||||||
const [count, setCount] = React.useState(0)
|
|
||||||
const [embedVisible, setEmbedVisible] = React.useState(false)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
this button was clicked {count} times
|
|
||||||
{embedVisible && (
|
|
||||||
<Embed>
|
|
||||||
<EmbedTitle>the counter</EmbedTitle>
|
|
||||||
{count > 0 && (
|
|
||||||
<EmbedField name="is it even?">
|
|
||||||
{count % 2 === 0 ? "yes" : "no"}
|
|
||||||
</EmbedField>
|
|
||||||
)}
|
|
||||||
</Embed>
|
|
||||||
)}
|
|
||||||
{embedVisible && (
|
|
||||||
<Button label="hide embed" onClick={() => setEmbedVisible(false)} />
|
|
||||||
)}
|
|
||||||
<Button
|
|
||||||
style="primary"
|
|
||||||
emoji="<:plus_one:778531744860602388>"
|
|
||||||
label="clicc"
|
|
||||||
onClick={() => setCount(count + 1)}
|
|
||||||
/>
|
|
||||||
{!embedVisible && (
|
|
||||||
<Button label="show embed" onClick={() => setEmbedVisible(true)} />
|
|
||||||
)}
|
|
||||||
<Button style="danger" label="deactivate" onClick={props.onDeactivate} />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import React, { useState } from "react"
|
|
||||||
import { Button, Option, Select } from "../library/main"
|
|
||||||
|
|
||||||
export function FruitSelect({
|
|
||||||
onConfirm,
|
|
||||||
}: {
|
|
||||||
onConfirm: (choice: string) => void
|
|
||||||
}) {
|
|
||||||
const [value, setValue] = useState<string>()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Select
|
|
||||||
placeholder="choose a fruit"
|
|
||||||
value={value}
|
|
||||||
onChangeValue={setValue}
|
|
||||||
>
|
|
||||||
<Option value="🍎" />
|
|
||||||
<Option value="🍌" />
|
|
||||||
<Option value="🍒" />
|
|
||||||
</Select>
|
|
||||||
<Button
|
|
||||||
label="confirm"
|
|
||||||
disabled={value == undefined}
|
|
||||||
onClick={() => {
|
|
||||||
if (value) onConfirm(value)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
import { Client, IntentsBitField } from "discord.js"
|
|
||||||
import "dotenv/config"
|
|
||||||
import React from "react"
|
|
||||||
import { Button, ReacordDiscordJs, useInstance } from "../library/main"
|
|
||||||
import { createCommandHandler } from "./command-handler"
|
|
||||||
import { Counter } from "./counter"
|
|
||||||
import { FruitSelect } from "./fruit-select"
|
|
||||||
|
|
||||||
const client = new Client({
|
|
||||||
intents: IntentsBitField.Flags.Guilds,
|
|
||||||
})
|
|
||||||
|
|
||||||
const reacord = new ReacordDiscordJs(client)
|
|
||||||
|
|
||||||
client.on("ready", () => {
|
|
||||||
console.info("ready 💖")
|
|
||||||
|
|
||||||
// const now = new Date()
|
|
||||||
|
|
||||||
// function UptimeCounter() {
|
|
||||||
// const [uptime, setUptime] = React.useState(0)
|
|
||||||
|
|
||||||
// React.useEffect(() => {
|
|
||||||
// const interval = setInterval(() => {
|
|
||||||
// setUptime(Date.now() - now.getTime())
|
|
||||||
// }, 5000)
|
|
||||||
// return () => clearInterval(interval)
|
|
||||||
// }, [])
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <Embed>this bot has been running for {prettyMilliseconds(uptime)}</Embed>
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
|
|
||||||
// reacord.send("671787605624487941", <UptimeCounter />)
|
|
||||||
})
|
|
||||||
|
|
||||||
createCommandHandler(client, [
|
|
||||||
{
|
|
||||||
name: "button",
|
|
||||||
description: "it's a button",
|
|
||||||
run: (interaction) => {
|
|
||||||
reacord.reply(
|
|
||||||
interaction,
|
|
||||||
<Button label="clic" onClick={() => console.info("was clic")} />,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "counter",
|
|
||||||
description: "shows a counter button",
|
|
||||||
run: (interaction) => {
|
|
||||||
const reply = reacord.reply(interaction)
|
|
||||||
reply.render(<Counter onDeactivate={() => reply.destroy()} />)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "select",
|
|
||||||
description: "shows a select",
|
|
||||||
run: (interaction) => {
|
|
||||||
const instance = reacord.reply(
|
|
||||||
interaction,
|
|
||||||
<FruitSelect
|
|
||||||
onConfirm={(value) => {
|
|
||||||
instance.render(`you chose ${value}`)
|
|
||||||
instance.deactivate()
|
|
||||||
}}
|
|
||||||
/>,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ephemeral-button",
|
|
||||||
description: "button which shows ephemeral messages",
|
|
||||||
run: (interaction) => {
|
|
||||||
reacord.reply(
|
|
||||||
interaction,
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
label="public clic"
|
|
||||||
onClick={(event) =>
|
|
||||||
reacord.reply(
|
|
||||||
interaction,
|
|
||||||
`${event.guild?.member.displayName} clic`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
label="clic"
|
|
||||||
onClick={(event) => event.ephemeralReply("you clic")}
|
|
||||||
/>
|
|
||||||
</>,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "delete-this",
|
|
||||||
description: "delete this",
|
|
||||||
run: (interaction) => {
|
|
||||||
function DeleteThis() {
|
|
||||||
const instance = useInstance()
|
|
||||||
return <Button label="delete this" onClick={() => instance.destroy()} />
|
|
||||||
}
|
|
||||||
reacord.reply(interaction, <DeleteThis />)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
await client.login(process.env.TEST_BOT_TOKEN)
|
|
||||||
134
packages/reacord/scripts/discordjs-manual-test.tsx
Normal file
134
packages/reacord/scripts/discordjs-manual-test.tsx
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
import type { TextChannel } from "discord.js"
|
||||||
|
import { ChannelType, Client, IntentsBitField } from "discord.js"
|
||||||
|
import "dotenv/config"
|
||||||
|
import { kebabCase } from "lodash-es"
|
||||||
|
import * as React from "react"
|
||||||
|
import { useState } from "react"
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Option,
|
||||||
|
ReacordDiscordJs,
|
||||||
|
Select,
|
||||||
|
useInstance,
|
||||||
|
} from "../library/main"
|
||||||
|
|
||||||
|
const client = new Client({ intents: IntentsBitField.Flags.Guilds })
|
||||||
|
const reacord = new ReacordDiscordJs(client)
|
||||||
|
|
||||||
|
await client.login(process.env.TEST_BOT_TOKEN)
|
||||||
|
|
||||||
|
const guild = await client.guilds.fetch(process.env.TEST_GUILD_ID!)
|
||||||
|
|
||||||
|
const category = await guild.channels.fetch(process.env.TEST_CATEGORY_ID!)
|
||||||
|
if (category?.type !== ChannelType.GuildCategory) {
|
||||||
|
throw new Error(
|
||||||
|
`channel ${process.env.TEST_CATEGORY_ID} is not a guild category. received ${category?.type}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [, channel] of category.children.cache) {
|
||||||
|
await channel.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
let prefix = 0
|
||||||
|
const createTest = async (
|
||||||
|
name: string,
|
||||||
|
block: (channel: TextChannel) => void | Promise<unknown>,
|
||||||
|
) => {
|
||||||
|
prefix += 1
|
||||||
|
const channel = await category.children.create({
|
||||||
|
type: ChannelType.GuildText,
|
||||||
|
name: `${String(prefix).padStart(3, "0")}-${kebabCase(name)}`,
|
||||||
|
})
|
||||||
|
await block(channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
await createTest("basic", (channel) => {
|
||||||
|
reacord.send(channel.id, "Hello, world!")
|
||||||
|
})
|
||||||
|
|
||||||
|
await createTest("counter", (channel) => {
|
||||||
|
const Counter = () => {
|
||||||
|
const [count, setCount] = React.useState(0)
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
count: {count}
|
||||||
|
<Button
|
||||||
|
style="primary"
|
||||||
|
emoji="➕"
|
||||||
|
onClick={() => setCount(count + 1)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
style="primary"
|
||||||
|
emoji="➖"
|
||||||
|
onClick={() => setCount(count - 1)}
|
||||||
|
/>
|
||||||
|
<Button label="reset" onClick={() => setCount(0)} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
reacord.send(channel.id, <Counter />)
|
||||||
|
})
|
||||||
|
|
||||||
|
await createTest("select", (channel) => {
|
||||||
|
function FruitSelect({ onConfirm }: { onConfirm: (choice: string) => void }) {
|
||||||
|
const [value, setValue] = useState<string>()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Select
|
||||||
|
placeholder="choose a fruit"
|
||||||
|
value={value}
|
||||||
|
onChangeValue={setValue}
|
||||||
|
>
|
||||||
|
<Option value="🍎" />
|
||||||
|
<Option value="🍌" />
|
||||||
|
<Option value="🍒" />
|
||||||
|
</Select>
|
||||||
|
<Button
|
||||||
|
label="confirm"
|
||||||
|
disabled={value == undefined}
|
||||||
|
onClick={() => {
|
||||||
|
if (value) onConfirm(value)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const instance = reacord.send(
|
||||||
|
channel.id,
|
||||||
|
<FruitSelect
|
||||||
|
onConfirm={(value) => {
|
||||||
|
instance.render(`you chose ${value}`)
|
||||||
|
instance.deactivate()
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
await createTest("ephemeral button", (channel) => {
|
||||||
|
reacord.send(
|
||||||
|
channel.id,
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
label="public clic"
|
||||||
|
onClick={(event) =>
|
||||||
|
event.reply(`${event.guild?.member.displayName} clic`)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
label="clic"
|
||||||
|
onClick={(event) => event.ephemeralReply("you clic")}
|
||||||
|
/>
|
||||||
|
</>,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
await createTest("delete this", (channel) => {
|
||||||
|
function DeleteThis() {
|
||||||
|
const instance = useInstance()
|
||||||
|
return <Button label="delete this" onClick={() => instance.destroy()} />
|
||||||
|
}
|
||||||
|
reacord.send(channel.id, <DeleteThis />)
|
||||||
|
})
|
||||||
672
pnpm-lock.yaml
generated
672
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user