Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion env/.env.development
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
VITE_BACKEND_BASE_URL=https://webuddhist-dev-backend.onrender.com
# VITE_BACKEND_BASE_URL=https://webuddhist-dev-backend.onrender.com
VITE_BACKEND_BASE_URL=http://127.0.0.1:8000
# VITE_BACKEND_BASE_URL=https://api.webuddhist.com/
VITE_DEFAULT_LANGUAGE=en
VITE_TOKEN_EXPIRY_TIME_SEC=60000
112 changes: 44 additions & 68 deletions src/routes/chapterV2/chapter/ContentsChapter.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ mockAxios();
mockUseAuth();
mockReactQuery();

const axiosPostMock = axiosInstance.post as unknown as Mock;
const axiosGetMock = axiosInstance.get as unknown as Mock;

vi.mock("@tolgee/react", async () => {
const actual = await vi.importActual("@tolgee/react");
Expand Down Expand Up @@ -58,6 +58,7 @@ vi.mock("../../../context/PanelContext.jsx", () => ({

vi.mock("../../../config/axios-config.js", () => ({
default: {
get: vi.fn(),
post: vi.fn(),
},
}));
Expand Down Expand Up @@ -165,17 +166,10 @@ describe("ContentsChapter", () => {
describe("fetchContentDetails function", () => {
test("calls axios with correct parameters when all props are provided", async () => {
const mockData = { content: { sections: [] } };
axiosPostMock.mockResolvedValue({ data: mockData });

const queryKey = [
"content",
"text-1",
"content-1",
"version-1",
20,
"segment-1",
];
const pageParam = { segmentId: "test-segment", direction: "next" };
axiosGetMock.mockResolvedValue({ data: mockData });

const queryKey = ["content", "text-1", 20];
const pageParam = 10;

let capturedFetchFunction: any;
vi.spyOn(reactQuery, "useInfiniteQuery").mockImplementation(
Expand All @@ -190,21 +184,17 @@ describe("ContentsChapter", () => {
await capturedFetchFunction({ pageParam, queryKey });
}

expect(axiosInstance.post).toHaveBeenCalledWith(
expect(axiosInstance.get).toHaveBeenCalledWith(
"/api/v1/texts/text-1/details",
{
content_id: "content-1",
segment_id: "test-segment",
version_id: "version-1",
direction: "next",
size: 20,
params: { offset: 10, limit: 20 },
},
);
});

test("calls axios with default direction when pageParam is null", async () => {
test("calls axios with default offset when pageParam is undefined", async () => {
const mockData = { content: { sections: [] } };
axiosPostMock.mockResolvedValue({ data: mockData });
axiosGetMock.mockResolvedValue({ data: mockData });

let capturedFetchFunction: any;
vi.spyOn(reactQuery, "useInfiniteQuery").mockImplementation(
Expand All @@ -216,34 +206,23 @@ describe("ContentsChapter", () => {

setup();

const queryKey = [
"content",
"text-1",
"content-1",
"version-1",
20,
"segment-1",
];
const queryKey = ["content", "text-1", 20];

if (capturedFetchFunction) {
await capturedFetchFunction({ pageParam: null, queryKey });
await capturedFetchFunction({ pageParam: undefined, queryKey });
}

expect(axiosInstance.post).toHaveBeenCalledWith(
expect(axiosInstance.get).toHaveBeenCalledWith(
"/api/v1/texts/text-1/details",
{
content_id: "content-1",
segment_id: "segment-1",
version_id: "version-1",
direction: "next",
size: 20,
params: { offset: 0, limit: 20 },
},
);
});

test("calls axios without optional parameters when they are null/undefined", async () => {
test("calls axios with zero offset when pageParam is 0", async () => {
const mockData = { content: { sections: [] } };
axiosPostMock.mockResolvedValue({ data: mockData });
axiosGetMock.mockResolvedValue({ data: mockData });

let capturedFetchFunction: any;
vi.spyOn(reactQuery, "useInfiniteQuery").mockImplementation(
Expand All @@ -253,30 +232,25 @@ describe("ContentsChapter", () => {
},
);

setup({
contentId: null,
segmentId: null,
versionId: null,
});
setup();

const queryKey = ["content", "text-1", null, null, 20, null];
const queryKey = ["content", "text-1", 20];

if (capturedFetchFunction) {
await capturedFetchFunction({ pageParam: null, queryKey });
await capturedFetchFunction({ pageParam: 0, queryKey });
}

expect(axiosInstance.post).toHaveBeenCalledWith(
expect(axiosInstance.get).toHaveBeenCalledWith(
"/api/v1/texts/text-1/details",
{
direction: "next",
size: 20,
params: { offset: 0, limit: 20 },
},
);
});
});

describe("getNextPageParam logic", () => {
test("returns null when current_segment_position equals total_segments", () => {
test("returns undefined when currentOffset >= total_segments", () => {
let capturedGetNextPageParam: any;

vi.spyOn(reactQuery, "useInfiniteQuery").mockImplementation(
Expand All @@ -289,16 +263,18 @@ describe("ContentsChapter", () => {
setup();

const lastPage = {
current_segment_position: 10,
total_segments: 10,
total_segments: 20,
content: { sections: [{ id: 1 }] },
};
// allPages with 1 page, size is 20 (default), so currentOffset = 1 * 20 = 20
// 20 >= 20, so should return undefined
const allPages = [lastPage];

const result = capturedGetNextPageParam(lastPage);
expect(result).toBeNull();
const result = capturedGetNextPageParam(lastPage, allPages);
expect(result).toBeUndefined();
});

test("handles undefined lastPage gracefully", () => {
test("returns next offset when more pages available", () => {
let capturedGetNextPageParam: any;

vi.spyOn(reactQuery, "useInfiniteQuery").mockImplementation(
Expand All @@ -310,31 +286,31 @@ describe("ContentsChapter", () => {

setup();

const result = capturedGetNextPageParam(undefined);
expect(result).toBeNull();
const lastPage = {
total_segments: 50,
content: { sections: [{ id: 1 }] },
};
// allPages with 1 page, size is 20 (default), so currentOffset = 1 * 20 = 20
// 20 < 50, so should return 20 (next offset)
const allPages = [lastPage];

const result = capturedGetNextPageParam(lastPage, allPages);
expect(result).toBe(20);
});
});

describe("getPreviousPageParam logic", () => {
test("returns null when current_segment_position equals 1", () => {
let capturedGetPreviousPageParam: any;
test("is undefined when isFromSheet is true", () => {
let capturedGetNextPageParam: any;

vi.spyOn(reactQuery, "useInfiniteQuery").mockImplementation(
(_key: any, _fetchFn: any, options: any) => {
capturedGetPreviousPageParam = options.getPreviousPageParam;
capturedGetNextPageParam = options.getNextPageParam;
return buildInfiniteQueryResult();
},
);

setup();

const firstPage = {
current_segment_position: 1,
content: { sections: [{ id: 1 }] },
};
setup({ isFromSheet: true });

const result = capturedGetPreviousPageParam(firstPage);
expect(result).toBeNull();
expect(capturedGetNextPageParam).toBeUndefined();
});
});

Expand Down
42 changes: 11 additions & 31 deletions src/routes/chapterV2/chapter/ContentsChapter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,15 @@ import UseChapterHook from "./helpers/UseChapterHook.tsx";
import axiosInstance from "@/config/axios-config.ts";
import { useInfiniteQuery } from "react-query";
import { PanelProvider } from "@/context/PanelContext.tsx";
import {
getEarlyReturn,
getFirstSegmentId,
getLastSegmentId,
mergeSections,
} from "@/utils/helperFunctions.tsx";
import { getEarlyReturn, mergeSections } from "@/utils/helperFunctions.tsx";
import { useTranslate } from "@tolgee/react";
import Seo from "@/routes/commons/seo/Seo.tsx";

const fetchContentDetails = async ({ pageParam = null, queryKey }: any) => {
const [_, textId, contentId, versionId, size, initialSegmentId] = queryKey;
const segmentId = pageParam?.segmentId ?? initialSegmentId;
const direction = pageParam?.direction ?? "next";
const { data } = await axiosInstance.post(`/api/v1/texts/${textId}/details`, {
...(contentId && { content_id: contentId }),
...(segmentId && { segment_id: segmentId }),
...(versionId && { version_id: versionId }),
direction,
size,
const fetchContentDetails = async ({ pageParam = 0, queryKey }: any) => {
const [_, textId, limit] = queryKey;
const offset = pageParam;
const { data } = await axiosInstance.get(`/api/v1/texts/${textId}/details`, {
params: { offset, limit },
});
return data;
};
Expand Down Expand Up @@ -100,25 +90,15 @@ const ContentsChapter = ({
}, [layoutMode]);

const infiniteQuery = useInfiniteQuery(
["content", textId, contentId, versionId, size, currentSegmentId],
["content", textId, size],
fetchContentDetails,
{
getNextPageParam: isFromSheet
? undefined
: (lastPage) => {
if (lastPage?.current_segment_position === lastPage?.total_segments)
return null;
const lastSegmentId = getLastSegmentId(lastPage.content.sections);
return { segmentId: lastSegmentId, direction: "next" };
},
getPreviousPageParam: isFromSheet
? undefined
: (firstPage) => {
if (firstPage?.current_segment_position === 1) return null;
const firstSegmentId = getFirstSegmentId(
firstPage.content.sections,
);
return { segmentId: firstSegmentId, direction: "previous" };
: (lastPage, allPages) => {
const currentOffset = allPages.length * size;
if (currentOffset >= lastPage?.total_segments) return undefined;
return currentOffset;
},
enabled: !!textId,
refetchOnWindowFocus: false,
Expand Down
5 changes: 3 additions & 2 deletions src/routes/chapterV2/utils/resources/Resources.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const Resources = ({
className="w-full flex justify-start gap-1.5"
>
<IoLanguage className="text-lg" />
{`${t("connection_pannel.translations")} (${sidePanelData.segment_info.translations})`}
{t("connection_pannel.translations")}
</Button>
);

Expand All @@ -77,7 +77,7 @@ const Resources = ({
onClick={() => setActiveView("commentary")}
>
<BiBookOpen className="text-lg" />
{`${t("text.commentary")} (${sidePanelData.segment_info.related_text.commentaries})`}
{t("text.commentary")}
</Button>
);

Expand Down Expand Up @@ -235,6 +235,7 @@ const Resources = ({
return (
<RootTextView
segmentId={segmentId}
textId={sidePanelData?.segment_info?.text_id}
setIsRootTextView={setActiveView}
addChapter={addChapter}
currentChapter={currentChapter}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ describe("RootTextView", () => {
const setup = (props: Record<string, unknown> = {}) => {
const defaultProps = {
segmentId: "mock-segment-id",
textId: "mock-text-id",
setIsRootTextView: mockSetIsRootTextView,
addChapter: mockAddChapter,
sectionindex: 0,
Expand All @@ -150,6 +151,22 @@ describe("RootTextView", () => {
});

test("fetchRootTextData makes correct API call", async () => {
const segmentId = "mock-segment-id";
const textId = "mock-text-id";
(axiosInstance.get as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
data: mockRootTextData,
});

const result = await fetchRootTextData(segmentId, textId);

expect(axiosInstance.get).toHaveBeenCalledWith(
`/api/v1/segments/${segmentId}/root_text`,
{ params: { text_id: textId } },
);
expect(result).toEqual(mockRootTextData);
});

test("fetchRootTextData works without text_id parameter", async () => {
const segmentId = "mock-segment-id";
(axiosInstance.get as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
data: mockRootTextData,
Expand All @@ -159,6 +176,7 @@ describe("RootTextView", () => {

expect(axiosInstance.get).toHaveBeenCalledWith(
`/api/v1/segments/${segmentId}/root_text`,
{ params: { text_id: undefined } },
);
expect(result).toEqual(mockRootTextData);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@ import TextExpand from "../../../../../commons/expandtext/TextExpand.tsx";
import ResourceHeader from "../common/ResourceHeader.tsx";
import { Button } from "@/components/ui/button.tsx";

export const fetchRootTextData = async (segment_id: string) => {
export const fetchRootTextData = async (
segment_id: string,
text_id?: string,
) => {
const { data } = await axiosInstance.get(
`/api/v1/segments/${segment_id}/root_text`,
{ params: { text_id } },
);
return data;
};

const RootTextView = ({
segmentId,
textId,
setIsRootTextView,
addChapter,
currentChapter,
Expand All @@ -26,8 +31,8 @@ const RootTextView = ({
const { t } = useTranslate();
const { closeResourcesPanel } = usePanelContext() as any;
const { data: rootTextData } = useQuery(
["rootTexts", segmentId],
() => fetchRootTextData(segmentId),
["rootTexts", segmentId, textId],
() => fetchRootTextData(segmentId, textId),
{
refetchOnWindowFocus: false,
},
Expand Down
Loading
Loading