api-surface #1

Merged
luna merged 51 commits from api-surface into mistress 2026-07-05 14:43:13 +00:00
12 changed files with 621 additions and 11 deletions
Showing only changes of commit 6aec66f5ad - Show all commits

feat(api): commands, emojis/stickers, moderation, users, misc rollout — full surface

Luna 2026-07-05 06:34:45 -03:00

View file

@ -408,6 +408,8 @@ defmodule Dexcord.Api do
Dexcord.Api.Users,
Dexcord.Api.Interactions,
Dexcord.Api.Commands,
Dexcord.Api.EmojisStickers,
Dexcord.Api.Moderation,
Dexcord.Api.Misc
]

View file

@ -19,4 +19,57 @@ defmodule Dexcord.Api.Commands do
"/applications/:application_id/guilds/:guild_id/commands",
body: true,
returns: [Dexcord.ApplicationCommand]
endpoint :get_global_commands, :get, "/applications/:application_id/commands",
query: [:with_localizations],
returns: [Dexcord.ApplicationCommand]
endpoint :create_global_command, :post, "/applications/:application_id/commands",
body: true,
returns: Dexcord.ApplicationCommand
endpoint :get_global_command, :get, "/applications/:application_id/commands/:command_id",
returns: Dexcord.ApplicationCommand
endpoint :edit_global_command, :patch, "/applications/:application_id/commands/:command_id",
body: true,
returns: Dexcord.ApplicationCommand
endpoint :delete_global_command, :delete, "/applications/:application_id/commands/:command_id",
returns: nil
endpoint :get_guild_commands, :get, "/applications/:application_id/guilds/:guild_id/commands",
query: [:with_localizations],
returns: [Dexcord.ApplicationCommand]
endpoint :create_guild_command,
:post,
"/applications/:application_id/guilds/:guild_id/commands",
body: true,
returns: Dexcord.ApplicationCommand
endpoint :get_guild_command,
:get,
"/applications/:application_id/guilds/:guild_id/commands/:command_id",
returns: Dexcord.ApplicationCommand
endpoint :edit_guild_command,
:patch,
"/applications/:application_id/guilds/:guild_id/commands/:command_id",
body: true,
returns: Dexcord.ApplicationCommand
endpoint :delete_guild_command,
:delete,
"/applications/:application_id/guilds/:guild_id/commands/:command_id", returns: nil
endpoint :get_guild_command_permissions,
:get,
"/applications/:application_id/guilds/:guild_id/commands/permissions",
returns: [Dexcord.GuildApplicationCommandPermissions]
endpoint :get_command_permissions,
:get,
"/applications/:application_id/guilds/:guild_id/commands/:command_id/permissions",
returns: Dexcord.GuildApplicationCommandPermissions
end

View file

