Openstatus
www.openstatus.dev
1/** @jsxImportSource react */
2
3import { describe, expect, test } from "bun:test";
4import { render } from "@react-email/render";
5import StatusReportEmail from "../emails/status-report";
6
7describe("Status Report Email - Unsubscribe Link in Body", () => {
8 const unsubscribeUrl =
9 "https://openstatus.openstatus.dev/unsubscribe/test-token";
10
11 test("should include unsubscribe link in email body when URL is provided", async () => {
12 const html = await render(
13 <StatusReportEmail
14 pageTitle="Test Page"
15 reportTitle="Test Report"
16 status="investigating"
17 date={new Date().toISOString()}
18 message="Test message"
19 monitors={["Monitor 1"]}
20 unsubscribeUrl={unsubscribeUrl}
21 />,
22 );
23
24 expect(html).toContain(unsubscribeUrl);
25 expect(html).toContain("Unsubscribe");
26 });
27
28 test("should not include unsubscribe section when URL is not provided", async () => {
29 const html = await render(
30 <StatusReportEmail
31 pageTitle="Test Page"
32 reportTitle="Test Report"
33 status="investigating"
34 date={new Date().toISOString()}
35 message="Test message"
36 monitors={["Monitor 1"]}
37 />,
38 );
39
40 // Should not contain the unsubscribe text when no URL provided
41 expect(html).not.toContain("from these notifications");
42 });
43
44 test("should render unsubscribe link as clickable", async () => {
45 const html = await render(
46 <StatusReportEmail
47 pageTitle="Test Page"
48 reportTitle="Test Report"
49 status="investigating"
50 date={new Date().toISOString()}
51 message="Test message"
52 monitors={["Monitor 1"]}
53 unsubscribeUrl={unsubscribeUrl}
54 />,
55 );
56
57 // Check that the URL is in an href attribute
58 expect(html).toContain(`href="${unsubscribeUrl}"`);
59 });
60
61 test("should display unsubscribe link with proper styling", async () => {
62 const html = await render(
63 <StatusReportEmail
64 pageTitle="Test Page"
65 reportTitle="Test Report"
66 status="investigating"
67 date={new Date().toISOString()}
68 message="Test message"
69 monitors={["Monitor 1"]}
70 unsubscribeUrl={unsubscribeUrl}
71 />,
72 );
73
74 // Check for muted styling (gray color for footer)
75 expect(html).toContain("#6b7280");
76 });
77});
78
79describe("Status Report Email - Email Content Validation", () => {
80 test("should include all required email fields", async () => {
81 const props = {
82 pageTitle: "OpenStatus",
83 reportTitle: "API Outage",
84 status: "investigating" as const,
85 date: "2024-01-15T10:00:00.000Z",
86 message: "We are investigating the issue",
87 monitors: ["API", "Web"],
88 unsubscribeUrl: "https://openstatus.openstatus.dev/unsubscribe/test",
89 };
90
91 const html = await render(<StatusReportEmail {...props} />);
92
93 expect(html).toContain(props.pageTitle);
94 expect(html).toContain(props.reportTitle);
95 expect(html).toContain(props.message);
96 expect(html).toContain("API");
97 expect(html).toContain("Web");
98 expect(html).toContain(props.unsubscribeUrl);
99 });
100
101 test("should handle all status types correctly", async () => {
102 const statuses = [
103 "investigating",
104 "identified",
105 "monitoring",
106 "resolved",
107 "maintenance",
108 ] as const;
109
110 for (const status of statuses) {
111 const html = await render(
112 <StatusReportEmail
113 pageTitle="Test"
114 reportTitle="Test Report"
115 status={status}
116 date={new Date().toISOString()}
117 message="Test"
118 monitors={[]}
119 unsubscribeUrl="https://example.com/unsubscribe"
120 />,
121 );
122
123 // Should render without errors and contain the status
124 // Note: status is rendered lowercase in HTML with text-transform: uppercase CSS
125 expect(html).toContain(status);
126 }
127 });
128});