Skip to content

Commit 01fa6e9

Browse files
committed
Add heartbeat menu item tests
1 parent 1097e3a commit 01fa6e9

File tree

7 files changed

+114
-18
lines changed

7 files changed

+114
-18
lines changed

src/Frontend/src/components/heartbeats/HeartbeatsMenuItem.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ const { failedHeartbeatsCount } = storeToRefs(useHeartbeatsStore());
88
</script>
99

1010
<template>
11-
<RouterLink :to="routeLinks.heartbeats.root">
11+
<RouterLink aria-label="Heartbeats Menu Item" :to="routeLinks.heartbeats.root">
1212
<i class="fa fa-heartbeat icon-white" title="Heartbeats"></i>
1313
<span class="navbar-label">Heartbeats</span>
14-
<span v-if="failedHeartbeatsCount > 0" class="badge badge-important">{{ failedHeartbeatsCount }}</span>
14+
<span v-if="failedHeartbeatsCount > 0" class="badge badge-important" aria-label="Alert Count">{{ failedHeartbeatsCount }}</span>
1515
</RouterLink>
1616
</template>
1717

src/Frontend/test/preconditions/hasHeartbeatEndpoints.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ export const hasHeartbeatsEndpoints =
1111
return endpoints;
1212
};
1313

14-
export const hasUnhealthyHeartbeatsEndpoints = (numberOfUnhealthyEndpoints: number = 1) => {
14+
export const hasUnhealthyHeartbeatsEndpoints = (numberOfUnhealthyEndpoints: number, endpointNamePrefix: string) => {
1515
const unhealthyEndpoints = [];
1616

1717
for (let i = 0; i < numberOfUnhealthyEndpoints; i++) {
1818
unhealthyEndpoints.push(<EndpointsView>{
1919
is_sending_heartbeats: true,
2020
id: "",
21-
name: `UnhealthyHeartbeatEndpoint_${i}`,
21+
name: `${endpointNamePrefix}_${i}`,
2222
monitor_heartbeat: true,
2323
host_display_name: "",
2424
heartbeat_information: { reported_status: EndpointStatus.Dead, last_report_at: "" },
@@ -28,4 +28,45 @@ export const hasUnhealthyHeartbeatsEndpoints = (numberOfUnhealthyEndpoints: numb
2828
return hasHeartbeatsEndpoints(unhealthyEndpoints);
2929
};
3030

31+
export const hasAnUnhealthyEndpoint = () => hasUnhealthyHeartbeatsEndpoints(1, "UnhealthyHeartbeatEndpoint");
32+
33+
export const hasUnhealthyEndpoints = (numberOfUnhealthyHeartbeats: number) => hasUnhealthyHeartbeatsEndpoints(numberOfUnhealthyHeartbeats, "UnhealthyHeartbeatEndpoint");
34+
35+
export const hasAnUnhealthyEndpointWithNamePrefix = (endpointNamePrefix: string) => hasUnhealthyHeartbeatsEndpoints(1, endpointNamePrefix);
36+
37+
export const hasHealthyHeartbeatsEndpoints = (numberOfHealthyEndpoints: number, endpointNamePrefix: string) => {
38+
const healthyEndpoints = [];
39+
40+
for (let i = 0; i < numberOfHealthyEndpoints; i++) {
41+
healthyEndpoints.push(<EndpointsView>{
42+
is_sending_heartbeats: true,
43+
id: "",
44+
name: `${endpointNamePrefix}_${i}`,
45+
monitor_heartbeat: true,
46+
host_display_name: "",
47+
heartbeat_information: { reported_status: EndpointStatus.Alive, last_report_at: "" },
48+
});
49+
}
50+
return hasHeartbeatsEndpoints(healthyEndpoints);
51+
};
52+
53+
export const hasAHealthyEndpoint = () => hasHealthyHeartbeatsEndpoints(1, "HealthyHeartbeatEndpoit");
54+
55+
export const hasHealthyEndpoints = (numberOfUnhealthyHeartbeats: number) => hasHealthyHeartbeatsEndpoints(numberOfUnhealthyHeartbeats, "HealthyHeartbeatEndpoint");
56+
57+
export const hasAHealthyEndpointWithNamePrefix = (endpointNamePrefix: string) => hasHealthyHeartbeatsEndpoints(1, endpointNamePrefix);
58+
3159
export const hasNoHeartbeatsEndpoints = hasHeartbeatsEndpoints([]);
60+
61+
export const hasAnUnhealthyUnMonitoredEndpoint = () => {
62+
return hasHeartbeatsEndpoints([
63+
<EndpointsView>{
64+
is_sending_heartbeats: true,
65+
id: "",
66+
name: `Unhealthy_UnmonitoredEndpoint`,
67+
monitor_heartbeat: true,
68+
host_display_name: "",
69+
heartbeat_information: { reported_status: EndpointStatus.Dead, last_report_at: "" },
70+
},
71+
]);
72+
};

src/Frontend/test/preconditions/hasServiceControlMainInstance.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { serviceControlMainInstance } from "../mocks/service-control-instance-te
22
import { SetupFactoryOptions } from "../driver";
33

44
export const hasServiceControlMainInstance =
5-
(serviceControlVersion = "5.0.4") =>
5+
(serviceControlVersion = "6.1.1") =>
66
({ driver }: SetupFactoryOptions) => {
77
const serviceControlInstanceUrl = window.defaultConfig.service_control_url;
88
driver.mockEndpoint(serviceControlInstanceUrl, {

src/Frontend/test/preconditions/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export { hasEventLogItems } from "../preconditions/hasEventLogItems";
1212
export { hasRecoverabilityGroups } from "../preconditions/hasEmptyRecoverabilityGroups";
1313
export * from "./hasEndpointsWithHistoryPeriodData";
1414
export * from "./hasMonitoredEndpointDetails";
15-
export { hasNoHeartbeatsEndpoints, hasHeartbeatsEndpoints, hasUnhealthyHeartbeatsEndpoints } from "../preconditions/hasHeartbeatEndpoints";
15+
export * from "../preconditions/hasHeartbeatEndpoints";
1616
export { serviceControlWithMonitoring } from "./serviceControlWithMonitoring";
1717
export * from "./recoverability";
1818
export { hasLicensingReportAvailable } from "../preconditions/hasLicensingReportAvailable";

src/Frontend/test/specs/heartbeats/dashboard-item.spec.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,28 @@
11
import { test, describe } from "../../drivers/vitest/driver";
22
import * as precondition from "../../preconditions";
3-
import { expect, vi } from "vitest";
3+
import { expect } from "vitest";
44
import { queryHeartbeatDashboardItem } from "./questions/queryHeartbeatDashboardItem";
55
import { waitFor } from "@testing-library/vue";
66

77
describe("FEATURE: Dashboard item", () => {
88
describe("RULE: The count of unhealthy endpoints should be displayed", () => {
99
test("EXAMPLE: No unhealthy endpoints.", async ({ driver }) => {
10-
vi.useFakeTimers();
1110
await driver.setUp(precondition.serviceControlWithMonitoring);
11+
await driver.setUp(precondition.hasAHealthyEndpoint());
1212

1313
await driver.goTo("dashboard");
1414

15-
vi.advanceTimersByTime(5000);
16-
const heartbeatDashboardItem = await queryHeartbeatDashboardItem();
17-
18-
// Reverse logic here to make sure the heartbeatDashboardItem is defined but the flag is falsey.
19-
expect(heartbeatDashboardItem && !heartbeatDashboardItem.isCounterVisible).toBeTruthy();
15+
await waitFor(async () => {
16+
const heartbeatDashboardItem = await queryHeartbeatDashboardItem();
2017

21-
vi.useRealTimers();
18+
// Reverse logic here to make sure the heartbeatDashboardItem is defined but the flag is falsey.
19+
expect(heartbeatDashboardItem && !heartbeatDashboardItem.isCounterVisible).toBeTruthy();
20+
});
2221
});
2322

2423
test("EXAMPLE: One unhealthy endpoint.", async ({ driver }) => {
2524
await driver.setUp(precondition.serviceControlWithMonitoring);
26-
await driver.setUp(precondition.hasUnhealthyHeartbeatsEndpoints());
25+
await driver.setUp(precondition.hasAnUnhealthyEndpoint());
2726

2827
await driver.goTo("dashboard");
2928

@@ -39,7 +38,7 @@ describe("FEATURE: Dashboard item", () => {
3938
const numberOfUnhealthyEndpoints = 3;
4039

4140
await driver.setUp(precondition.serviceControlWithMonitoring);
42-
await driver.setUp(precondition.hasUnhealthyHeartbeatsEndpoints(numberOfUnhealthyEndpoints));
41+
await driver.setUp(precondition.hasUnhealthyEndpoints(numberOfUnhealthyEndpoints));
4342

4443
await driver.goTo("dashboard");
4544

src/Frontend/test/specs/heartbeats/menu-item.spec.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,59 @@
1+
import { expect, vi } from "vitest";
12
import { test, describe } from "../../drivers/vitest/driver";
3+
import * as precondition from "../../preconditions";
4+
import { queryHeartbeatMenuItem } from "./questions/queryHeartbeatMenuItem";
5+
import { waitFor } from "@testing-library/vue";
26

37
describe("FEATURE: Menu item", () => {
48
describe("RULE: The count of inactive endpoints should be displayed in the navigation menu", () => {
5-
test.todo("EXAMPLE: An instance stops sending heartbeats, the menu item should show a badge with (1) of inactive endpoints");
9+
test("EXAMPLE: One unhealthy endpoint", async ({ driver }) => {
10+
await driver.setUp(precondition.serviceControlWithMonitoring);
11+
await driver.setUp(precondition.hasAnUnhealthyEndpoint());
12+
13+
await driver.goTo("dashboard");
14+
15+
await waitFor(async () => {
16+
const heartbeatMenuItem = await queryHeartbeatMenuItem();
17+
18+
expect(heartbeatMenuItem && heartbeatMenuItem.isCounterVisible).toBeTruthy();
19+
expect(heartbeatMenuItem && heartbeatMenuItem.counterValue).toBe(1);
20+
});
21+
});
622

723
/* SCENARIO
824
Given 5 monitored endpoint instances sending heartbeats
925
When 1 of the endpoint instances stops sending heartbeats
1026
Then the menu item in the page header updates to include a badge indicating how many have stopped
1127
*/
1228

13-
test.todo("EXAMPLE: An instance starts sending heartbeats, the menu item should remove the badge");
29+
test("EXAMPLE: An instance starts sending heartbeats, the menu item should remove the badge", async ({ driver }) => {
30+
vi.useFakeTimers();
31+
await driver.setUp(precondition.serviceControlWithMonitoring);
32+
await driver.setUp(precondition.hasAnUnhealthyEndpointWithNamePrefix("ResurrectingEndpoint"));
33+
34+
await driver.goTo("dashboard");
35+
36+
vi.advanceTimersByTime(5000);
37+
38+
await waitFor(async () => {
39+
const heartbeatMenuItem = await queryHeartbeatMenuItem();
40+
41+
expect(heartbeatMenuItem && heartbeatMenuItem.isCounterVisible).toBeTruthy();
42+
expect(heartbeatMenuItem && heartbeatMenuItem.counterValue).toBe(1);
43+
});
44+
45+
await driver.setUp(precondition.hasAHealthyEndpointWithNamePrefix("ResurrectingEndpoint"));
46+
vi.advanceTimersByTime(5000);
47+
48+
await waitFor(async () => {
49+
const heartbeatMenuItem = await queryHeartbeatMenuItem();
50+
51+
expect(heartbeatMenuItem && !heartbeatMenuItem.isCounterVisible).toBeTruthy();
52+
expect(heartbeatMenuItem && heartbeatMenuItem.counterValue).toBe(0);
53+
});
54+
55+
vi.restoreAllMocks();
56+
});
1457
/* SCENARIO
1558
Given a set of monitored endpoint instances
1659
When all instances are sending heartbeats
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { screen, within } from "@testing-library/vue";
2+
3+
export async function queryHeartbeatMenuItem() {
4+
const navBar = await screen.findByRole("navigation");
5+
const menuItem = await within(navBar).getByRole("link", { name: "Heartbeats Menu Item" });
6+
const counter = within(menuItem).queryByLabelText("Alert Count");
7+
8+
return {
9+
menuItemName: menuItem.ariaLabel,
10+
isCounterVisible: counter && true,
11+
counterValue: counter ? Number(counter.textContent) : 0,
12+
};
13+
}

0 commit comments

Comments
 (0)