fix(ui): keep the Slack page usable on an unreadable check time

- Guard the last-checked timestamp with isValid before formatting
- Fall back to the never-checked rendering instead of the error boundary
This commit is contained in:
Pablo F.G
2026-08-18 09:23:40 +02:00
parent 68f1092f56
commit 434e5aaf03
4 changed files with 61 additions and 17 deletions
+21 -9
View File
@@ -193,6 +193,17 @@ export const connectedSlackFixture = (
...overrides,
});
const configuredInstall = (): SlackInstallFixture => ({
id: SLACK_INTEGRATION_ID,
connected: true,
connectionLastCheckedAt: "2026-08-10T09:30:00Z",
workspace: {
...PROWLER_HQ,
channelId: SLACK_DEFAULT_CHANNEL.id,
channelName: SLACK_DEFAULT_CHANNEL.name,
},
});
/**
* A workspace connected *and* a channel on record. Anything the API refuses
* until a channel exists (the connection check) needs this fixture.
@@ -200,16 +211,17 @@ export const connectedSlackFixture = (
export const configuredSlackFixture = (
overrides: Partial<SlackFixture> = {},
): SlackFixture =>
connectedSlackFixture({ install: configuredInstall(), ...overrides });
/**
* The same finished setup, with a check time no parser can read: a zero date
* from a bad write or a serializer change. The contract types the attribute as
* a string and rules nothing else out.
*/
export const unreadableCheckTimeSlackFixture = (): SlackFixture =>
connectedSlackFixture({
install: {
id: SLACK_INTEGRATION_ID,
connected: true,
connectionLastCheckedAt: "2026-08-10T09:30:00Z",
workspace: {
...PROWLER_HQ,
channelId: SLACK_DEFAULT_CHANNEL.id,
channelName: SLACK_DEFAULT_CHANNEL.name,
},
...configuredInstall(),
connectionLastCheckedAt: "0000-00-00T00:00:00Z",
},
...overrides,
});
@@ -240,6 +240,17 @@ export class SlackIntegrationHarness extends BrowserHarness<SlackFixture> {
return this.containsText(/Choosing a destination channel is the next step/);
}
/**
* The "last checked" line as rendered, or null when the page shows none —
* which is what a workspace whose connection was never checked shows.
*/
lastCheckedLine(): string | null {
const line = Array.from(
this.container.querySelectorAll<HTMLElement>("p"),
).find((p) => /^Last checked:/.test((p.textContent ?? "").trim()));
return line ? (line.textContent ?? "").trim() : null;
}
async testConnection(): Promise<ConnectionOutcome> {
await this.clickButton(/Test connection/);
@@ -13,6 +13,7 @@ import {
connectedSlackFixture,
INTEGRATIONS_SERVER_ERROR_DETAIL,
slackFixture,
unreadableCheckTimeSlackFixture,
} from "@/__tests__/msw/handlers/slack.fixtures";
import {
@@ -190,6 +191,23 @@ describe("a connected workspace", () => {
expect(badge).not.toMatch(/Disconnected/);
}, 30000);
it("keeps the page usable when the recorded check time is one no parser can read", async () => {
// Given — a finished setup whose `connection_last_checked_at` is a zero
// date. `date-fns` throws a RangeError on it, which would replace the whole
// page with the route's error boundary.
const harness = new SlackIntegrationHarness(
unreadableCheckTimeSlackFixture(),
);
await harness.mount();
expect(await harness.connectedWorkspaceName()).toBe(WORKSPACE_NAME);
expect(await harness.connectionBadge()).toBe("Connected");
// Nothing to show, so nothing is shown: the same line a workspace that was
// never checked renders.
expect(harness.lastCheckedLine()).toBeNull();
}, 30000);
it("does not offer a connection check the API is bound to refuse", async () => {
// Given — a workspace connected and no destination channel recorded.
const harness = new SlackIntegrationHarness(connectedSlackFixture());
@@ -1,6 +1,6 @@
"use client";
import { format } from "date-fns";
import { format, isValid, parseISO } from "date-fns";
import { TestTube } from "lucide-react";
import { useState } from "react";
@@ -73,6 +73,14 @@ export const SlackIntegrationManager = ({
// Absent until a channel is chosen, never present-and-null.
const channelId = configuration?.channel_id ?? null;
const checkedAt = integration?.attributes.connection_last_checked_at;
const checkedOn = checkedAt ? parseISO(checkedAt) : null;
// `format` throws a RangeError on an unreadable value, which would replace
// the page with the route's error boundary: show nothing instead, as for a
// connection that was never checked.
const lastCheckedOn =
checkedOn && isValid(checkedOn) ? format(checkedOn, "yyyy/MM/dd") : null;
return (
<div className="flex flex-col gap-6">
{rateLimitMessage && (
@@ -118,15 +126,10 @@ export const SlackIntegrationManager = ({
<CardContent className="pt-0">
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="text-xs text-gray-500 dark:text-gray-300">
{integration.attributes.connection_last_checked_at && (
{lastCheckedOn && (
<p>
<span className="font-medium">Last checked:</span>{" "}
{format(
new Date(
integration.attributes.connection_last_checked_at,
),
"yyyy/MM/dd",
)}
{lastCheckedOn}
</p>
)}
{!channelId && (