@ -0,0 +1,69 @@
defmodule Dexcord.Api.EmojisStickers do
@moduledoc """
Emoji and sticker endpoints, declared with the `Dexcord.Api.Endpoint` DSL
mirrors the Discord "Emoji" and "Sticker" resource pages.
Emoji create/edit bodies carry base64 `image` data in plain JSON (no
multipart). `create_guild_sticker` is the exception: it uses plain form-field
multipart (`files: :form`) with `name`/`description`/`tags` parts plus a single
`file` part. `list_application_emojis` and the sticker-pack listings return
`{"items": [...]}` / pack envelopes with no model (`:raw`).
"""
use Dexcord.Api.Endpoint
endpoint :list_guild_emojis, :get, "/guilds/:guild_id/emojis", returns: [Dexcord.Emoji]
endpoint :get_guild_emoji, :get, "/guilds/:guild_id/emojis/:emoji_id", returns: Dexcord.Emoji
endpoint :create_guild_emoji, :post, "/guilds/:guild_id/emojis",
body: true,
reason: true,
returns: Dexcord.Emoji
endpoint :edit_guild_emoji, :patch, "/guilds/:guild_id/emojis/:emoji_id",
body: true,
reason: true,
returns: Dexcord.Emoji
endpoint :delete_guild_emoji, :delete, "/guilds/:guild_id/emojis/:emoji_id",
reason: true,
returns: nil
endpoint :list_application_emojis, :get, "/applications/:application_id/emojis", returns: :raw
endpoint :get_application_emoji, :get, "/applications/:application_id/emojis/:emoji_id",
returns: Dexcord.Emoji
endpoint :create_application_emoji, :post, "/applications/:application_id/emojis",
body: true,
returns: Dexcord.Emoji
endpoint :edit_application_emoji, :patch, "/applications/:application_id/emojis/:emoji_id",
body: true,
returns: Dexcord.Emoji
endpoint :delete_application_emoji, :delete, "/applications/:application_id/emojis/:emoji_id",
returns: nil
endpoint :get_sticker, :get, "/stickers/:sticker_id", returns: Dexcord.Sticker
endpoint :list_sticker_packs, :get, "/sticker-packs", returns: :raw
endpoint :get_sticker_pack, :get, "/sticker-packs/:pack_id", returns: :raw
endpoint :list_guild_stickers, :get, "/guilds/:guild_id/stickers", returns: [Dexcord.Sticker]
endpoint :get_guild_sticker, :get, "/guilds/:guild_id/stickers/:sticker_id",
returns: Dexcord.Sticker
endpoint :create_guild_sticker, :post, "/guilds/:guild_id/stickers",
body: true,
files: :form,
reason: true,
returns: Dexcord.Sticker
endpoint :edit_guild_sticker, :patch, "/guilds/:guild_id/stickers/:sticker_id",
body: true,
reason: true,
returns: Dexcord.Sticker
endpoint :delete_guild_sticker, :delete, "/guilds/:guild_id/stickers/:sticker_id",
reason: true,
returns: nil
end

View file

