mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-29 14:54:30 +00:00
122 lines
3.7 KiB
TypeScript
122 lines
3.7 KiB
TypeScript
/**
|
|
* The Slack double's own writes, driven over HTTP because the page cannot
|
|
* navigate to every state a connection check leaves behind. A double serving a
|
|
* state the API cannot produce lets a UI test prove copy no deployment shows.
|
|
*/
|
|
|
|
import { setupServer } from "msw/node";
|
|
import { afterAll, afterEach, beforeAll, describe, expect, it } from "vitest";
|
|
|
|
import { handlersForSlack } from "./slack";
|
|
import {
|
|
SLACK_INTEGRATION_ID,
|
|
SLACK_NOT_IN_CHANNEL_CODE,
|
|
SLACK_PRIVATE_CHANNEL,
|
|
SLACK_PUBLIC_CHANNEL,
|
|
SLACK_TOKEN_REVOKED_CODE,
|
|
unconfirmedChannelsSlackFixture,
|
|
} from "./slack.fixtures";
|
|
import type { SlackConnectionFixture } from "./slack.fixtures";
|
|
|
|
const API = process.env.UI_API_BASE_URL;
|
|
|
|
/** Re-declared, not imported from product code, so a rename fails here. */
|
|
interface ChannelBody {
|
|
id: string;
|
|
confirmation_sent_at: string | null;
|
|
}
|
|
|
|
const server = setupServer();
|
|
|
|
beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
|
|
afterEach(() => server.resetHandlers());
|
|
afterAll(() => server.close());
|
|
|
|
/** The poll is what writes, so the read has to follow it. */
|
|
const runConnectionCheck = async (connection: SlackConnectionFixture) => {
|
|
server.use(
|
|
...handlersForSlack(
|
|
unconfirmedChannelsSlackFixture(
|
|
[SLACK_PUBLIC_CHANNEL, SLACK_PRIVATE_CHANNEL],
|
|
{ connection },
|
|
),
|
|
),
|
|
);
|
|
|
|
const queued = await fetch(
|
|
`${API}/integrations/${SLACK_INTEGRATION_ID}/connection`,
|
|
{ method: "POST" },
|
|
);
|
|
expect(queued.status).toBe(202);
|
|
const { data: task } = (await queued.json()) as { data: { id: string } };
|
|
|
|
const polled = await fetch(`${API}/tasks/${task.id}`);
|
|
expect(polled.status).toBe(200);
|
|
|
|
const listed = await fetch(
|
|
`${API}/integrations?filter[integration_type]=slack`,
|
|
);
|
|
const { data } = (await listed.json()) as {
|
|
data: {
|
|
attributes: {
|
|
connected: boolean | null;
|
|
configuration: { channels: ChannelBody[] };
|
|
};
|
|
}[];
|
|
};
|
|
|
|
const { connected: recorded, configuration } = data[0].attributes;
|
|
return {
|
|
connected: recorded,
|
|
confirmedAt: new Map(
|
|
configuration.channels.map((channel) => [
|
|
channel.id,
|
|
channel.confirmation_sent_at,
|
|
]),
|
|
),
|
|
};
|
|
};
|
|
|
|
describe("the Slack double's connection check", () => {
|
|
it("confirms no channel at all when the failure is about the workspace", async () => {
|
|
// Given/When — a revoked grant, which `auth.test` finds before the
|
|
// per-channel loop, so the failure names no channel.
|
|
const { connected, confirmedAt } = await runConnectionCheck({
|
|
connected: false,
|
|
error: SLACK_TOKEN_REVOKED_CODE,
|
|
});
|
|
|
|
// Then
|
|
expect(connected).toBe(false);
|
|
expect(confirmedAt.get(SLACK_PUBLIC_CHANNEL.id)).toBeNull();
|
|
expect(confirmedAt.get(SLACK_PRIVATE_CHANNEL.id)).toBeNull();
|
|
});
|
|
|
|
it("confirms every channel but the one a channel-level failure names", async () => {
|
|
// Given/When — the token is fine and Slack refuses one channel of the set.
|
|
const { connected, confirmedAt } = await runConnectionCheck({
|
|
connected: false,
|
|
error: SLACK_NOT_IN_CHANNEL_CODE,
|
|
failedChannelId: SLACK_PRIVATE_CHANNEL.id,
|
|
});
|
|
|
|
// Then — the refused channel is the retry's remaining work.
|
|
expect(connected).toBe(false);
|
|
expect(confirmedAt.get(SLACK_PUBLIC_CHANNEL.id)).not.toBeNull();
|
|
expect(confirmedAt.get(SLACK_PRIVATE_CHANNEL.id)).toBeNull();
|
|
});
|
|
|
|
it("confirms the whole set when the check succeeds", async () => {
|
|
// Given/When
|
|
const { connected, confirmedAt } = await runConnectionCheck({
|
|
connected: true,
|
|
error: null,
|
|
});
|
|
|
|
// Then
|
|
expect(connected).toBe(true);
|
|
expect(confirmedAt.get(SLACK_PUBLIC_CHANNEL.id)).not.toBeNull();
|
|
expect(confirmedAt.get(SLACK_PRIVATE_CHANNEL.id)).not.toBeNull();
|
|
});
|
|
});
|