137 lines
4.5 KiB
TypeScript
137 lines
4.5 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
type MetricServiceMocks = {
|
|
metricLogGroupBy: ReturnType<typeof vi.fn>;
|
|
adminGetAllTenantsIdsAndNames: ReturnType<typeof vi.fn>;
|
|
adminGetAllUsersNames: ReturnType<typeof vi.fn>;
|
|
};
|
|
|
|
function getMocks(): MetricServiceMocks {
|
|
const store = globalThis as typeof globalThis & { __metricServiceMocks__?: MetricServiceMocks };
|
|
store.__metricServiceMocks__ ??= {
|
|
metricLogGroupBy: vi.fn(),
|
|
adminGetAllTenantsIdsAndNames: vi.fn(),
|
|
adminGetAllUsersNames: vi.fn(),
|
|
};
|
|
return store.__metricServiceMocks__;
|
|
}
|
|
|
|
vi.mock("~/utils/db.server", () => ({
|
|
db: {
|
|
metricLog: {
|
|
groupBy: getMocks().metricLogGroupBy,
|
|
},
|
|
},
|
|
}));
|
|
|
|
vi.mock("~/utils/db/tenants.db.server", () => ({
|
|
adminGetAllTenantsIdsAndNames: getMocks().adminGetAllTenantsIdsAndNames,
|
|
}));
|
|
|
|
vi.mock("~/utils/db/users.db.server", () => ({
|
|
adminGetAllUsersNames: getMocks().adminGetAllUsersNames,
|
|
}));
|
|
|
|
import MetricService from "./MetricService";
|
|
|
|
const mocks = getMocks();
|
|
|
|
function createDeferred<T>() {
|
|
let resolve!: (value: T) => void;
|
|
const promise = new Promise<T>((promiseResolve) => {
|
|
resolve = promiseResolve;
|
|
});
|
|
return { promise, resolve };
|
|
}
|
|
|
|
describe("MetricService filters", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
mocks.metricLogGroupBy
|
|
.mockResolvedValueOnce([{ route: "/app", _count: { route: 3 } }])
|
|
.mockResolvedValueOnce([{ url: "https://app.example.test/app", _count: { url: 2 } }])
|
|
.mockResolvedValueOnce([{ function: "loader", _count: { function: 5 } }]);
|
|
mocks.adminGetAllTenantsIdsAndNames.mockResolvedValue([]);
|
|
mocks.adminGetAllUsersNames.mockResolvedValue([]);
|
|
});
|
|
|
|
it("returns translation keys for static visible metric filter labels", async () => {
|
|
const { filterableProperties } = await MetricService.getFilters({
|
|
request: new Request("https://admin.example.test/admin/metrics"),
|
|
});
|
|
|
|
expect(filterableProperties.find((filter) => filter.name === "env")).toMatchObject({
|
|
title: "admin.metrics.columns.env",
|
|
options: [
|
|
{ name: "shared.environments.production", value: "production" },
|
|
{ name: "shared.environments.staging", value: "staging" },
|
|
{ name: "shared.environments.development", value: "development" },
|
|
],
|
|
});
|
|
expect(filterableProperties.find((filter) => filter.name === "type")).toMatchObject({
|
|
title: "admin.metrics.columns.type",
|
|
options: [
|
|
{ name: "admin.metrics.types.loader", value: "loader" },
|
|
{ name: "admin.metrics.types.action", value: "action" },
|
|
],
|
|
});
|
|
expect(filterableProperties.find((filter) => filter.name === "function")).toMatchObject({
|
|
title: "admin.metrics.columns.function",
|
|
});
|
|
});
|
|
|
|
it("runs independent metric filter group queries together with a bounded result size", async () => {
|
|
const routeGroupBy = createDeferred([{ route: "/app", _count: { route: 3 } }]);
|
|
const urlGroupBy = createDeferred([{ url: "https://app.example.test/app", _count: { url: 2 } }]);
|
|
const functionGroupBy = createDeferred([{ function: "loader", _count: { function: 5 } }]);
|
|
|
|
mocks.metricLogGroupBy
|
|
.mockReset()
|
|
.mockReturnValueOnce(routeGroupBy.promise)
|
|
.mockReturnValueOnce(urlGroupBy.promise)
|
|
.mockReturnValueOnce(functionGroupBy.promise);
|
|
|
|
const filtersPromise = MetricService.getFilters({
|
|
request: new Request("https://admin.example.test/admin/metrics"),
|
|
});
|
|
|
|
await Promise.resolve();
|
|
|
|
expect(mocks.metricLogGroupBy).toHaveBeenCalledTimes(3);
|
|
expect(mocks.metricLogGroupBy).toHaveBeenNthCalledWith(
|
|
1,
|
|
expect.objectContaining({
|
|
by: ["route"],
|
|
take: 200,
|
|
})
|
|
);
|
|
expect(mocks.metricLogGroupBy).toHaveBeenNthCalledWith(
|
|
2,
|
|
expect.objectContaining({
|
|
by: ["url"],
|
|
take: 200,
|
|
})
|
|
);
|
|
expect(mocks.metricLogGroupBy).toHaveBeenNthCalledWith(
|
|
3,
|
|
expect.objectContaining({
|
|
by: ["function"],
|
|
take: 200,
|
|
})
|
|
);
|
|
|
|
routeGroupBy.resolve([{ route: "/app", _count: { route: 3 } }]);
|
|
urlGroupBy.resolve([{ url: "https://app.example.test/app", _count: { url: 2 } }]);
|
|
functionGroupBy.resolve([{ function: "loader", _count: { function: 5 } }]);
|
|
|
|
await expect(filtersPromise).resolves.toMatchObject({
|
|
filterableProperties: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
name: "route",
|
|
options: [{ name: "/app (3)", value: "/app" }],
|
|
}),
|
|
]),
|
|
});
|
|
});
|
|
});
|