-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
aa995ea
commit 1d13565
Showing
5 changed files
with
603 additions
and
914 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
// @vitest-environment jsdom | ||
|
||
import { ReactNode } from "react"; | ||
import { describe, test, expect, beforeEach, vi, afterEach } from "vitest"; | ||
import { render, waitFor, screen } from "@testing-library/react"; | ||
import { loader, TimeSeriesCard } from "../resources.timeseries"; | ||
import * as RemixReact from "@remix-run/react"; | ||
import "vitest-dom/extend-expect"; | ||
import { getDefaultContext } from "./testutils"; | ||
|
||
// Mock the useFetcher hook | ||
vi.mock("@remix-run/react", async () => { | ||
const actual = await vi.importActual("@remix-run/react"); | ||
return { | ||
...actual, | ||
useFetcher: vi.fn(), | ||
}; | ||
}); | ||
|
||
describe("resources.timeseries loader", () => { | ||
const { context } = getDefaultContext(); | ||
|
||
beforeEach(() => { | ||
vi.spyOn( | ||
context.analyticsEngine, | ||
"getViewsGroupedByInterval", | ||
).mockResolvedValue([ | ||
["2024-01-15T00:00:00Z", 100], | ||
["2024-01-16T00:00:00Z", 200], | ||
]); | ||
|
||
// mock out responsive container to just return a standard div, otherwise | ||
// recharts doesnt render underneath | ||
vi.mock("recharts", async () => { | ||
const OriginalModule = await vi.importActual("recharts"); | ||
return { | ||
...OriginalModule, | ||
ResponsiveContainer: ({ | ||
children, | ||
}: { | ||
children: ReactNode; | ||
}) => <div>{children}</div>, | ||
}; | ||
}); | ||
}); | ||
|
||
afterEach(() => { | ||
vi.restoreAllMocks(); | ||
}); | ||
|
||
test("processes data correctly", async () => { | ||
const request = new Request( | ||
"http://test.com?interval=7d&site=test-site&timezone=UTC", | ||
); | ||
const result = await loader({ | ||
// @ts-expect-error we don't need to provide all the properties of the contextobject | ||
context, | ||
request, | ||
}); | ||
|
||
const data = await result.json(); | ||
expect(data.chartData).toEqual([ | ||
{ date: "2024-01-15T00:00:00Z", views: 100 }, | ||
{ date: "2024-01-16T00:00:00Z", views: 200 }, | ||
]); | ||
expect(data.intervalType).toBe("DAY"); | ||
|
||
expect( | ||
context.analyticsEngine.getViewsGroupedByInterval, | ||
).toHaveBeenCalledWith( | ||
"test-site", | ||
"DAY", | ||
expect.any(Date), | ||
expect.any(Date), | ||
"UTC", | ||
{}, | ||
); | ||
}); | ||
}); | ||
|
||
describe("TimeSeriesCard", () => { | ||
const mockFetcher = { | ||
submit: vi.fn(), | ||
data: { | ||
chartData: [ | ||
{ date: "2024-01-15T00:00:00Z", views: 100 }, | ||
{ date: "2024-01-16T00:00:00Z", views: 200 }, | ||
], | ||
intervalType: "DAY", | ||
}, | ||
}; | ||
|
||
beforeEach(() => { | ||
// @ts-expect-error we don't need to provide all the properties of the mockFetcher | ||
vi.mocked(RemixReact.useFetcher).mockReturnValue(mockFetcher); | ||
|
||
// Mock ResizeObserver for recharts | ||
global.ResizeObserver = vi.fn().mockImplementation(() => ({ | ||
observe: vi.fn(), | ||
unobserve: vi.fn(), | ||
disconnect: vi.fn(), | ||
})); | ||
}); | ||
|
||
afterEach(() => { | ||
vi.restoreAllMocks(); | ||
}); | ||
|
||
test("fetches data on mount", () => { | ||
const props = { | ||
siteId: "test-site", | ||
interval: "7d", | ||
filters: {}, | ||
timezone: "UTC", | ||
}; | ||
|
||
render(<TimeSeriesCard {...props} />); | ||
|
||
expect(mockFetcher.submit).toHaveBeenCalledWith( | ||
{ | ||
site: "test-site", | ||
interval: "7d", | ||
timezone: "UTC", | ||
}, | ||
{ | ||
method: "get", | ||
action: "/resources/timeseries", | ||
}, | ||
); | ||
}); | ||
|
||
test("renders TimeSeriesChart when data is available", async () => { | ||
const props = { | ||
siteId: "test-site", | ||
interval: "7d", | ||
filters: {}, | ||
timezone: "UTC", | ||
}; | ||
|
||
render(<TimeSeriesCard {...props} />); | ||
|
||
// Wait for the chart to be rendered | ||
await waitFor(() => screen.getAllByText("Mon, Jan 15").length > 0); | ||
// assert data appears in chart | ||
expect(screen.getAllByText("100")).toHaveLength(2); | ||
}); | ||
|
||
test("refetches when props change", () => { | ||
expect(mockFetcher.submit).toHaveBeenCalledTimes(0); | ||
|
||
const props = { | ||
siteId: "test-site", | ||
interval: "7d", | ||
filters: {}, | ||
timezone: "UTC", | ||
}; | ||
|
||
const { rerender } = render(<TimeSeriesCard {...props} />); | ||
|
||
// Change interval | ||
rerender(<TimeSeriesCard {...props} interval="1d" />); | ||
|
||
expect(mockFetcher.submit).toHaveBeenCalledTimes(2); | ||
expect(mockFetcher.submit).toHaveBeenLastCalledWith( | ||
{ | ||
site: "test-site", | ||
interval: "1d", | ||
timezone: "UTC", | ||
}, | ||
{ | ||
method: "get", | ||
action: "/resources/timeseries", | ||
}, | ||
); | ||
}); | ||
}); |
Oops, something went wrong.