Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discovery: Cache revalidation #77

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
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.test
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ UNILOGIN_API_URL=https://et-broker.unilogin.dk
UNILOGIN_CLIENT_ID=https://stg.ereolengo.itkdev.dk/
UNILOGIN_CLIENT_SECRET=XXX
UNILOGIN_SESSION_SECRET=XXX
UNILOGIN_WELLKNOWN_URL=https://hi-i-am-well-known-url.com

NEXT_PUBLIC_APP_URL=https://hellboy.the-movie.com
UNILOGIN_WELLKNOWN_URL=https://hi-i-am-well-known-url.com

REVALIDATE_CACHE_SECRET=i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=
181 changes: 181 additions & 0 deletions __tests__/revalidating-cache.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
// @vitest-environment node
import { testApiHandler } from "next-test-api-route-handler"
import { revalidatePath, revalidateTag } from "next/cache"
import { describe, test } from "vitest"

// @ts-ignore
import * as revalidateCacheHandler from "@/app/cache/revalidate/route"

vi.mock("next/cache", () => ({
revalidatePath: vi.fn(),
revalidateTag: vi.fn(),
}))

beforeEach(() => {
// Mock the revalidatePath and revalidateTag functions
// @ts-ignore
revalidatePath.mockReturnValue(true)
// @ts-ignore
revalidateTag.mockReturnValue(true)
})

describe("Revalidate cache test access via bearer token", () => {
test("That the cache revalidation endpoint returns 401 if no bearer token is provided", async () => {
await testApiHandler({
appHandler: revalidateCacheHandler,

Check failure on line 25 in __tests__/revalidating-cache.test.ts

View workflow job for this annotation

GitHub Actions / build

Type 'typeof import("/home/runner/work/dpl-go/dpl-go/app/cache/revalidate/route")' is not assignable to type 'Omit<any, string | number | symbol> & { [x: string]: ((req: NextRequest, context?: any) => any) | undefined; }'.
url: `/cache/revalidate`,
async test({ fetch }) {
const res = await fetch({
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ type: "tag", tags: ["tag1", "tag2"] }),
})
expect(res.status).toBe(401)
},
})
})

test("That the cache revalidation endpoint returns 200 if a valid bearer token is provided", async () => {
await testApiHandler({
appHandler: revalidateCacheHandler,

Check failure on line 40 in __tests__/revalidating-cache.test.ts

View workflow job for this annotation

GitHub Actions / build

Type 'typeof import("/home/runner/work/dpl-go/dpl-go/app/cache/revalidate/route")' is not assignable to type 'Omit<any, string | number | symbol> & { [x: string]: ((req: NextRequest, context?: any) => any) | undefined; }'.
url: `/cache/revalidate`,
async test({ fetch }) {
const res = await fetch({
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
},
body: JSON.stringify({ type: "tag", tags: ["tag1", "tag2"] }),
})
expect(res.status).toBe(200)
},
})
})
})

describe("Revalidate cache test combination of payloads", () => {
test("That the cache revalidation endpoint returns 422 upon wrong input", async () => {
await testApiHandler({
appHandler: revalidateCacheHandler,

Check failure on line 60 in __tests__/revalidating-cache.test.ts

View workflow job for this annotation

GitHub Actions / build

Type 'typeof import("/home/runner/work/dpl-go/dpl-go/app/cache/revalidate/route")' is not assignable to type 'Omit<any, string | number | symbol> & { [x: string]: ((req: NextRequest, context?: any) => any) | undefined; }'.
url: `/cache/revalidate`,
async test({ fetch }) {
const res = await fetch({
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
},
body: JSON.stringify({ type: "unknown-type" }),
})
expect(res.status).toBe(422)
},
})

await testApiHandler({
appHandler: revalidateCacheHandler,

Check failure on line 76 in __tests__/revalidating-cache.test.ts

View workflow job for this annotation

GitHub Actions / build

Type 'typeof import("/home/runner/work/dpl-go/dpl-go/app/cache/revalidate/route")' is not assignable to type 'Omit<any, string | number | symbol> & { [x: string]: ((req: NextRequest, context?: any) => any) | undefined; }'.
url: `/cache/revalidate`,
async test({ fetch }) {
const res = await fetch({
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
},
body: JSON.stringify({ type: "tag", theTags: ["tag1", "tag2"] }),
})
expect(res.status).toBe(422)
},
})
})

