@decocms/apps-blog 7.52.1 → 7.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +13 -4
- package/src/README.md +69 -0
- package/src/__tests__/blogRecords.test.ts +270 -0
- package/src/__tests__/date.test.ts +134 -0
- package/src/__tests__/handlePosts.test.ts +230 -230
- package/src/__tests__/loaders.test.ts +154 -154
- package/src/__tests__/mod.test.ts +6 -6
- package/src/__tests__/publicationStatus.test.ts +176 -0
- package/src/__tests__/records.test.ts +68 -68
- package/src/__tests__/seoSections.test.ts +245 -0
- package/src/actions/submitRating.ts +36 -0
- package/src/actions/submitReview.ts +95 -0
- package/src/actions/submitView.ts +28 -0
- package/src/client.ts +69 -0
- package/src/core/blogRecords.ts +94 -0
- package/src/core/handlePosts.ts +154 -63
- package/src/core/records.ts +147 -12
- package/src/index.ts +48 -14
- package/src/loaderMap.ts +28 -24
- package/src/loaders/BlogPostItem.ts +15 -5
- package/src/loaders/BlogPostPage.ts +25 -20
- package/src/loaders/BlogRelatedPosts.ts +45 -45
- package/src/loaders/BlogpostList.ts +73 -0
- package/src/loaders/BlogpostListing.ts +114 -77
- package/src/loaders/GetCategories.ts +42 -28
- package/src/loaders/extensions/BlogpostList/ratings.ts +36 -0
- package/src/loaders/extensions/BlogpostList/reviews.ts +36 -0
- package/src/loaders/extensions/BlogpostListing/ratings.ts +38 -0
- package/src/loaders/extensions/BlogpostListing/reviews.ts +38 -0
- package/src/loaders/extensions/BlogpostPage/ratings.ts +24 -0
- package/src/loaders/extensions/BlogpostPage/reviews.ts +31 -0
- package/src/loaders/extensions/types.ts +15 -0
- package/src/manifest.gen.ts +82 -14
- package/src/mod.ts +71 -20
- package/src/registry.ts +5 -5
- package/src/sections/Seo/SeoBlogPost.tsx +75 -0
- package/src/sections/Seo/SeoBlogPostListing.tsx +80 -0
- package/src/sections/Template.tsx +96 -0
- package/src/sections/blocks/BlockImage.tsx +21 -0
- package/src/sections/blocks/Callout.tsx +64 -0
- package/src/sections/blocks/CardGroup.tsx +60 -0
- package/src/sections/blocks/Checklist.tsx +58 -0
- package/src/sections/blocks/Code.tsx +29 -0
- package/src/sections/blocks/Comparison.tsx +77 -0
- package/src/sections/blocks/Cta.tsx +22 -0
- package/src/sections/blocks/Divider.tsx +3 -0
- package/src/sections/blocks/Heading.tsx +28 -0
- package/src/sections/blocks/List.tsx +39 -0
- package/src/sections/blocks/Paragraph.tsx +15 -0
- package/src/sections/blocks/Quote.tsx +32 -0
- package/src/sections/blocks/Stat.tsx +23 -0
- package/src/sections/blocks/StatGroup.tsx +38 -0
- package/src/sections/blocks/Steps.tsx +64 -0
- package/src/sections/blocks/Table.tsx +80 -0
- package/src/sections/blocks/Video.tsx +39 -0
- package/src/static/css.ts +178 -0
- package/src/types.ts +312 -77
- package/src/utils/blocksToSections.ts +170 -0
- package/src/utils/constants.ts +1 -0
- package/src/utils/date.ts +95 -0
- package/src/utils/hardSanitize.ts +106 -0
- package/src/utils/jsonLD.ts +115 -0
- package/src/utils/sanitizeHtml.ts +37 -0
|
@@ -1,285 +1,285 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import handlePosts, {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
filterPostsByCategory,
|
|
4
|
+
filterPostsBySlugs,
|
|
5
|
+
filterPostsByTerm,
|
|
6
|
+
filterRelatedPosts,
|
|
7
|
+
slicePosts,
|
|
8
|
+
sortPosts,
|
|
9
9
|
} from "../core/handlePosts";
|
|
10
10
|
import type { BlogPost, SortBy } from "../types";
|
|
11
11
|
|
|
12
12
|
function makePost(overrides: Partial<BlogPost> = {}): BlogPost {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
return {
|
|
14
|
+
title: "Test Post",
|
|
15
|
+
slug: "test-post",
|
|
16
|
+
date: "2024-06-01",
|
|
17
|
+
excerpt: "A test post",
|
|
18
|
+
content: "Full content here",
|
|
19
|
+
categories: [{ name: "News", slug: "news" }],
|
|
20
|
+
authors: [{ name: "Author", email: "a@b.com" }],
|
|
21
|
+
...overrides,
|
|
22
|
+
};
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
// ---------------------------------------------------------------------------
|
|
26
26
|
// sortPosts
|
|
27
27
|
// ---------------------------------------------------------------------------
|
|
28
28
|
describe("sortPosts", () => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
29
|
+
const posts = [
|
|
30
|
+
makePost({ title: "Alpha", slug: "a", date: "2024-01-01" }),
|
|
31
|
+
makePost({ title: "Charlie", slug: "c", date: "2024-03-01" }),
|
|
32
|
+
makePost({ title: "Bravo", slug: "b", date: "2024-02-01" }),
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
it("sorts date_desc — most recent first", async () => {
|
|
36
|
+
const sorted = await sortPosts(posts, "date_desc");
|
|
37
|
+
expect(sorted.map((p) => p.slug)).toEqual(["c", "b", "a"]);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("sorts date_asc — oldest first", async () => {
|
|
41
|
+
const sorted = await sortPosts(posts, "date_asc");
|
|
42
|
+
expect(sorted.map((p) => p.slug)).toEqual(["a", "b", "c"]);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("sorts title_asc", async () => {
|
|
46
|
+
const sorted = await sortPosts(posts, "title_asc");
|
|
47
|
+
// localeCompare(a,b) is negated for asc → Z-A
|
|
48
|
+
expect(sorted.map((p) => p.title)).toEqual(["Charlie", "Bravo", "Alpha"]);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("sorts title_desc", async () => {
|
|
52
|
+
const sorted = await sortPosts(posts, "title_desc");
|
|
53
|
+
// localeCompare(a,b) kept as-is for desc → A-Z
|
|
54
|
+
expect(sorted.map((p) => p.title)).toEqual(["Alpha", "Bravo", "Charlie"]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("falls back to date for invalid sort field", async () => {
|
|
58
|
+
const sorted = await sortPosts(posts, "invalid_desc" as SortBy);
|
|
59
|
+
expect(sorted.map((p) => p.slug)).toEqual(["c", "b", "a"]);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("falls back to desc for invalid sort order", async () => {
|
|
63
|
+
const sorted = await sortPosts(posts, "date_wrong" as SortBy);
|
|
64
|
+
expect(sorted.map((p) => p.slug)).toEqual(["c", "b", "a"]);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("sorts posts with missing date to end", async () => {
|
|
68
|
+
const withMissing = [
|
|
69
|
+
makePost({ slug: "no-date", date: undefined as unknown as string }),
|
|
70
|
+
makePost({ slug: "has-date", date: "2024-06-01" }),
|
|
71
|
+
];
|
|
72
|
+
const sorted = await sortPosts(withMissing, "date_desc");
|
|
73
|
+
expect(sorted[0].slug).toBe("has-date");
|
|
74
|
+
expect(sorted[1].slug).toBe("no-date");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("throws on empty array (accesses blogPosts[0])", async () => {
|
|
78
|
+
await expect(sortPosts([], "date_desc")).rejects.toThrow();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("does not mutate original array", async () => {
|
|
82
|
+
const original = [...posts];
|
|
83
|
+
await sortPosts(posts, "date_asc");
|
|
84
|
+
expect(posts).toEqual(original);
|
|
85
|
+
});
|
|
86
86
|
});
|
|
87
87
|
|
|
88
88
|
// ---------------------------------------------------------------------------
|
|
89
89
|
// filterPostsByCategory
|
|
90
90
|
// ---------------------------------------------------------------------------
|
|
91
91
|
describe("filterPostsByCategory", () => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
92
|
+
const posts = [
|
|
93
|
+
makePost({ slug: "a", categories: [{ name: "News", slug: "news" }] }),
|
|
94
|
+
makePost({
|
|
95
|
+
slug: "b",
|
|
96
|
+
categories: [
|
|
97
|
+
{ name: "News", slug: "news" },
|
|
98
|
+
{ name: "Tech", slug: "tech" },
|
|
99
|
+
],
|
|
100
|
+
}),
|
|
101
|
+
makePost({ slug: "c", categories: [{ name: "Tech", slug: "tech" }] }),
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
it("returns all posts when no slug provided", () => {
|
|
105
|
+
expect(filterPostsByCategory(posts)).toHaveLength(3);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("filters by matching slug", () => {
|
|
109
|
+
const result = filterPostsByCategory(posts, "tech");
|
|
110
|
+
expect(result.map((p) => p.slug)).toEqual(["b", "c"]);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("returns empty when no match", () => {
|
|
114
|
+
expect(filterPostsByCategory(posts, "sports")).toEqual([]);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("excludes posts with no categories", () => {
|
|
118
|
+
const withNone = [...posts, makePost({ slug: "d", categories: undefined })];
|
|
119
|
+
expect(filterPostsByCategory(withNone, "news").map((p) => p.slug)).toEqual(["a", "b"]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("includes post when one of multiple categories matches", () => {
|
|
123
|
+
const result = filterPostsByCategory(posts, "tech");
|
|
124
|
+
expect(result.find((p) => p.slug === "b")).toBeTruthy();
|
|
125
|
+
});
|
|
126
126
|
});
|
|
127
127
|
|
|
128
128
|
// ---------------------------------------------------------------------------
|
|
129
129
|
// filterPostsBySlugs
|
|
130
130
|
// ---------------------------------------------------------------------------
|
|
131
131
|
describe("filterPostsBySlugs", () => {
|
|
132
|
-
|
|
132
|
+
const posts = [makePost({ slug: "a" }), makePost({ slug: "b" }), makePost({ slug: "c" })];
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
it("filters to only matching slugs", () => {
|
|
135
|
+
expect(filterPostsBySlugs(posts, ["a", "c"]).map((p) => p.slug)).toEqual(["a", "c"]);
|
|
136
|
+
});
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
it("returns empty for empty slugs array", () => {
|
|
139
|
+
expect(filterPostsBySlugs(posts, [])).toEqual([]);
|
|
140
|
+
});
|
|
141
141
|
});
|
|
142
142
|
|
|
143
143
|
// ---------------------------------------------------------------------------
|
|
144
144
|
// filterPostsByTerm
|
|
145
145
|
// ---------------------------------------------------------------------------
|
|
146
146
|
describe("filterPostsByTerm", () => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
147
|
+
const posts = [
|
|
148
|
+
makePost({ slug: "a", title: "Hello World", excerpt: "intro", content: "body" }),
|
|
149
|
+
makePost({ slug: "b", title: "Goodbye", excerpt: "farewell world", content: "end" }),
|
|
150
|
+
makePost({ slug: "c", title: "Nothing", excerpt: "nope", content: "empty" }),
|
|
151
|
+
];
|
|
152
|
+
|
|
153
|
+
it("matches in title", () => {
|
|
154
|
+
expect(filterPostsByTerm(posts, "Hello").map((p) => p.slug)).toEqual(["a"]);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("matches in excerpt", () => {
|
|
158
|
+
expect(filterPostsByTerm(posts, "farewell").map((p) => p.slug)).toEqual(["b"]);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("matches in content", () => {
|
|
162
|
+
expect(filterPostsByTerm(posts, "empty").map((p) => p.slug)).toEqual(["c"]);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("is case-insensitive", () => {
|
|
166
|
+
expect(filterPostsByTerm(posts, "hELLo")).toHaveLength(1);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("returns empty when no match", () => {
|
|
170
|
+
expect(filterPostsByTerm(posts, "zzz")).toEqual([]);
|
|
171
|
+
});
|
|
172
172
|
});
|
|
173
173
|
|
|
174
174
|
// ---------------------------------------------------------------------------
|
|
175
175
|
// filterRelatedPosts
|
|
176
176
|
// ---------------------------------------------------------------------------
|
|
177
177
|
describe("filterRelatedPosts", () => {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
178
|
+
const posts = [
|
|
179
|
+
makePost({ slug: "a", categories: [{ name: "News", slug: "news" }] }),
|
|
180
|
+
makePost({ slug: "b", categories: [{ name: "Tech", slug: "tech" }] }),
|
|
181
|
+
makePost({ slug: "c", categories: undefined }),
|
|
182
|
+
];
|
|
183
|
+
|
|
184
|
+
it("includes post with category overlap", () => {
|
|
185
|
+
expect(filterRelatedPosts(posts, ["news"]).map((p) => p.slug)).toEqual(["a"]);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("excludes post with no overlap", () => {
|
|
189
|
+
expect(filterRelatedPosts(posts, ["sports"])).toEqual([]);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("excludes post with no categories", () => {
|
|
193
|
+
const result = filterRelatedPosts(posts, ["news"]);
|
|
194
|
+
expect(result.find((p) => p.slug === "c")).toBeUndefined();
|
|
195
|
+
});
|
|
196
196
|
});
|
|
197
197
|
|
|
198
198
|
// ---------------------------------------------------------------------------
|
|
199
199
|
// slicePosts
|
|
200
200
|
// ---------------------------------------------------------------------------
|
|
201
201
|
describe("slicePosts", () => {
|
|
202
|
-
|
|
202
|
+
const posts = Array.from({ length: 5 }, (_, i) => makePost({ slug: `p${i + 1}` }));
|
|
203
203
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
it("page 1 returns first N", () => {
|
|
205
|
+
expect(slicePosts(posts, 1, 2).map((p) => p.slug)).toEqual(["p1", "p2"]);
|
|
206
|
+
});
|
|
207
207
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
208
|
+
it("page 2 returns next N", () => {
|
|
209
|
+
expect(slicePosts(posts, 2, 2).map((p) => p.slug)).toEqual(["p3", "p4"]);
|
|
210
|
+
});
|
|
211
211
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
212
|
+
it("last page with fewer items", () => {
|
|
213
|
+
expect(slicePosts(posts, 3, 2).map((p) => p.slug)).toEqual(["p5"]);
|
|
214
|
+
});
|
|
215
215
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
216
|
+
it("page beyond total returns empty", () => {
|
|
217
|
+
expect(slicePosts(posts, 10, 2)).toEqual([]);
|
|
218
|
+
});
|
|
219
219
|
});
|
|
220
220
|
|
|
221
221
|
// ---------------------------------------------------------------------------
|
|
222
222
|
// handlePosts (composition pipeline)
|
|
223
223
|
// ---------------------------------------------------------------------------
|
|
224
224
|
describe("handlePosts", () => {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
225
|
+
const posts = [
|
|
226
|
+
makePost({
|
|
227
|
+
slug: "a",
|
|
228
|
+
title: "Alpha",
|
|
229
|
+
date: "2024-01-01",
|
|
230
|
+
categories: [{ name: "News", slug: "news" }],
|
|
231
|
+
}),
|
|
232
|
+
makePost({
|
|
233
|
+
slug: "b",
|
|
234
|
+
title: "Bravo",
|
|
235
|
+
date: "2024-02-01",
|
|
236
|
+
categories: [{ name: "Tech", slug: "tech" }],
|
|
237
|
+
}),
|
|
238
|
+
makePost({
|
|
239
|
+
slug: "c",
|
|
240
|
+
title: "Charlie",
|
|
241
|
+
date: "2024-03-01",
|
|
242
|
+
categories: [
|
|
243
|
+
{ name: "News", slug: "news" },
|
|
244
|
+
{ name: "Tech", slug: "tech" },
|
|
245
|
+
],
|
|
246
|
+
}),
|
|
247
|
+
];
|
|
248
|
+
|
|
249
|
+
it("slug string + postSlugs — uses slug filtering", async () => {
|
|
250
|
+
const result = await handlePosts(posts, "date_desc", "news", ["a", "c"]);
|
|
251
|
+
// sorted by date_desc: c (March) before a (Jan)
|
|
252
|
+
expect(result?.map((p) => p.slug)).toEqual(["c", "a"]);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("slug string + term — chains category + term filters", async () => {
|
|
256
|
+
const result = await handlePosts(posts, "date_desc", "news", undefined, "Alpha");
|
|
257
|
+
expect(result?.map((p) => p.slug)).toEqual(["a"]);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it("slug as string[] — triggers related posts path", async () => {
|
|
261
|
+
const result = await handlePosts(posts, "date_desc", ["tech"]);
|
|
262
|
+
expect(result?.map((p) => p.slug)).toEqual(["c", "b"]);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it("no slug + term — term-only filtering", async () => {
|
|
266
|
+
const result = await handlePosts(posts, "date_asc", undefined, undefined, "Bravo");
|
|
267
|
+
expect(result).toHaveLength(1);
|
|
268
|
+
expect(result![0].slug).toBe("b");
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it("excludePostSlug removes matching post", async () => {
|
|
272
|
+
const result = await handlePosts(posts, "date_desc", undefined, undefined, undefined, "b");
|
|
273
|
+
expect(result?.find((p) => p.slug === "b")).toBeUndefined();
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it("returns null when result is empty", async () => {
|
|
277
|
+
expect(await handlePosts(posts, "date_desc", "nonexistent")).toBeNull();
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it("returns all posts sorted when no filters given", async () => {
|
|
281
|
+
const result = await handlePosts(posts, "date_desc");
|
|
282
|
+
expect(result).toHaveLength(3);
|
|
283
|
+
expect(result![0].slug).toBe("c");
|
|
284
|
+
});
|
|
285
285
|
});
|