@ -3,17 +3,29 @@ defmodule Dexcord.Api.Misc do
Gateway / application-info endpoints, declared with the
`Dexcord.Api.Endpoint` DSL.
`get_gateway_bot/0` stays `:raw` its `url` / `shards` / `session_start_limit`
shape has no model and the gateway reads it as a raw map.
`get_current_application/0` returns a `Dexcord.ApplicationInfo`.
`get_gateway/0` and `get_gateway_bot/0` stay `:raw` their
`url` / `shards` / `session_start_limit` shapes have no model and the gateway
reads them as raw maps.
`get_current_application/0` hits the docs-canonical `GET /applications/@me`;
the older `GET /oauth2/applications/@me` route is preserved as
`get_current_bot_application/0`. Both return a `Dexcord.ApplicationInfo`.
`get_guild` moved to `Dexcord.Api.Guilds` the `Dexcord.Api` facade delegate
follows the group automatically.
"""
use Dexcord.Api.Endpoint
endpoint :get_gateway, :get, "/gateway", returns: :raw
endpoint :get_gateway_bot, :get, "/gateway/bot", returns: :raw
endpoint :get_current_application, :get, "/applications/@me", returns: Dexcord.ApplicationInfo
endpoint :get_current_application, :get, "/oauth2/applications/@me",
endpoint :edit_current_application, :patch, "/applications/@me",
body: true,
returns: Dexcord.ApplicationInfo
endpoint :get_current_bot_application, :get, "/oauth2/applications/@me",
returns: Dexcord.ApplicationInfo
endpoint :list_voice_regions, :get, "/voice/regions", returns: [Dexcord.VoiceRegion]
end

View file

@ -0,0 +1,69 @@
defmodule Dexcord.Api.Moderation do
@moduledoc """
Auto-moderation and guild-scheduled-event endpoints, declared with the
`Dexcord.Api.Endpoint` DSL mirrors the Discord "Auto Moderation" and
"Guild Scheduled Event" resource pages.
`delete_guild_scheduled_event` deliberately has NO `reason:` support (the docs
are asymmetric create/edit take a reason, delete does not).
"""
use Dexcord.Api.Endpoint
endpoint :list_auto_moderation_rules, :get, "/guilds/:guild_id/auto-moderation/rules",
returns: [Dexcord.AutoModerationRule]
endpoint :get_auto_moderation_rule,
:get,
"/guilds/:guild_id/auto-moderation/rules/:auto_moderation_rule_id",
returns: Dexcord.AutoModerationRule
endpoint :create_auto_moderation_rule, :post, "/guilds/:guild_id/auto-moderation/rules",
body: true,
reason: true,
returns: Dexcord.AutoModerationRule
endpoint :edit_auto_moderation_rule,
:patch,
"/guilds/:guild_id/auto-moderation/rules/:auto_moderation_rule_id",
body: true,
reason: true,
returns: Dexcord.AutoModerationRule
endpoint :delete_auto_moderation_rule,
:delete,
"/guilds/:guild_id/auto-moderation/rules/:auto_moderation_rule_id",
reason: true,
returns: nil
endpoint :list_guild_scheduled_events, :get, "/guilds/:guild_id/scheduled-events",
query: [:with_user_count],
returns: [Dexcord.GuildScheduledEvent]
endpoint :create_guild_scheduled_event, :post, "/guilds/:guild_id/scheduled-events",
body: true,
reason: true,
returns: Dexcord.GuildScheduledEvent
endpoint :get_guild_scheduled_event,
:get,
"/guilds/:guild_id/scheduled-events/:guild_scheduled_event_id",
query: [:with_user_count],
returns: Dexcord.GuildScheduledEvent
endpoint :edit_guild_scheduled_event,
:patch,
"/guilds/:guild_id/scheduled-events/:guild_scheduled_event_id",
body: true,
reason: true,
returns: Dexcord.GuildScheduledEvent
endpoint :delete_guild_scheduled_event,
:delete,
"/guilds/:guild_id/scheduled-events/:guild_scheduled_event_id", returns: nil
endpoint :get_guild_scheduled_event_users,
:get,
"/guilds/:guild_id/scheduled-events/:guild_scheduled_event_id/users",
query: [:limit, :with_member, :before, :after],
returns: [Dexcord.GuildScheduledEventUser]
end

View file

@ -13,6 +13,20 @@ defmodule Dexcord.Api.Users do
endpoint :get_current_user, :get, "/users/@me", returns: Dexcord.User
endpoint :get_user, :get, "/users/:user_id", returns: Dexcord.User
endpoint :edit_current_user, :patch, "/users/@me", body: true, returns: Dexcord.User
endpoint :get_current_user_guilds, :get, "/users/@me/guilds",
query: [:before, :after, :limit, :with_counts],
returns: [Dexcord.PartialGuild]
endpoint :get_current_user_guild_member, :get, "/users/@me/guilds/:guild_id/member",
returns: Dexcord.Member
endpoint :leave_guild, :delete, "/users/@me/guilds/:guild_id", returns: nil
endpoint :get_current_user_connections, :get, "/users/@me/connections",
returns: [Dexcord.Connection]
@create_dm_spec %{
name: :create_dm,
method: :post,

View file

@ -9,7 +9,7 @@ defmodule Dexcord.Slash.Registrar do
On start it:
1. calls `GET /oauth2/applications/@me` to learn the application id and caches
1. calls `GET /applications/@me` to learn the application id and caches
it via `Dexcord.Config.put_application_id/1` (a dedicated `:persistent_term`
key, so any process can read it back with `Dexcord.Config.application_id/0`);
2. bulk-overwrites the module's `commands/0`:
@ -114,7 +114,7 @@ defmodule Dexcord.Slash.Registrar do
other ->
{:error,
"could not resolve the application id (GET /oauth2/applications/@me): " <>
"could not resolve the application id (GET /applications/@me): " <>
inspect(other)}
end
end

View file

@ -0,0 +1,140 @@
defmodule Dexcord.ApiCommandsTest do
@moduledoc """
Representative wire tests for the extended `Dexcord.Api.Commands` group
(Phase 5 Task 5), including a struct body encoded via `to_map/1` with a
recursive (sub-command-group) options tree.
"""
use ExUnit.Case, async: false
alias Dexcord.Api
alias Dexcord.Api.Ratelimit
alias Dexcord.FakeRest
@token "test.token.value"
setup do
Dexcord.EnvSandbox.sandbox_env()
Dexcord.Config.put(%{token: @token, handler: nil, intents: 0})
start_supervised!({Finch, name: Dexcord.Finch})
start_supervised!(Ratelimit)
start_supervised!(FakeRest)
Application.put_env(:dexcord, :api_base_url, FakeRest.base_url())
FakeRest.subscribe(self())
:ok
end
test "get_global_commands forwards with_localizations and decodes a list" do
FakeRest.stub(
:get,
"/applications/1/commands",
FakeRest.resp(200, body: ~s([{"id":"2","name":"ping"}]))
)
assert {:ok, [%Dexcord.ApplicationCommand{id: 2, name: "ping"}]} =
Api.get_global_commands(1, with_localizations: true)
assert_receive {:rest_hit, info}
assert info.query_string == "with_localizations=true"
end
test "create_global_command encodes a recursive ApplicationCommand struct body" do
FakeRest.stub(
:post,
"/applications/1/commands",
FakeRest.resp(201, body: ~s({"id":"7","name":"config"}))
)
command = %Dexcord.ApplicationCommand{
name: "config",
description: "configure the bot",
options: [
%Dexcord.ApplicationCommand.Option{
type: :sub_command_group,
name: "group",
description: "a group",
options: [
%Dexcord.ApplicationCommand.Option{
type: :sub_command,
name: "sub",
description: "a sub-command"
}
]
}
]
}
assert {:ok, %Dexcord.ApplicationCommand{id: 7, name: "config"}} =
Api.create_global_command(1, command)
assert_receive {:rest_hit, info}
body = JSON.decode!(info.body)
assert body["name"] == "config"
assert [group] = body["options"]
# sub_command_group encodes to 2, the nested sub_command to 1.
assert group["type"] == 2
assert group["name"] == "group"
assert [sub] = group["options"]
assert sub["type"] == 1
assert sub["name"] == "sub"
end
test "edit_global_command PATCHes and decodes an ApplicationCommand" do
FakeRest.stub(
:patch,
"/applications/1/commands/2",
FakeRest.resp(200, body: ~s({"id":"2","name":"renamed"}))
)
assert {:ok, %Dexcord.ApplicationCommand{id: 2, name: "renamed"}} =
Api.edit_global_command(1, 2, %{"name" => "renamed"})
end
test "delete_global_command returns nil" do
FakeRest.stub(:delete, "/applications/1/commands/2", FakeRest.resp(204))
assert {:ok, nil} = Api.delete_global_command(1, 2)
end
test "create_guild_command decodes an ApplicationCommand" do
FakeRest.stub(
:post,
"/applications/1/guilds/9/commands",
FakeRest.resp(201, body: ~s({"id":"3","name":"g"}))
)
assert {:ok, %Dexcord.ApplicationCommand{id: 3, name: "g"}} =
Api.create_guild_command(1, 9, %{"name" => "g", "description" => "d"})
end
test "get_guild_command_permissions decodes a list of permission structs" do
FakeRest.stub(
:get,
"/applications/1/guilds/9/commands/permissions",
FakeRest.resp(200,
body: ~s([{"id":"2","permissions":[{"id":"5","type":1,"permission":true}]}])
)
)
assert {:ok,
[
%Dexcord.GuildApplicationCommandPermissions{
id: 2,
permissions: [%Dexcord.ApplicationCommandPermission{id: 5, permission: true}]
}
]} = Api.get_guild_command_permissions(1, 9)
end
test "get_command_permissions decodes a single permissions struct" do
FakeRest.stub(
:get,
"/applications/1/guilds/9/commands/2/permissions",
FakeRest.resp(200, body: ~s({"id":"2","permissions":[]}))
)
assert {:ok, %Dexcord.GuildApplicationCommandPermissions{id: 2, permissions: []}} =
Api.get_command_permissions(1, 9, 2)
end
end

View file

@ -75,6 +75,8 @@ defmodule Dexcord.ApiFacadeTest do
Dexcord.Api.Users,
Dexcord.Api.Interactions,
Dexcord.Api.Commands,
Dexcord.Api.EmojisStickers,
Dexcord.Api.Moderation,
Dexcord.Api.Misc
]
end

View file

@ -0,0 +1,248 @@
defmodule Dexcord.ApiModerationTest do
@moduledoc """
Representative wire tests for the Phase 5 Task 5 groups: `Dexcord.Api.Moderation`
(auto-moderation + scheduled events), `Dexcord.Api.EmojisStickers` (base64 JSON
emoji bodies vs. plain-form sticker multipart), the `Dexcord.Api.Users`
additions, and the `Dexcord.Api.Misc` `get_current_application` re-point.
"""
use ExUnit.Case, async: false
alias Dexcord.Api
alias Dexcord.Api.Ratelimit
alias Dexcord.FakeRest
@token "test.token.value"
setup do
Dexcord.EnvSandbox.sandbox_env()
Dexcord.Config.put(%{token: @token, handler: nil, intents: 0})
start_supervised!({Finch, name: Dexcord.Finch})
start_supervised!(Ratelimit)
start_supervised!(FakeRest)
Application.put_env(:dexcord, :api_base_url, FakeRest.base_url())
FakeRest.subscribe(self())
:ok
end
# --- Moderation: auto-moderation ---------------------------------------
test "create_auto_moderation_rule posts a body and decodes the rule with a reason" do
FakeRest.stub(
:post,
"/guilds/1/auto-moderation/rules",
FakeRest.resp(200, body: ~s({"id":"5","name":"no-spam","trigger_type":1}))
)
assert {:ok, %Dexcord.AutoModerationRule{id: 5, name: "no-spam"}} =
Api.create_auto_moderation_rule(1, %{"name" => "no-spam"}, reason: "policy")
assert_receive {:rest_hit, info}
assert Map.new(info.headers)["x-audit-log-reason"] == "policy"
end
test "list_auto_moderation_rules decodes a list of rules" do
FakeRest.stub(
:get,
"/guilds/1/auto-moderation/rules",
FakeRest.resp(200, body: ~s([{"id":"5","name":"a"},{"id":"6","name":"b"}]))
)
assert {:ok, [%Dexcord.AutoModerationRule{id: 5}, %Dexcord.AutoModerationRule{id: 6}]} =
Api.list_auto_moderation_rules(1)
end
# --- Moderation: scheduled events --------------------------------------
test "get_guild_scheduled_event forwards with_user_count and decodes the event" do
FakeRest.stub(
:get,
"/guilds/1/scheduled-events/2",
FakeRest.resp(200, body: ~s({"id":"2","name":"party","user_count":10}))
)
assert {:ok, %Dexcord.GuildScheduledEvent{id: 2, name: "party", user_count: 10}} =
Api.get_guild_scheduled_event(1, 2, with_user_count: true)
assert_receive {:rest_hit, info}
assert info.query_string == "with_user_count=true"
end
test "delete_guild_scheduled_event returns nil (no reason support)" do
FakeRest.stub(:delete, "/guilds/1/scheduled-events/2", FakeRest.resp(204))
assert {:ok, nil} = Api.delete_guild_scheduled_event(1, 2)
end
# --- Emojis / Stickers -------------------------------------------------
test "create_guild_emoji sends a base64 image in a plain JSON body (NOT multipart)" do
FakeRest.stub(
:post,
"/guilds/1/emojis",
FakeRest.resp(200, body: ~s({"id":"9","name":"blob"}))
)
image = "data:image/png;base64,iVBORw0KGgo="
assert {:ok, %Dexcord.Emoji{id: 9, name: "blob"}} =
Api.create_guild_emoji(1, %{"name" => "blob", "image" => image}, reason: "add")
assert_receive {:rest_hit, info}
headers = Map.new(info.headers)
assert headers["content-type"] == "application/json"
assert JSON.decode!(info.body) == %{"name" => "blob", "image" => image}
end
test "create_guild_sticker sends plain-form multipart (name/description/tags + file)" do
FakeRest.stub(
:post,
"/guilds/1/stickers",
FakeRest.resp(201, body: ~s({"id":"9","name":"wave"}))
)
file = %{filename: "wave.png", data: <<137, 80, 78, 71>>, content_type: "image/png"}
assert {:ok, %Dexcord.Sticker{id: 9, name: "wave"}} =
Api.create_guild_sticker(
1,
%{"name" => "wave", "description" => "a wave", "tags" => "wave"},
files: [file],
reason: "add sticker"
)
assert_receive {:rest_hit, info}
headers = Map.new(info.headers)
assert "multipart/form-data; boundary=" <> boundary = headers["content-type"]
assert headers["x-audit-log-reason"] == "add%20sticker"
named = info.body |> parse_multipart(boundary) |> by_name()
assert named["name"].data == "wave"
assert named["name"].filename == nil
assert named["description"].data == "a wave"
assert named["tags"].data == "wave"
assert %{"file" => file_part} = named
assert file_part.filename == "wave.png"
assert file_part.content_type == "image/png"
assert file_part.data == <<137, 80, 78, 71>>
end
test "list_application_emojis returns the raw {items: [...]} envelope" do
FakeRest.stub(
:get,
"/applications/1/emojis",
FakeRest.resp(200, body: ~s({"items":[]}))
)
assert {:ok, %{"items" => []}} = Api.list_application_emojis(1)
end
# --- Users -------------------------------------------------------------
test "edit_current_user PATCHes and decodes a User" do
FakeRest.stub(
:patch,
"/users/@me",
FakeRest.resp(200, body: ~s({"id":"42","username":"bot"}))
)
assert {:ok, %Dexcord.User{id: 42, username: "bot"}} =
Api.edit_current_user(%{"username" => "bot"})
end
test "get_current_user_guilds forwards the query and decodes PartialGuilds" do
FakeRest.stub(
:get,
"/users/@me/guilds",
FakeRest.resp(200, body: ~s([{"id":"1","name":"g1"},{"id":"2","name":"g2"}]))
)
assert {:ok, [%Dexcord.PartialGuild{id: 1, name: "g1"}, %Dexcord.PartialGuild{id: 2}]} =
Api.get_current_user_guilds(limit: 100, with_counts: true)
assert_receive {:rest_hit, info}
assert URI.decode_query(info.query_string) == %{"limit" => "100", "with_counts" => "true"}
end
test "leave_guild returns nil" do
FakeRest.stub(:delete, "/users/@me/guilds/1", FakeRest.resp(204))
assert {:ok, nil} = Api.leave_guild(1)
end
# --- Misc: application-info re-point ------------------------------------
test "get_current_application now hits the canonical /applications/@me route" do
FakeRest.stub(
:get,
"/applications/@me",
FakeRest.resp(200, body: ~s({"id":"99","name":"App"}))
)
assert {:ok, %Dexcord.ApplicationInfo{id: 99}} = Api.get_current_application()
assert_receive {:rest_hit, info}
assert info.path == "/applications/@me"
end
test "get_current_bot_application keeps the oauth2 route" do
FakeRest.stub(
:get,
"/oauth2/applications/@me",
FakeRest.resp(200, body: ~s({"id":"99","name":"App"}))
)
assert {:ok, %Dexcord.ApplicationInfo{id: 99}} = Api.get_current_bot_application()
assert_receive {:rest_hit, info}
assert info.path == "/oauth2/applications/@me"
end
# --- multipart parsing helpers (copied from api_integration_test.exs) ---
defp parse_multipart(body, boundary) do
body
|> String.split("--" <> boundary)
|> Enum.drop(1)
|> Enum.reject(fn seg -> seg == "--\r\n" or seg == "--" end)
|> Enum.map(fn seg ->
seg = String.replace_prefix(seg, "\r\n", "")
[raw_headers, rest] = String.split(seg, "\r\n\r\n", parts: 2)
data = String.replace_suffix(rest, "\r\n", "")
disposition = header_value(raw_headers, "content-disposition")
%{
name: extract(disposition, ~r/name="([^"]*)"/),
filename: extract(disposition, ~r/filename="([^"]*)"/),
content_type: header_value(raw_headers, "content-type"),
data: data
}
end)
end
defp by_name(parts), do: Map.new(parts, fn part -> {part.name, part} end)
defp header_value(raw_headers, name) do
raw_headers
|> String.split("\r\n")
|> Enum.find_value(fn line ->
case String.split(line, ": ", parts: 2) do
[key, value] -> if String.downcase(key) == name, do: value
_ -> nil
end
end)
end
defp extract(nil, _re), do: nil
defp extract(string, re) do
case Regex.run(re, string) do
[_, captured] -> captured
_ -> nil
end
end
end

View file

@ -40,10 +40,11 @@ defmodule Dexcord.RegistrarIntegrationTest do
# The application/guild ids are numeric snowflakes: `get_current_application`
# now decodes to `%Dexcord.ApplicationInfo{}` (id cast to an integer) and the
# `bulk_overwrite_*` endpoints cast their `*_id` path params via
# `Dexcord.Snowflake.cast/1`.
# `Dexcord.Snowflake.cast/1`. As of Phase 5 Task 5, `get_current_application`
# is re-pointed to the docs-canonical `GET /applications/@me`.
FakeRest.stub(
:get,
"/oauth2/applications/@me",
"/applications/@me",
FakeRest.resp(200, body: ~s({"id":"99"}))
)
@ -58,7 +59,7 @@ defmodule Dexcord.RegistrarIntegrationTest do
assert Dexcord.Config.application_id() == 99
assert_receive {:rest_hit, %{method: "GET", path: "/oauth2/applications/@me"}}
assert_receive {:rest_hit, %{method: "GET", path: "/applications/@me"}}
assert_receive {:rest_hit, %{method: "PUT", path: "/applications/99/commands", body: body}}
@ -87,7 +88,7 @@ defmodule Dexcord.RegistrarIntegrationTest do
assert Registrar.run(config) == :ok
end)
assert_receive {:rest_hit, %{method: "GET", path: "/oauth2/applications/@me"}}
assert_receive {:rest_hit, %{method: "GET", path: "/applications/@me"}}
# The global-commands overwrite must NOT be attempted for an empty list.
refute_receive {:rest_hit, %{method: "PUT", path: "/applications/99/commands"}}

View file

@ -41,7 +41,7 @@ defmodule Dexcord.RegistrarTreeTest do
Application.put_env(:dexcord, :api_base_url, FakeRest.base_url())
FakeRest.subscribe(self())
FakeRest.stub(:get, "/oauth2/applications/@me", FakeRest.resp(200, body: ~s({"id":"1"})))
FakeRest.stub(:get, "/applications/@me", FakeRest.resp(200, body: ~s({"id":"1"})))
# Registration fails forever with a 4xx.
FakeRest.stub(:put, "/applications/1/commands", FakeRest.resp(403, body: "forbidden"))