test("That the cache revalidation endpoint returns 200 upon successful tag invalidation", async () => {
await testApiHandler({
appHandler: revalidateCacheHandler,

Check failure on line 94 in __tests__/revalidating-cache.test.ts

View workflow job for this annotation

GitHub Actions / build

Type 'typeof import("/home/runner/work/dpl-go/dpl-go/app/cache/revalidate/route")' is not assignable to type 'Omit<any, string | number | symbol> & { [x: string]: ((req: NextRequest, context?: any) => any) | undefined; }'.
url: `/cache/revalidate`,
async test({ fetch }) {
const res = await fetch({
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
},
body: JSON.stringify({ type: "tag", tags: ["tag1", "tag2"] }),
})
expect(res.status).toBe(200)
},
})
})

test("That the cache revalidation endpoint returns 200 upon successful path invalidation", async () => {
await testApiHandler({
appHandler: revalidateCacheHandler,

Check failure on line 112 in __tests__/revalidating-cache.test.ts

View workflow job for this annotation

GitHub Actions / build

Type 'typeof import("/home/runner/work/dpl-go/dpl-go/app/cache/revalidate/route")' is not assignable to type 'Omit<any, string | number | symbol> & { [x: string]: ((req: NextRequest, context?: any) => any) | undefined; }'.
url: `/cache/revalidate`,
async test({ fetch }) {
const res = await fetch({
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
},
body: JSON.stringify({ type: "path", paths: ["/some/path", "/some/path"] }),
})
expect(res.status).toBe(200)
},
})
})
})

describe("Revalidate cache test different path and tag formats", async () => {
test("That the cache revalidation endpoint returns 422 if a wrongly formatted path is given", async () => {
await testApiHandler({
appHandler: revalidateCacheHandler,

Check failure on line 132 in __tests__/revalidating-cache.test.ts

View workflow job for this annotation

GitHub Actions / build

Type 'typeof import("/home/runner/work/dpl-go/dpl-go/app/cache/revalidate/route")' is not assignable to type 'Omit<any, string | number | symbol> & { [x: string]: ((req: NextRequest, context?: any) => any) | undefined; }'.
url: `/cache/revalidate`,
async test({ fetch }) {
const res = await fetch({
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
},
body: JSON.stringify({ type: "path", paths: ["some/path", "/some/path"] }),
})
expect(res.status).toBe(422)
},
})
})
test("That the cache revalidation endpoint returns 422 if a wrongly formatted path is given", async () => {
await testApiHandler({
appHandler: revalidateCacheHandler,

Check failure on line 149 in __tests__/revalidating-cache.test.ts

View workflow job for this annotation

GitHub Actions / build

Type 'typeof import("/home/runner/work/dpl-go/dpl-go/app/cache/revalidate/route")' is not assignable to type 'Omit<any, string | number | symbol> & { [x: string]: ((req: NextRequest, context?: any) => any) | undefined; }'.
url: `/cache/revalidate`,
async test({ fetch }) {
const res = await fetch({
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
},
body: JSON.stringify({ type: "path", paths: ["/some/*path", "/some/path"] }),
})
expect(res.status).toBe(422)
},
})
})
test("That the cache revalidation endpoint returns 422 if a wrongly formatted tag is given", async () => {
await testApiHandler({
appHandler: revalidateCacheHandler,

Check failure on line 166 in __tests__/revalidating-cache.test.ts

View workflow job for this annotation

GitHub Actions / build

Type 'typeof import("/home/runner/work/dpl-go/dpl-go/app/cache/revalidate/route")' is not assignable to type 'Omit<any, string | number | symbol> & { [x: string]: ((req: NextRequest, context?: any) => any) | undefined; }'.
url: `/cache/revalidate`,
async test({ fetch }) {
const res = await fetch({
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
},
body: JSON.stringify({ type: "tag", paths: ["!wrong-tag", "another tag"] }),
})
expect(res.status).toBe(422)
},
})
})
})
14 changes: 0 additions & 14 deletions app/article/[id]/article.dpl-cms.graphql

