frontitygit
Version:
A Frontity source package for the REST API of self-hosted and WordPress.com sites
223 lines (204 loc) • 7.5 kB
text/typescript
import { createStore, InitializedStore, observe } from "@frontity/connect";
import clone from "clone-deep";
import wpSource from "../../../";
import WpSource from "../../../../types";
import Api from "../../api";
// JSON mocks
import { mockResponse } from "./mocks/helpers";
import author1 from "./mocks/author/author-1.json";
import author1Posts from "./mocks/author/author-1-posts.json";
import author1PostsPage2 from "./mocks/author/author-1-posts-page-2.json";
import author1PostsCpt from "./mocks/author/author-1-posts-cpt.json";
import { isSearch } from "@frontity/source";
let store: InitializedStore<WpSource>;
let api: jest.Mocked<Api>;
beforeEach(() => {
store = createStore<WpSource>(clone(wpSource()));
store.state.source.url = "https://test.frontity.org";
store.actions.source.init();
api = store.libraries.source.api as jest.Mocked<Api>;
});
describe("author", () => {
test("doesn't exist in source.author", async () => {
// Mock Api responses
api.get = jest
.fn()
.mockResolvedValueOnce(mockResponse([author1]))
.mockResolvedValueOnce(
mockResponse(author1Posts, {
"X-WP-Total": "5",
"X-WP-TotalPages": "2",
})
);
// Fetch entities
await store.actions.source.fetch("/author/author-1/");
expect(store.state.source).toMatchSnapshot();
});
test("was populated but not accessed", async () => {
// Add author to the store
await store.libraries.source.populate({
state: store.state,
response: mockResponse(author1),
});
// Mock Api responses
api.get = jest.fn().mockResolvedValueOnce(
mockResponse(author1PostsPage2, {
"X-WP-Total": "5",
"X-WP-TotalPages": "2",
})
);
// Observe changes in isFetching and isReady properties
const dataState = [];
observe(() => {
const { isFetching, isReady } = store.state.source.get(
"/author/author-1/page/2/"
);
dataState.push({ isFetching, isReady });
});
// Fetch entities
await store.actions.source.fetch("/author/author-1/page/2/");
expect(api.get).toHaveBeenCalledTimes(1);
expect(store.state.source).toMatchSnapshot();
// Values history of isFetching and isReady
expect(dataState).toEqual([
// First values are from a different object.
{ isFetching: false, isReady: false },
// Fetch starts.
{ isFetching: true, isReady: false },
// Intermediate values.
{ isFetching: false, isReady: false },
// Fetch ends.
{ isFetching: false, isReady: true },
]);
});
test("overwrites the data when fetched with { force: true }", async () => {
// Define the JSON response for the author with the name updated.
const updatedAuthor = { ...author1, name: "Author 2" };
// Do the same for the posts that were written by that author.
const updatedPosts = clone(author1Posts);
updatedPosts.forEach((post) => (post._embedded.author = [updatedAuthor]));
// Mock Api responses
api.get = jest
.fn()
// First `actions.source.fetch()` call.
.mockResolvedValueOnce(mockResponse(author1))
.mockResolvedValueOnce(
mockResponse(author1Posts, {
"X-WP-Total": "5",
"X-WP-TotalPages": "2",
})
)
// Second `actions.source.fetch()` call, with the author name updated.
.mockResolvedValueOnce(mockResponse(updatedAuthor))
.mockResolvedValueOnce(
mockResponse(updatedPosts, {
"X-WP-Total": "5",
"X-WP-TotalPages": "2",
})
);
// Fetch author posts for the first time.
await store.actions.source.fetch("/author/author-1/");
expect(store.state.source.author["1"].name).toEqual("Author 1");
// Fetch entities with { force: true }.
await store.actions.source.fetch("/author/author-1/", { force: true });
// Make sure that api.get() was called twice for each `source.fetch()`.
expect(api.get).toHaveBeenCalledTimes(4);
expect(store.state.source).toMatchSnapshot();
expect(store.state.source.author["1"].name).toEqual("Author 2");
});
test("fetchs from a different endpoint with extra params", async () => {
// Add custom post endpoint and params
store.state.source.postEndpoint = "multiple-post-type";
store.state.source.params = { type: ["post", "cpt"] };
// Mock Api responses
api.get = jest
.fn()
.mockResolvedValueOnce(mockResponse([author1]))
.mockResolvedValueOnce(
mockResponse(author1PostsCpt, {
"X-WP-Total": "5",
"X-WP-TotalPages": "2",
})
);
// Fetch entities
await store.actions.source.fetch("/author/author-1/");
expect(api.get.mock.calls).toMatchSnapshot();
expect(store.state.source).toMatchSnapshot();
});
test("returns 404 if author doesn't exist in WP", async () => {
// Mock Api responses
api.get = jest.fn().mockResolvedValue(mockResponse([]));
// Fetch entities
await store.actions.source.fetch("/author/non-existent/");
expect(api.get).toHaveBeenCalledTimes(1);
expect(store.state.source).toMatchSnapshot();
});
test("returns 404 if the page fetched is out of range", async () => {
// Mock Api responses
api.get = jest
.fn()
.mockResolvedValueOnce(mockResponse([author1]))
.mockResolvedValueOnce(mockResponse([]));
// Fetch entities
await store.actions.source.fetch("/author/author-1/page/3");
expect(store.state.source).toMatchSnapshot();
});
test("doesn't return 404 if the first page is empty", async () => {
// Mock Api responses
api.get = jest
.fn()
.mockResolvedValueOnce(mockResponse([author1]))
.mockResolvedValueOnce(
mockResponse([], {
"X-WP-Total": "0",
"X-WP-TotalPages": "0",
})
);
// Fetch entities
await store.actions.source.fetch("/author/author-1/");
expect(store.state.source).toMatchSnapshot();
});
test("doesn't return 404 if the first page is empty (no headers)", async () => {
// Mock Api responses
api.get = jest
.fn()
.mockResolvedValueOnce(mockResponse([author1]))
.mockResolvedValueOnce(mockResponse([], {}));
// Fetch entities
await store.actions.source.fetch("/author/author-1/");
expect(store.state.source).toMatchSnapshot();
});
test("is requested with any query param", async () => {
// Mock Api responses
api.get = jest
.fn()
.mockResolvedValueOnce(mockResponse([author1]))
.mockResolvedValueOnce(
mockResponse(author1Posts, {
"X-WP-Total": "5",
"X-WP-TotalPages": "2",
})
);
// Fetch entities
await store.actions.source.fetch("/author/author-1/?some=param");
expect(store.state.source).toMatchSnapshot();
});
test("is requested with a search param", async () => {
// Mock Api responses
api.get = jest
.fn()
.mockResolvedValueOnce(mockResponse([author1]))
.mockResolvedValueOnce(
mockResponse(author1Posts, {
"X-WP-Total": "5",
"X-WP-TotalPages": "2",
})
);
// Fetch entities
await store.actions.source.fetch("/author/author-1/?s=findAuthor");
const data = store.state.source.data["/author/author-1/?s=findAuthor"];
expect(isSearch(data)).toBe(true);
expect(isSearch(data) && data.searchQuery).toBe("findAuthor");
expect(store.state.source).toMatchSnapshot();
});
});