component testing

This commit is contained in:
Zaid-maker 2024-11-20 18:48:13 +05:00
parent fe09beaf6a
commit 7855dd97a5
7 changed files with 1471 additions and 2 deletions

21
config/vitest.config.js Normal file
View 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

File diff suppressed because it is too large Load diff

View file

@ -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",

View 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);
});
});

View 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);
});
});

View 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
View 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()),
},
};