mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-11-27 08:44:04 +00:00
component testing
This commit is contained in:
parent
fe09beaf6a
commit
7855dd97a5
7 changed files with 1471 additions and 2 deletions
21
config/vitest.config.js
Normal file
21
config/vitest.config.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { defineConfig } from 'vite';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, resolve } from 'path';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
setupFiles: ['./test/component/setup.js'],
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve(__dirname, '../src'),
|
||||
},
|
||||
},
|
||||
});
|
1159
package-lock.json
generated
1159
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -30,6 +30,7 @@
|
|||
"test-backend": "cross-env TEST_BACKEND=1 node --test test/backend-test",
|
||||
"test-e2e": "playwright test --config ./config/playwright.config.js",
|
||||
"test-e2e-ui": "playwright test --config ./config/playwright.config.js --ui --ui-port=51063",
|
||||
"test-component": "vitest --config ./config/vitest.config.js",
|
||||
"playwright-codegen": "playwright codegen localhost:3000 --save-storage=./private/e2e-auth.json",
|
||||
"playwright-show-report": "playwright show-report ./private/playwright-report",
|
||||
"tsc": "tsc",
|
||||
|
@ -152,12 +153,14 @@
|
|||
"@popperjs/core": "~2.10.2",
|
||||
"@testcontainers/hivemq": "^10.13.1",
|
||||
"@testcontainers/rabbitmq": "^10.13.2",
|
||||
"@testing-library/vue": "^8.1.0",
|
||||
"@types/bootstrap": "~5.1.9",
|
||||
"@types/node": "^20.8.6",
|
||||
"@typescript-eslint/eslint-plugin": "^6.7.5",
|
||||
"@typescript-eslint/parser": "^6.7.5",
|
||||
"@vitejs/plugin-vue": "~5.0.1",
|
||||
"@vue/compiler-sfc": "~3.4.2",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"@vuepic/vue-datepicker": "~3.4.8",
|
||||
"aedes": "^0.46.3",
|
||||
"bootstrap": "5.1.3",
|
||||
|
@ -175,6 +178,7 @@
|
|||
"eslint-plugin-vue": "~8.7.1",
|
||||
"favico.js": "~0.3.10",
|
||||
"get-port-please": "^3.1.1",
|
||||
"jsdom": "^25.0.1",
|
||||
"node-ssh": "~13.1.0",
|
||||
"postcss-html": "~1.5.0",
|
||||
"postcss-rtlcss": "~3.7.2",
|
||||
|
@ -193,6 +197,7 @@
|
|||
"vite": "~5.2.8",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-vue-devtools": "^7.0.15",
|
||||
"vitest": "^2.1.5",
|
||||
"vue": "~3.4.2",
|
||||
"vue-chartjs": "~5.2.0",
|
||||
"vue-confirm-dialog": "~1.0.2",
|
||||
|
|
100
test/component/MonitorList.spec.js
Normal file
100
test/component/MonitorList.spec.js
Normal file
|
@ -0,0 +1,100 @@
|
|||
import { describe, it, expect, beforeEach, vi } from "vitest";
|
||||
import { mount } from "@vue/test-utils";
|
||||
import MonitorList from "../../src/components/MonitorList.vue";
|
||||
import MonitorListItem from "../../src/components/MonitorListItem.vue";
|
||||
|
||||
// Mock child components
|
||||
vi.mock("../../src/components/MonitorListItem.vue", {
|
||||
default: {
|
||||
name: "MonitorListItem",
|
||||
template: "<div class=\"monitor-list-item\"></div>"
|
||||
}
|
||||
});
|
||||
|
||||
describe("MonitorList.vue", () => {
|
||||
let wrapper;
|
||||
const mockMonitors = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Test Monitor 1",
|
||||
type: "http",
|
||||
status: "up",
|
||||
url: "https://example.com"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Test Monitor 2",
|
||||
type: "ping",
|
||||
status: "down",
|
||||
hostname: "example.org"
|
||||
}
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = mount(MonitorList, {
|
||||
props: {
|
||||
monitors: mockMonitors,
|
||||
activeMonitor: null,
|
||||
showTags: true,
|
||||
showStatus: true,
|
||||
showPing: true,
|
||||
showAverage: true
|
||||
},
|
||||
global: {
|
||||
stubs: {
|
||||
MonitorListItem: true
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("renders monitor list items", () => {
|
||||
const items = wrapper.findAllComponents(MonitorListItem);
|
||||
expect(items).toHaveLength(mockMonitors.length);
|
||||
});
|
||||
|
||||
it("emits select-monitor event when monitor is clicked", async () => {
|
||||
const items = wrapper.findAll(".monitor-list-item");
|
||||
await items[0].trigger("click");
|
||||
|
||||
expect(wrapper.emitted("select-monitor")).toBeTruthy();
|
||||
expect(wrapper.emitted("select-monitor")[0]).toEqual([mockMonitors[0]]);
|
||||
});
|
||||
|
||||
it("applies active class to selected monitor", async () => {
|
||||
await wrapper.setProps({
|
||||
activeMonitor: mockMonitors[0]
|
||||
});
|
||||
|
||||
const items = wrapper.findAll(".monitor-list-item");
|
||||
expect(items[0].classes()).toContain("active");
|
||||
expect(items[1].classes()).not.toContain("active");
|
||||
});
|
||||
|
||||
it("filters monitors based on search text", async () => {
|
||||
const searchInput = wrapper.find("input[type=\"search\"]");
|
||||
await searchInput.setValue("Test Monitor 1");
|
||||
|
||||
const items = wrapper.findAllComponents(MonitorListItem);
|
||||
expect(items).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("sorts monitors by status", async () => {
|
||||
const sortButton = wrapper.find(".sort-status");
|
||||
await sortButton.trigger("click");
|
||||
|
||||
const items = wrapper.findAllComponents(MonitorListItem);
|
||||
const firstMonitorProps = items[0].props();
|
||||
expect(firstMonitorProps.monitor.status).toBe("down");
|
||||
});
|
||||
|
||||
it("toggles visibility of columns", async () => {
|
||||
await wrapper.setProps({
|
||||
showPing: false,
|
||||
showAverage: false
|
||||
});
|
||||
|
||||
expect(wrapper.find(".ping-column").exists()).toBe(false);
|
||||
expect(wrapper.find(".average-column").exists()).toBe(false);
|
||||
});
|
||||
});
|
114
test/component/PingChart.spec.js
Normal file
114
test/component/PingChart.spec.js
Normal file
|
@ -0,0 +1,114 @@
|
|||
import { describe, it, expect, beforeEach, vi } from "vitest";
|
||||
import { mount } from "@vue/test-utils";
|
||||
import PingChart from "../../src/components/PingChart.vue";
|
||||
import { Line } from "vue-chartjs";
|
||||
|
||||
// Mock Chart.js components
|
||||
vi.mock("vue-chartjs", () => ({
|
||||
Line: {
|
||||
name: "Line",
|
||||
template: "<canvas></canvas>"
|
||||
}
|
||||
}));
|
||||
|
||||
describe("PingChart.vue", () => {
|
||||
let wrapper;
|
||||
const mockData = {
|
||||
labels: ["12:00", "12:01", "12:02"],
|
||||
datasets: [{
|
||||
label: "Ping",
|
||||
data: [100, 150, 120],
|
||||
borderColor: "#42b983",
|
||||
tension: 0.3
|
||||
}]
|
||||
};
|
||||
|
||||
const mockOptions = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: "Response Time (ms)"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = mount(PingChart, {
|
||||
props: {
|
||||
chartData: mockData,
|
||||
options: mockOptions
|
||||
},
|
||||
global: {
|
||||
stubs: {
|
||||
Line: true
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("renders the chart component", () => {
|
||||
expect(wrapper.findComponent(Line).exists()).toBe(true);
|
||||
});
|
||||
|
||||
it("passes correct data to chart component", () => {
|
||||
const chart = wrapper.findComponent(Line);
|
||||
expect(chart.props("data")).toEqual(mockData);
|
||||
});
|
||||
|
||||
it("passes correct options to chart component", () => {
|
||||
const chart = wrapper.findComponent(Line);
|
||||
expect(chart.props("options")).toEqual(mockOptions);
|
||||
});
|
||||
|
||||
it("updates chart when data changes", async () => {
|
||||
const newData = {
|
||||
labels: ["12:03", "12:04"],
|
||||
datasets: [{
|
||||
label: "Ping",
|
||||
data: [130, 140],
|
||||
borderColor: "#42b983",
|
||||
tension: 0.3
|
||||
}]
|
||||
};
|
||||
|
||||
await wrapper.setProps({ chartData: newData });
|
||||
const chart = wrapper.findComponent(Line);
|
||||
expect(chart.props("data")).toEqual(newData);
|
||||
});
|
||||
|
||||
it("handles empty data gracefully", async () => {
|
||||
const emptyData = {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: "Ping",
|
||||
data: [],
|
||||
borderColor: "#42b983",
|
||||
tension: 0.3
|
||||
}]
|
||||
};
|
||||
|
||||
await wrapper.setProps({ chartData: emptyData });
|
||||
const chart = wrapper.findComponent(Line);
|
||||
expect(chart.props("data")).toEqual(emptyData);
|
||||
});
|
||||
|
||||
it("applies custom styling options", async () => {
|
||||
const customOptions = {
|
||||
...mockOptions,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await wrapper.setProps({ options: customOptions });
|
||||
const chart = wrapper.findComponent(Line);
|
||||
expect(chart.props("options")).toEqual(customOptions);
|
||||
});
|
||||
});
|
52
test/component/Status.spec.js
Normal file
52
test/component/Status.spec.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
import { describe, it, expect } from "vitest";
|
||||
import { mount } from "@vue/test-utils";
|
||||
import Status from "../../src/components/Status.vue";
|
||||
import { UP, DOWN, PENDING, MAINTENANCE } from "../../src/util";
|
||||
|
||||
describe("Status.vue", () => {
|
||||
const mountStatus = (status) => {
|
||||
return mount(Status, {
|
||||
props: {
|
||||
status
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
it("renders UP status correctly", () => {
|
||||
const wrapper = mountStatus(UP);
|
||||
expect(wrapper.find(".badge").classes()).toContain("bg-success");
|
||||
expect(wrapper.text()).toContain("UP");
|
||||
});
|
||||
|
||||
it("renders DOWN status correctly", () => {
|
||||
const wrapper = mountStatus(DOWN);
|
||||
expect(wrapper.find(".badge").classes()).toContain("bg-danger");
|
||||
expect(wrapper.text()).toContain("DOWN");
|
||||
});
|
||||
|
||||
it("renders PENDING status correctly", () => {
|
||||
const wrapper = mountStatus(PENDING);
|
||||
expect(wrapper.find(".badge").classes()).toContain("bg-warning");
|
||||
expect(wrapper.text()).toContain("PENDING");
|
||||
});
|
||||
|
||||
it("renders MAINTENANCE status correctly", () => {
|
||||
const wrapper = mountStatus(MAINTENANCE);
|
||||
expect(wrapper.find(".badge").classes()).toContain("bg-info");
|
||||
expect(wrapper.text()).toContain("MAINTENANCE");
|
||||
});
|
||||
|
||||
it("handles unknown status gracefully", () => {
|
||||
const wrapper = mountStatus("UNKNOWN");
|
||||
expect(wrapper.find(".badge").classes()).toContain("bg-secondary");
|
||||
expect(wrapper.text()).toContain("UNKNOWN");
|
||||
});
|
||||
|
||||
it("updates when status prop changes", async () => {
|
||||
const wrapper = mountStatus(UP);
|
||||
expect(wrapper.find(".badge").classes()).toContain("bg-success");
|
||||
|
||||
await wrapper.setProps({ status: DOWN });
|
||||
expect(wrapper.find(".badge").classes()).toContain("bg-danger");
|
||||
});
|
||||
});
|
22
test/component/setup.js
Normal file
22
test/component/setup.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { config } from "@vue/test-utils";
|
||||
import { vi } from "vitest";
|
||||
|
||||
// Setup global mocks
|
||||
vi.mock("vue-i18n", () => ({
|
||||
useI18n: () => ({
|
||||
t: (key) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
// Global components mock
|
||||
config.global.stubs = {
|
||||
"font-awesome-icon": true,
|
||||
};
|
||||
|
||||
// Global mounting options
|
||||
config.global.mocks = {
|
||||
$t: (key) => key,
|
||||
$filters: {
|
||||
formatDateTime: vi.fn((date) => date.toString()),
|
||||
},
|
||||
};
|
Loading…
Reference in a new issue