fix(ui): refresh the Slack page after a connection test

- Revalidate the Slack path so the badge and last-checked date update
- Hide the decorative Slack icon from assistive technology
- Keep the Slack integration card a Server Component
- Match Slack error codes on own properties only
- Assert the callback redirects back to the integration page
This commit is contained in:
Pablo F.G
2026-08-18 09:23:40 +02:00
parent 37b3ae7d25
commit 8481a43fe3
5 changed files with 18 additions and 10 deletions
+1
View File
@@ -341,6 +341,7 @@ export const testIntegrationConnection = async (
revalidatePath("/integrations/amazon-s3");
revalidatePath("/integrations/aws-security-hub");
revalidatePath("/integrations/jira");
revalidatePath("/integrations/slack");
if ("error" in pollResult) {
return { success: false, error: pollResult.error };
@@ -760,8 +760,7 @@ export const SlackIcon: React.FC<IconSvgProps> = ({
...props
}) => (
<svg
aria-hidden="false"
aria-label="Slack logo"
aria-hidden="true"
fill="none"
focusable="false"
height={size || height}
@@ -15,20 +15,27 @@ import { SlackCallback } from "./slack-callback";
const COMPLETED_QUERY = "code=slack-code-1f4a&state=st-2f1c9d7a";
const { exchangeSlackOAuthCode, callbackQuery } = vi.hoisted(() => ({
exchangeSlackOAuthCode: vi.fn(),
callbackQuery: { value: "" },
}));
const { exchangeSlackOAuthCode, callbackQuery, routerReplace } = vi.hoisted(
() => ({
exchangeSlackOAuthCode: vi.fn(),
callbackQuery: { value: "" },
routerReplace: vi.fn(),
}),
);
vi.mock("@/actions/integrations/slack", () => ({ exchangeSlackOAuthCode }));
// One router across renders, so the redirect off the spent code is assertable.
const router = { replace: routerReplace };
vi.mock("next/navigation", () => ({
useRouter: () => ({ replace: vi.fn() }),
useRouter: () => router,
useSearchParams: () => new URLSearchParams(callbackQuery.value),
}));
beforeEach(() => {
callbackQuery.value = COMPLETED_QUERY;
routerReplace.mockClear();
});
const SPINNER_COPY = /Connecting your Slack workspace/;
@@ -94,6 +101,8 @@ describe("returning from Slack when the completion answers unexpectedly", () =>
expect(
screen.queryByRole("link", { name: /Back to Slack integration/ }),
).not.toBeInTheDocument();
// `replace`, not `push`: a back navigation must not remount onto the code.
expect(routerReplace).toHaveBeenCalledWith("/integrations/slack");
});
});
@@ -1,5 +1,3 @@
"use client";
import { SettingsIcon } from "lucide-react";
import Link from "next/link";
+2 -1
View File
@@ -77,7 +77,8 @@ export interface SlackApiFailure extends SlackErrorSource {
}
const isKnownCode = (code: string | null | undefined): code is SlackErrorCode =>
typeof code === "string" && code in SLACK_ERROR_MESSAGES;
typeof code === "string" &&
Object.prototype.hasOwnProperty.call(SLACK_ERROR_MESSAGES, code);
/**
* Copy for a refusal: Prowler's wording for a known `code`, else the API's