Skip to content

Commit cac9673

Browse files
committed
add unit test
1 parent c31f6fc commit cac9673

File tree

3 files changed

+222
-24
lines changed

3 files changed

+222
-24
lines changed

packages/open-next/src/adapters/cache.ts

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,9 @@ export default class Cache {
6363

6464
const _tags = [...(tags ?? []), ...(softTags ?? [])];
6565
const _lastModified = cachedEntry.lastModified ?? Date.now();
66-
const _hasBeenRevalidated = cachedEntry.shouldBypassTagCache ? false : await hasBeenRevalidated(
67-
key,
68-
_tags,
69-
cachedEntry,
70-
);
66+
const _hasBeenRevalidated = cachedEntry.shouldBypassTagCache
67+
? false
68+
: await hasBeenRevalidated(key, _tags, cachedEntry);
7169

7270
if (_hasBeenRevalidated) return null;
7371

@@ -82,11 +80,13 @@ export default class Cache {
8280
!tag.endsWith("page"),
8381
);
8482
if (path) {
85-
const hasPathBeenUpdated = cachedEntry.shouldBypassTagCache ? false : await hasBeenRevalidated(
86-
path.replace("_N_T_/", ""),
87-
[],
88-
cachedEntry,
89-
);
83+
const hasPathBeenUpdated = cachedEntry.shouldBypassTagCache
84+
? false
85+
: await hasBeenRevalidated(
86+
path.replace("_N_T_/", ""),
87+
[],
88+
cachedEntry,
89+
);
9090
if (hasPathBeenUpdated) {
9191
// In case the path has been revalidated, we don't want to use the fetch cache
9292
return null;
@@ -118,11 +118,9 @@ export default class Cache {
118118
const meta = cacheData.meta;
119119
const tags = getTagsFromValue(cacheData);
120120
const _lastModified = cachedEntry.lastModified ?? Date.now();
121-
const _hasBeenRevalidated = cachedEntry.shouldBypassTagCache ? false : await hasBeenRevalidated(
122-
key,
123-
tags,
124-
cachedEntry,
125-
);
121+
const _hasBeenRevalidated = cachedEntry.shouldBypassTagCache
122+
? false
123+
: await hasBeenRevalidated(key, tags, cachedEntry);
126124
if (_hasBeenRevalidated) return null;
127125

128126
const store = globalThis.__openNextAls.getStore();

packages/open-next/src/adapters/composable-cache.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,23 @@ export default {
2828
globalThis.tagCache.mode === "nextMode" &&
2929
result.value.tags.length > 0
3030
) {
31-
const hasBeenRevalidated = result.shouldBypassTagCache ? false : await globalThis.tagCache.hasBeenRevalidated(
32-
result.value.tags,
33-
result.lastModified,
34-
);
31+
const hasBeenRevalidated = result.shouldBypassTagCache
32+
? false
33+
: await globalThis.tagCache.hasBeenRevalidated(
34+
result.value.tags,
35+
result.lastModified,
36+
);
3537
if (hasBeenRevalidated) return undefined;
3638
} else if (
3739
globalThis.tagCache.mode === "original" ||
3840
globalThis.tagCache.mode === undefined
3941
) {
40-
const hasBeenRevalidated = result.shouldBypassTagCache ? false :
41-
(await globalThis.tagCache.getLastModified(
42-
cacheKey,
43-
result.lastModified,
44-
)) === -1;
42+
const hasBeenRevalidated = result.shouldBypassTagCache
43+
? false
44+
: (await globalThis.tagCache.getLastModified(
45+
cacheKey,
46+
result.lastModified,
47+
)) === -1;
4548
if (hasBeenRevalidated) return undefined;
4649
}
4750

packages/tests-unit/tests/adapters/cache.test.ts

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,8 @@ describe("CacheHandler", () => {
531531
await cache.revalidateTag("tag");
532532

533533
expect(tagCache.writeTags).not.toHaveBeenCalled();
534+
// Reset the config
535+
globalThis.openNextConfig.dangerous.disableTagCache = false;
534536
});
535537

536538
it("Should call tagCache.writeTags", async () => {
@@ -621,4 +623,199 @@ describe("CacheHandler", () => {
621623
globalThis.tagCache.getPathsByTags = undefined;
622624
});
623625
});
626+
627+
describe("shouldBypassTagCache", () => {
628+
describe("fetch cache", () => {
629+
it("Should bypass tag cache validation when shouldBypassTagCache is true", async () => {
630+
incrementalCache.get.mockResolvedValueOnce({
631+
value: {
632+
kind: "FETCH",
633+
data: {
634+
headers: {},
635+
body: "{}",
636+
url: "https://example.com",
637+
status: 200,
638+
},
639+
},
640+
lastModified: Date.now(),
641+
shouldBypassTagCache: true,
642+
});
643+
644+
const result = await cache.get("key", {
645+
kind: "FETCH",
646+
tags: ["tag1"],
647+
});
648+
649+
expect(getFetchCacheSpy).toHaveBeenCalled();
650+
expect(tagCache.getLastModified).not.toHaveBeenCalled();
651+
expect(tagCache.hasBeenRevalidated).not.toHaveBeenCalled();
652+
expect(result).not.toBeNull();
653+
expect(result?.value).toEqual({
654+
kind: "FETCH",
655+
data: {
656+
headers: {},
657+
body: "{}",
658+
url: "https://example.com",
659+
status: 200,
660+
},
661+
});
662+
});
663+
664+
it("Should not bypass tag cache validation when shouldBypassTagCache is false", async () => {
665+
globalThis.tagCache.mode = "nextMode";
666+
incrementalCache.get.mockResolvedValueOnce({
667+
value: {
668+
kind: "FETCH",
669+
data: {
670+
headers: {},
671+
body: "{}",
672+
url: "https://example.com",
673+
status: 200,
674+
},
675+
},
676+
lastModified: Date.now(),
677+
shouldBypassTagCache: false,
678+
});
679+
680+
const result = await cache.get("key", {
681+
kind: "FETCH",
682+
tags: ["tag1"],
683+
});
684+
685+
expect(getFetchCacheSpy).toHaveBeenCalled();
686+
expect(tagCache.hasBeenRevalidated).toHaveBeenCalled();
687+
expect(result).not.toBeNull();
688+
});
689+
690+
it("Should not bypass tag cache validation when shouldBypassTagCache is undefined", async () => {
691+
globalThis.tagCache.mode = "nextMode";
692+
tagCache.hasBeenRevalidated.mockResolvedValueOnce(false);
693+
incrementalCache.get.mockResolvedValueOnce({
694+
value: {
695+
kind: "FETCH",
696+
data: {
697+
headers: {},
698+
body: "{}",
699+
url: "https://example.com",
700+
status: 200,
701+
},
702+
},
703+
lastModified: Date.now(),
704+
// shouldBypassTagCache not set
705+
});
706+
707+
const result = await cache.get("key", {
708+
kind: "FETCH",
709+
tags: ["tag1"],
710+
});
711+
712+
expect(getFetchCacheSpy).toHaveBeenCalled();
713+
expect(tagCache.hasBeenRevalidated).toHaveBeenCalled();
714+
expect(result).not.toBeNull();
715+
});
716+
717+
it("Should bypass path validation when shouldBypassTagCache is true for soft tags", async () => {
718+
incrementalCache.get.mockResolvedValueOnce({
719+
value: {
720+
kind: "FETCH",
721+
data: {
722+
headers: {},
723+
body: "{}",
724+
url: "https://example.com",
725+
status: 200,
726+
},
727+
},
728+
lastModified: Date.now(),
729+
shouldBypassTagCache: true,
730+
});
731+
732+
const result = await cache.get("key", {
733+
kind: "FETCH",
734+
softTags: ["_N_T_/path"],
735+
});
736+
737+
expect(getFetchCacheSpy).toHaveBeenCalled();
738+
expect(tagCache.getLastModified).not.toHaveBeenCalled();
739+
expect(tagCache.hasBeenRevalidated).not.toHaveBeenCalled();
740+
expect(result).not.toBeNull();
741+
});
742+
});
743+
744+
describe("incremental cache", () => {
745+
it("Should bypass tag cache validation when shouldBypassTagCache is true", async () => {
746+
incrementalCache.get.mockResolvedValueOnce({
747+
value: {
748+
type: "route",
749+
body: "{}",
750+
},
751+
lastModified: Date.now(),
752+
shouldBypassTagCache: true,
753+
});
754+
755+
const result = await cache.get("key", { kindHint: "app" });
756+
757+
expect(getIncrementalCache).toHaveBeenCalled();
758+
expect(tagCache.getLastModified).not.toHaveBeenCalled();
759+
expect(tagCache.hasBeenRevalidated).not.toHaveBeenCalled();
760+
expect(result).not.toBeNull();
761+
expect(result?.value?.kind).toEqual("ROUTE");
762+
});
763+
764+
it("Should not bypass tag cache validation when shouldBypassTagCache is false", async () => {
765+
globalThis.tagCache.mode = "nextMode";
766+
incrementalCache.get.mockResolvedValueOnce({
767+
value: {
768+
type: "route",
769+
body: "{}",
770+
},
771+
lastModified: Date.now(),
772+
shouldBypassTagCache: false,
773+
});
774+
775+
const result = await cache.get("key", { kindHint: "app" });
776+
777+
expect(getIncrementalCache).toHaveBeenCalled();
778+
expect(tagCache.hasBeenRevalidated).toHaveBeenCalled();
779+
expect(result).not.toBeNull();
780+
});
781+
782+
it("Should return null when tag cache indicates revalidation and shouldBypassTagCache is false", async () => {
783+
globalThis.tagCache.mode = "nextMode";
784+
tagCache.hasBeenRevalidated.mockResolvedValueOnce(true);
785+
incrementalCache.get.mockResolvedValueOnce({
786+
value: {
787+
type: "route",
788+
body: "{}",
789+
},
790+
lastModified: Date.now(),
791+
shouldBypassTagCache: false,
792+
});
793+
794+
const result = await cache.get("key", { kindHint: "app" });
795+
796+
expect(getIncrementalCache).toHaveBeenCalled();
797+
expect(tagCache.hasBeenRevalidated).toHaveBeenCalled();
798+
expect(result).toBeNull();
799+
});
800+
801+
it("Should return value when tag cache indicates revalidation but shouldBypassTagCache is true", async () => {
802+
incrementalCache.get.mockResolvedValueOnce({
803+
value: {
804+
type: "route",
805+
body: "{}",
806+
},
807+
lastModified: Date.now(),
808+
shouldBypassTagCache: true,
809+
});
810+
811+
const result = await cache.get("key", { kindHint: "app" });
812+
813+
expect(getIncrementalCache).toHaveBeenCalled();
814+
expect(tagCache.getLastModified).not.toHaveBeenCalled();
815+
expect(tagCache.hasBeenRevalidated).not.toHaveBeenCalled();
816+
expect(result).not.toBeNull();
817+
expect(result?.value?.kind).toEqual("ROUTE");
818+
});
819+
});
820+
});
624821
});

0 commit comments

Comments
 (0)