This file was deleted.

15 changes: 0 additions & 15 deletions app/article/[id]/loadArticle.ts

This file was deleted.

18 changes: 0 additions & 18 deletions app/article/[id]/page.tsx

This file was deleted.

35 changes: 35 additions & 0 deletions app/artikel/[...pathElements]/article.dpl-cms.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
query getArticle($id: ID!) {
nodeArticle(id: $id) {
title
subtitle
paragraphs {
__typename
... on ParagraphTextBody {
body {
value
}
}
}
}
}

query getArticleByRoute($path: String!) {
route(path: $path) {
... on RouteInternal {
entity {
... on NodeArticle {
title
subtitle
paragraphs {
__typename
... on ParagraphTextBody {
body {
value
}
}
}
}
}
}
}
}
15 changes: 15 additions & 0 deletions app/artikel/[...pathElements]/loadArticle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { fetcher } from "@/lib/graphql/fetchers/dpl-cms.fetcher"
import {
GetArticleByRouteDocument,
GetArticleByRouteQuery,
} from "@/lib/graphql/generated/dpl-cms/graphql"

const loadArticle = async (path: string) => {
const data = await fetcher<GetArticleByRouteQuery, { path: string }>(GetArticleByRouteDocument, {
path,
})()

return data
}

export default loadArticle
45 changes: 45 additions & 0 deletions app/artikel/[...pathElements]/loadArticlesSsg.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// import getQueryClient from "@/lib/getQueryClient"
// import {
// ExtractArticlesQuery,
// useExtractArticlesQuery,
// } from "@/lib/graphql/generated/dpl-cms/graphql"

// const loadArticlesSsg = async () => {
// const queryClient = getQueryClient()
// const pageSize = 100
// // We have a while loop.
// // Just to be safe we do not allow more than 100 iterations.
// const maxRuns = 100
// let runNumber = 0

// const {
// nodeArticles: { nodes, edges, pageInfo },
// } = await queryClient.fetchQuery<ExtractArticlesQuery>({
// queryKey: useExtractArticlesQuery.getKey({ pageSize }),
// queryFn: useExtractArticlesQuery.fetcher({ pageSize }),
// })
// let allNodes = nodes
// let allEdges = edges
// let cursor = edges[edges.length - 1]?.cursor

// while (pageInfo.hasNextPage && runNumber < maxRuns) {
// const {
// nodeArticles: { nodes: newNodes, edges: newEdges },
// } = await queryClient.fetchQuery<ExtractArticlesQuery>({
// queryKey: useExtractArticlesQuery.getKey({ pageSize, cursor }),
// queryFn: useExtractArticlesQuery.fetcher({ pageSize, cursor }),
// })

// allNodes = [...allNodes, ...newNodes]
// allEdges = [...allEdges, ...newEdges]
// cursor = newEdges[newEdges.length - 1]?.cursor
// // eslint-disable-next-line no-console
// console.log({ allNodes, allEdges, cursor })

// runNumber += 1
// }

// return { nodes: allNodes }
// }

// export default loadArticlesSsg
19 changes: 19 additions & 0 deletions app/artikel/[...pathElements]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import loadArticle from "./loadArticle"

// import loadArticlesSsg from "./loadArticlesSsg"

const Page = async (props: { params: Promise<{ pathElements: string[] }> }) => {
const params = await props.params

const { pathElements } = params

const path = [...pathElements].join("/")
const data = await loadArticle(path)
return <pre>{JSON.stringify(data, null, 2)}</pre>
}

export default Page

export async function generateStaticParams() {
return []
}
Loading
Loading