- {showSidebarLogo && (
+ {!isThemeLoading && showSidebarLogo && (
Date: Thu, 3 Oct 2024 09:07:43 -0700
Subject: [PATCH 06/25] refactor combine test cases
---
src/hooks/useTheme.test.ts | 86 ++++++++++++++++++--------------------
1 file changed, 40 insertions(+), 46 deletions(-)
diff --git a/src/hooks/useTheme.test.ts b/src/hooks/useTheme.test.ts
index 803b9ec8a1..cb3d30fad3 100644
--- a/src/hooks/useTheme.test.ts
+++ b/src/hooks/useTheme.test.ts
@@ -86,50 +86,44 @@ describe("useTheme", () => {
expect(activateTheme).toHaveBeenCalledOnce();
});
- it("overrides activeTheme when showSidebarLoto policy is true in managed storage", async () => {
- jest.mocked(readManagedStorageByKey).mockResolvedValue(true);
-
- const { result, waitForNextUpdate } = renderHook(() => useTheme());
-
- await waitForNextUpdate();
-
- expect(result.current.activeTheme.showSidebarLogo).toBe(true);
- });
-
- it("overrides activeTheme when showSidebarLogo policy is false in managed storage", async () => {
- jest.mocked(readManagedStorageByKey).mockResolvedValue(false);
-
- const { result, waitForNextUpdate } = renderHook(() => useTheme());
-
- await waitForNextUpdate();
-
- expect(result.current.activeTheme.showSidebarLogo).toBe(false);
- });
-
- it("uses default activeTheme when showSidebarLogo is undefined in managed storage", async () => {
- // eslint-disable-next-line no-restricted-syntax -- this func requires a parameter
- jest.mocked(readManagedStorageByKey).mockResolvedValue(undefined);
-
- const { result, waitForNextUpdate } = renderHook(() => useTheme());
-
- await waitForNextUpdate();
-
- expect(result.current.activeTheme.showSidebarLogo).toBe(
- initialTheme.showSidebarLogo,
- );
- });
-
- it("uses default activeTheme when an error occurs while fetching from managed storage", async () => {
- jest
- .mocked(readManagedStorageByKey)
- .mockRejectedValue(new Error("Managed storage error"));
-
- const { result, waitForNextUpdate } = renderHook(() => useTheme());
-
- await waitForNextUpdate();
-
- expect(result.current.activeTheme.showSidebarLogo).toBe(
- initialTheme.showSidebarLogo,
- );
- });
+ it.each([
+ { policyValue: true, expected: true },
+ { policyValue: false, expected: false },
+ ])(
+ "overrides activeTheme when showSidebarLogo policy is $policyValue in managed storage",
+ async ({ policyValue, expected }) => {
+ jest.mocked(readManagedStorageByKey).mockResolvedValue(policyValue);
+
+ const { result, waitForNextUpdate } = renderHook(() => useTheme());
+
+ await waitForNextUpdate();
+
+ expect(result.current.activeTheme.showSidebarLogo).toBe(expected);
+ },
+ );
+
+ it.each([
+ { scenario: "showSidebarLogo is undefined", mockPolicyValue: undefined },
+ {
+ scenario: "error occurs",
+ mockPolicyValue: new Error("Managed storage error"),
+ },
+ ])(
+ "uses default activeTheme when $scenario in managed storage",
+ async ({ mockPolicyValue }) => {
+ if (mockPolicyValue instanceof Error) {
+ jest.mocked(readManagedStorageByKey).mockRejectedValue(mockPolicyValue);
+ } else {
+ jest.mocked(readManagedStorageByKey).mockResolvedValue(mockPolicyValue);
+ }
+
+ const { result, waitForNextUpdate } = renderHook(() => useTheme());
+
+ await waitForNextUpdate();
+
+ expect(result.current.activeTheme.showSidebarLogo).toBe(
+ initialTheme.showSidebarLogo,
+ );
+ },
+ );
});
From 3924d4de590d81bebdfa7ae4804e58f0e52e65b2 Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 3 Oct 2024 09:31:47 -0700
Subject: [PATCH 07/25] add add custom theme to test cases
---
src/hooks/useTheme.test.ts | 37 +++++++++++++++++++++++++++++--------
1 file changed, 29 insertions(+), 8 deletions(-)
diff --git a/src/hooks/useTheme.test.ts b/src/hooks/useTheme.test.ts
index cb3d30fad3..6d2a8d0917 100644
--- a/src/hooks/useTheme.test.ts
+++ b/src/hooks/useTheme.test.ts
@@ -32,6 +32,18 @@ jest.mock("@/hooks/useAsyncExternalStore");
jest.mock("@/background/messenger/api");
jest.mock("@/store/enterprise/managedStorage");
+const customTheme = {
+ themeName: "custom",
+ showSidebarLogo: true,
+ customSidebarLogo: "https://example.com/custom-logo.png",
+ toolbarIcon: "https://example.com/custom-icon.svg",
+ logo: {
+ regular: "https://example.com/custom-logo-regular.png",
+ small: "https://example.com/custom-logo-small.png",
+ },
+ lastFetched: Date.now(),
+};
+
describe("useTheme", () => {
beforeEach(async () => {
jest
@@ -86,19 +98,23 @@ describe("useTheme", () => {
expect(activateTheme).toHaveBeenCalledOnce();
});
- it.each([
- { policyValue: true, expected: true },
- { policyValue: false, expected: false },
- ])(
+ it.each([{ policyValue: true }, { policyValue: false }])(
"overrides activeTheme when showSidebarLogo policy is $policyValue in managed storage",
- async ({ policyValue, expected }) => {
+ async ({ policyValue }) => {
+ jest.mocked(useAsyncExternalStore).mockReturnValue({
+ data: { ...customTheme, showSidebarLogo: !policyValue },
+ isLoading: false,
+ } as AsyncState);
jest.mocked(readManagedStorageByKey).mockResolvedValue(policyValue);
const { result, waitForNextUpdate } = renderHook(() => useTheme());
await waitForNextUpdate();
- expect(result.current.activeTheme.showSidebarLogo).toBe(expected);
+ expect(result.current.activeTheme).toMatchObject({
+ ...customTheme,
+ showSidebarLogo: policyValue,
+ });
},
);
@@ -109,8 +125,13 @@ describe("useTheme", () => {
mockPolicyValue: new Error("Managed storage error"),
},
])(
- "uses default activeTheme when $scenario in managed storage",
+ "uses activeTheme when $scenario in managed storage",
async ({ mockPolicyValue }) => {
+ jest.mocked(useAsyncExternalStore).mockReturnValue({
+ data: customTheme,
+ isLoading: false,
+ } as AsyncState);
+
if (mockPolicyValue instanceof Error) {
jest.mocked(readManagedStorageByKey).mockRejectedValue(mockPolicyValue);
} else {
@@ -122,7 +143,7 @@ describe("useTheme", () => {
await waitForNextUpdate();
expect(result.current.activeTheme.showSidebarLogo).toBe(
- initialTheme.showSidebarLogo,
+ customTheme.showSidebarLogo,
);
},
);
From ebba63ff6f7cdc01f99546f50d67b8b3614f93ca Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 3 Oct 2024 09:32:42 -0700
Subject: [PATCH 08/25] deck version number in code comment
---
src/store/enterprise/managedStorageTypes.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/store/enterprise/managedStorageTypes.ts b/src/store/enterprise/managedStorageTypes.ts
index 6a9c631959..15a522dec5 100644
--- a/src/store/enterprise/managedStorageTypes.ts
+++ b/src/store/enterprise/managedStorageTypes.ts
@@ -75,7 +75,7 @@ export type ManagedStorageState = {
disableBrowserWarning?: boolean;
/**
* Controls the visibility of the PixieBrix sidebar logo. Overrides the team theme, if one exists.
- * @since 2.1.4
+ * @since 2.1.3
*/
showSidebarLogo?: boolean;
};
From 1370d6a3ec496c89a1b994441160743114115ec1 Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 3 Oct 2024 10:20:40 -0700
Subject: [PATCH 09/25] refactor use useManagedStorageState instead of
readManagedStorageByKey
---
src/hooks/useTheme.test.ts | 59 +++++++++++++++++++++-----------------
src/hooks/useTheme.ts | 9 +++---
2 files changed, 37 insertions(+), 31 deletions(-)
diff --git a/src/hooks/useTheme.test.ts b/src/hooks/useTheme.test.ts
index 6d2a8d0917..58e51e6184 100644
--- a/src/hooks/useTheme.test.ts
+++ b/src/hooks/useTheme.test.ts
@@ -22,7 +22,7 @@ import { initialTheme } from "@/themes/themeStore";
import { type AsyncState } from "@/types/sliceTypes";
import { themeStorage } from "@/themes/themeUtils";
import { activateTheme } from "@/background/messenger/api";
-import { readManagedStorageByKey } from "@/store/enterprise/managedStorage";
+import useManagedStorageState from "@/store/enterprise/useManagedStorageState";
afterEach(() => {
jest.clearAllMocks();
@@ -30,7 +30,7 @@ afterEach(() => {
jest.mock("@/hooks/useAsyncExternalStore");
jest.mock("@/background/messenger/api");
-jest.mock("@/store/enterprise/managedStorage");
+jest.mock("@/store/enterprise/useManagedStorageState");
const customTheme = {
themeName: "custom",
@@ -49,16 +49,14 @@ describe("useTheme", () => {
jest
.mocked(useAsyncExternalStore)
.mockReturnValue({ data: initialTheme, isLoading: false } as AsyncState);
- // eslint-disable-next-line no-restricted-syntax -- this func requires a parameter
- jest.mocked(readManagedStorageByKey).mockResolvedValue(undefined);
+ jest.mocked(useManagedStorageState).mockReturnValue({
+ data: {},
+ isLoading: false,
+ });
});
test("calls useAsyncExternalStore and gets current theme state", async () => {
- const { result: themeResult, waitForNextUpdate } = renderHook(() =>
- useTheme(),
- );
-
- await waitForNextUpdate();
+ const { result: themeResult } = renderHook(() => useTheme());
expect(useAsyncExternalStore).toHaveBeenNthCalledWith(
1,
@@ -79,7 +77,7 @@ describe("useTheme", () => {
});
});
- it("calls activateTheme after loading is done and it hasn't been called recently", async () => {
+ it("calls activateTheme after loading is done and it hasn't been called recently", () => {
jest.useFakeTimers();
jest.mocked(useAsyncExternalStore).mockReturnValue({
@@ -87,14 +85,14 @@ describe("useTheme", () => {
isLoading: false,
} as AsyncState);
- let result = renderHook(() => useTheme());
- await result.waitForNextUpdate();
+ renderHook(() => useTheme());
+
expect(activateTheme).not.toHaveBeenCalled();
jest.advanceTimersByTime(125_000);
- result = renderHook(() => useTheme());
- await result.waitForNextUpdate();
+ renderHook(() => useTheme());
+
expect(activateTheme).toHaveBeenCalledOnce();
});
@@ -105,11 +103,12 @@ describe("useTheme", () => {
data: { ...customTheme, showSidebarLogo: !policyValue },
isLoading: false,
} as AsyncState);
- jest.mocked(readManagedStorageByKey).mockResolvedValue(policyValue);
-
- const { result, waitForNextUpdate } = renderHook(() => useTheme());
+ jest.mocked(useManagedStorageState).mockReturnValue({
+ data: { showSidebarLogo: policyValue },
+ isLoading: false,
+ });
- await waitForNextUpdate();
+ const { result } = renderHook(() => useTheme());
expect(result.current.activeTheme).toMatchObject({
...customTheme,
@@ -119,28 +118,34 @@ describe("useTheme", () => {
);
it.each([
- { scenario: "showSidebarLogo is undefined", mockPolicyValue: undefined },
+ {
+ scenario: "showSidebarLogo is undefined",
+ mockManagedStorageResult: undefined,
+ },
{
scenario: "error occurs",
- mockPolicyValue: new Error("Managed storage error"),
+ mockManagedStorageResult: new Error("Managed storage error"),
},
])(
"uses activeTheme when $scenario in managed storage",
- async ({ mockPolicyValue }) => {
+ async ({ mockManagedStorageResult }) => {
jest.mocked(useAsyncExternalStore).mockReturnValue({
data: customTheme,
isLoading: false,
} as AsyncState);
- if (mockPolicyValue instanceof Error) {
- jest.mocked(readManagedStorageByKey).mockRejectedValue(mockPolicyValue);
+ if (mockManagedStorageResult instanceof Error) {
+ jest.mocked(useManagedStorageState).mockImplementation(() => {
+ throw mockManagedStorageResult;
+ });
} else {
- jest.mocked(readManagedStorageByKey).mockResolvedValue(mockPolicyValue);
+ jest.mocked(useManagedStorageState).mockReturnValue({
+ data: mockManagedStorageResult,
+ isLoading: false,
+ });
}
- const { result, waitForNextUpdate } = renderHook(() => useTheme());
-
- await waitForNextUpdate();
+ const { result } = renderHook(() => useTheme());
expect(result.current.activeTheme.showSidebarLogo).toBe(
customTheme.showSidebarLogo,
diff --git a/src/hooks/useTheme.ts b/src/hooks/useTheme.ts
index b6f827279a..001f0c1b31 100644
--- a/src/hooks/useTheme.ts
+++ b/src/hooks/useTheme.ts
@@ -25,8 +25,7 @@ import {
import { initialTheme } from "@/themes/themeStore";
import useAsyncExternalStore from "@/hooks/useAsyncExternalStore";
import { activateTheme } from "@/background/messenger/api";
-import useAsyncState from "@/hooks/useAsyncState";
-import { readManagedStorageByKey } from "@/store/enterprise/managedStorage";
+import useManagedStorageState from "@/store/enterprise/useManagedStorageState";
const themeStorageSubscribe = (callback: () => void) => {
const abortController = new AbortController();
@@ -47,8 +46,10 @@ function useTheme(): { activeTheme: ThemeAssets; isLoading: boolean } {
const { data: cachedTheme, isLoading: isCachedThemeLoading } =
useAsyncExternalStore(themeStorageSubscribe, themeStorage.get);
- const { data: showSidebarLogoOverride, isLoading: isManagedStorageLoading } =
- useAsyncState(async () => readManagedStorageByKey("showSidebarLogo"), []);
+ const { data: managedStorageState, isLoading: isManagedStorageLoading } =
+ useManagedStorageState();
+
+ const showSidebarLogoOverride = managedStorageState?.showSidebarLogo;
const isLoading = isManagedStorageLoading || isCachedThemeLoading;
From cb2355f4b44db634af0d3b9e0eb4d256bb17959d Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 3 Oct 2024 12:36:48 -0700
Subject: [PATCH 10/25] make test cases complete
---
src/hooks/useTheme.test.ts | 59 +++++++++++++++++---------------------
1 file changed, 26 insertions(+), 33 deletions(-)
diff --git a/src/hooks/useTheme.test.ts b/src/hooks/useTheme.test.ts
index 6d2a8d0917..0ad8ccce25 100644
--- a/src/hooks/useTheme.test.ts
+++ b/src/hooks/useTheme.test.ts
@@ -98,11 +98,18 @@ describe("useTheme", () => {
expect(activateTheme).toHaveBeenCalledOnce();
});
- it.each([{ policyValue: true }, { policyValue: false }])(
- "overrides activeTheme when showSidebarLogo policy is $policyValue in managed storage",
- async ({ policyValue }) => {
+ it.each([
+ { policyValue: true, themeValue: true, expectedValue: true },
+ { policyValue: true, themeValue: false, expectedValue: true },
+ { policyValue: false, themeValue: true, expectedValue: false },
+ { policyValue: false, themeValue: false, expectedValue: false },
+ { policyValue: undefined, themeValue: true, expectedValue: true },
+ { policyValue: undefined, themeValue: false, expectedValue: false },
+ ])(
+ "handles showSidebarLogo policy (policy: $policyValue, theme: $themeValue, expected: $expectedValue)",
+ async ({ policyValue, themeValue, expectedValue }) => {
jest.mocked(useAsyncExternalStore).mockReturnValue({
- data: { ...customTheme, showSidebarLogo: !policyValue },
+ data: { ...customTheme, showSidebarLogo: themeValue },
isLoading: false,
} as AsyncState);
jest.mocked(readManagedStorageByKey).mockResolvedValue(policyValue);
@@ -111,40 +118,26 @@ describe("useTheme", () => {
await waitForNextUpdate();
- expect(result.current.activeTheme).toMatchObject({
- ...customTheme,
- showSidebarLogo: policyValue,
- });
+ expect(result.current.activeTheme.showSidebarLogo).toBe(expectedValue);
},
);
- it.each([
- { scenario: "showSidebarLogo is undefined", mockPolicyValue: undefined },
- {
- scenario: "error occurs",
- mockPolicyValue: new Error("Managed storage error"),
- },
- ])(
- "uses activeTheme when $scenario in managed storage",
- async ({ mockPolicyValue }) => {
- jest.mocked(useAsyncExternalStore).mockReturnValue({
- data: customTheme,
- isLoading: false,
- } as AsyncState);
+ it("uses activeTheme when an error occurs in managed storage", async () => {
+ jest.mocked(useAsyncExternalStore).mockReturnValue({
+ data: customTheme,
+ isLoading: false,
+ } as AsyncState);
- if (mockPolicyValue instanceof Error) {
- jest.mocked(readManagedStorageByKey).mockRejectedValue(mockPolicyValue);
- } else {
- jest.mocked(readManagedStorageByKey).mockResolvedValue(mockPolicyValue);
- }
+ jest
+ .mocked(readManagedStorageByKey)
+ .mockRejectedValue(new Error("Managed storage error"));
- const { result, waitForNextUpdate } = renderHook(() => useTheme());
+ const { result, waitForNextUpdate } = renderHook(() => useTheme());
- await waitForNextUpdate();
+ await waitForNextUpdate();
- expect(result.current.activeTheme.showSidebarLogo).toBe(
- customTheme.showSidebarLogo,
- );
- },
- );
+ expect(result.current.activeTheme.showSidebarLogo).toBe(
+ customTheme.showSidebarLogo,
+ );
+ });
});
From bcc470c59d5fcf142521f8918a59e8a60363120b Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 3 Oct 2024 10:20:40 -0700
Subject: [PATCH 11/25] refactor use useManagedStorageState instead of
readManagedStorageByKey
---
src/hooks/useTheme.test.ts | 54 ++++++++++++++++++++------------------
src/hooks/useTheme.ts | 9 ++++---
2 files changed, 34 insertions(+), 29 deletions(-)
diff --git a/src/hooks/useTheme.test.ts b/src/hooks/useTheme.test.ts
index 0ad8ccce25..7329d8a89e 100644
--- a/src/hooks/useTheme.test.ts
+++ b/src/hooks/useTheme.test.ts
@@ -22,7 +22,7 @@ import { initialTheme } from "@/themes/themeStore";
import { type AsyncState } from "@/types/sliceTypes";
import { themeStorage } from "@/themes/themeUtils";
import { activateTheme } from "@/background/messenger/api";
-import { readManagedStorageByKey } from "@/store/enterprise/managedStorage";
+import useManagedStorageState from "@/store/enterprise/useManagedStorageState";
afterEach(() => {
jest.clearAllMocks();
@@ -30,7 +30,7 @@ afterEach(() => {
jest.mock("@/hooks/useAsyncExternalStore");
jest.mock("@/background/messenger/api");
-jest.mock("@/store/enterprise/managedStorage");
+jest.mock("@/store/enterprise/useManagedStorageState");
const customTheme = {
themeName: "custom",
@@ -49,16 +49,14 @@ describe("useTheme", () => {
jest
.mocked(useAsyncExternalStore)
.mockReturnValue({ data: initialTheme, isLoading: false } as AsyncState);
- // eslint-disable-next-line no-restricted-syntax -- this func requires a parameter
- jest.mocked(readManagedStorageByKey).mockResolvedValue(undefined);
+ jest.mocked(useManagedStorageState).mockReturnValue({
+ data: {},
+ isLoading: false,
+ });
});
test("calls useAsyncExternalStore and gets current theme state", async () => {
- const { result: themeResult, waitForNextUpdate } = renderHook(() =>
- useTheme(),
- );
-
- await waitForNextUpdate();
+ const { result: themeResult } = renderHook(() => useTheme());
expect(useAsyncExternalStore).toHaveBeenNthCalledWith(
1,
@@ -79,7 +77,7 @@ describe("useTheme", () => {
});
});
- it("calls activateTheme after loading is done and it hasn't been called recently", async () => {
+ it("calls activateTheme after loading is done and it hasn't been called recently", () => {
jest.useFakeTimers();
jest.mocked(useAsyncExternalStore).mockReturnValue({
@@ -87,14 +85,14 @@ describe("useTheme", () => {
isLoading: false,
} as AsyncState);
- let result = renderHook(() => useTheme());
- await result.waitForNextUpdate();
+ renderHook(() => useTheme());
+
expect(activateTheme).not.toHaveBeenCalled();
jest.advanceTimersByTime(125_000);
- result = renderHook(() => useTheme());
- await result.waitForNextUpdate();
+ renderHook(() => useTheme());
+
expect(activateTheme).toHaveBeenCalledOnce();
});
@@ -112,11 +110,12 @@ describe("useTheme", () => {
data: { ...customTheme, showSidebarLogo: themeValue },
isLoading: false,
} as AsyncState);
- jest.mocked(readManagedStorageByKey).mockResolvedValue(policyValue);
-
- const { result, waitForNextUpdate } = renderHook(() => useTheme());
+ jest.mocked(useManagedStorageState).mockReturnValue({
+ data: { showSidebarLogo: policyValue },
+ isLoading: false,
+ });
- await waitForNextUpdate();
+ const { result } = renderHook(() => useTheme());
expect(result.current.activeTheme.showSidebarLogo).toBe(expectedValue);
},
@@ -128,13 +127,18 @@ describe("useTheme", () => {
isLoading: false,
} as AsyncState);
- jest
- .mocked(readManagedStorageByKey)
- .mockRejectedValue(new Error("Managed storage error"));
-
- const { result, waitForNextUpdate } = renderHook(() => useTheme());
-
- await waitForNextUpdate();
+ if (mockManagedStorageResult instanceof Error) {
+ jest.mocked(useManagedStorageState).mockImplementation(() => {
+ throw mockManagedStorageResult;
+ });
+ } else {
+ jest.mocked(useManagedStorageState).mockReturnValue({
+ data: mockManagedStorageResult,
+ isLoading: false,
+ });
+ }
+
+ const { result } = renderHook(() => useTheme());
expect(result.current.activeTheme.showSidebarLogo).toBe(
customTheme.showSidebarLogo,
diff --git a/src/hooks/useTheme.ts b/src/hooks/useTheme.ts
index b6f827279a..001f0c1b31 100644
--- a/src/hooks/useTheme.ts
+++ b/src/hooks/useTheme.ts
@@ -25,8 +25,7 @@ import {
import { initialTheme } from "@/themes/themeStore";
import useAsyncExternalStore from "@/hooks/useAsyncExternalStore";
import { activateTheme } from "@/background/messenger/api";
-import useAsyncState from "@/hooks/useAsyncState";
-import { readManagedStorageByKey } from "@/store/enterprise/managedStorage";
+import useManagedStorageState from "@/store/enterprise/useManagedStorageState";
const themeStorageSubscribe = (callback: () => void) => {
const abortController = new AbortController();
@@ -47,8 +46,10 @@ function useTheme(): { activeTheme: ThemeAssets; isLoading: boolean } {
const { data: cachedTheme, isLoading: isCachedThemeLoading } =
useAsyncExternalStore(themeStorageSubscribe, themeStorage.get);
- const { data: showSidebarLogoOverride, isLoading: isManagedStorageLoading } =
- useAsyncState(async () => readManagedStorageByKey("showSidebarLogo"), []);
+ const { data: managedStorageState, isLoading: isManagedStorageLoading } =
+ useManagedStorageState();
+
+ const showSidebarLogoOverride = managedStorageState?.showSidebarLogo;
const isLoading = isManagedStorageLoading || isCachedThemeLoading;
From 29b5180dd98bd719371854b9e8a3b58edc5ea748 Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 3 Oct 2024 12:44:56 -0700
Subject: [PATCH 12/25] rebase fixes
---
src/hooks/useTheme.test.ts | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/src/hooks/useTheme.test.ts b/src/hooks/useTheme.test.ts
index 7329d8a89e..d49c0657e3 100644
--- a/src/hooks/useTheme.test.ts
+++ b/src/hooks/useTheme.test.ts
@@ -127,18 +127,11 @@ describe("useTheme", () => {
isLoading: false,
} as AsyncState);
- if (mockManagedStorageResult instanceof Error) {
- jest.mocked(useManagedStorageState).mockImplementation(() => {
- throw mockManagedStorageResult;
- });
- } else {
- jest.mocked(useManagedStorageState).mockReturnValue({
- data: mockManagedStorageResult,
- isLoading: false,
- });
- }
+ jest.mocked(useManagedStorageState).mockImplementation(() => {
+ throw new Error("Managed storage error");
+ });
- const { result } = renderHook(() => useTheme());
+ const { result } = renderHook(() => useTheme());
expect(result.current.activeTheme.showSidebarLogo).toBe(
customTheme.showSidebarLogo,
From 0b71176288772a53625799f76b28655c396c7999 Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 3 Oct 2024 12:53:24 -0700
Subject: [PATCH 13/25] resolve merge issues
---
src/hooks/useTheme.test.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/hooks/useTheme.test.ts b/src/hooks/useTheme.test.ts
index 8d672d23e6..8d0a7b76c3 100644
--- a/src/hooks/useTheme.test.ts
+++ b/src/hooks/useTheme.test.ts
@@ -107,7 +107,7 @@ describe("useTheme", () => {
"handles showSidebarLogo policy (policy: $policyValue, theme: $themeValue, expected: $expectedValue)",
async ({ policyValue, themeValue, expectedValue }) => {
jest.mocked(useAsyncExternalStore).mockReturnValue({
- data: { ...customTheme, showSidebarLogo: !policyValue },
+ data: { ...customTheme, showSidebarLogo: themeValue },
isLoading: false,
} as AsyncState);
jest.mocked(useManagedStorageState).mockReturnValue({
@@ -119,7 +119,7 @@ describe("useTheme", () => {
expect(result.current.activeTheme).toMatchObject({
...customTheme,
- showSidebarLogo: policyValue,
+ showSidebarLogo: expectedValue,
});
},
);
From 9c46ed1a410ff53ca9839aa0da722271b79b919d Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Fri, 4 Oct 2024 14:30:13 -0700
Subject: [PATCH 14/25] replace useManagedStorageState implementation with
useAsyncExternalStore
---
src/auth/useRequiredPartnerAuth.test.tsx | 6 +++--
src/hooks/useTheme.test.ts | 20 ++++++--------
.../enterprise/useManagedStorageState.ts | 27 +++----------------
3 files changed, 16 insertions(+), 37 deletions(-)
diff --git a/src/auth/useRequiredPartnerAuth.test.tsx b/src/auth/useRequiredPartnerAuth.test.tsx
index 62c3b48aca..e94b390d13 100644
--- a/src/auth/useRequiredPartnerAuth.test.tsx
+++ b/src/auth/useRequiredPartnerAuth.test.tsx
@@ -39,6 +39,8 @@ import usePartnerAuthData from "@/auth/usePartnerAuthData";
import { Milestones } from "@/data/model/UserMilestone";
import { getDeploymentKey } from "@/auth/deploymentKey";
import { getExtensionToken } from "@/auth/authStorage";
+import type { AsyncState } from "@/types/sliceTypes";
+import { type ManagedStorageState } from "@/store/enterprise/managedStorageTypes";
jest.mock("@/store/enterprise/useManagedStorageState");
jest.mock("@/auth/usePartnerAuthData");
@@ -57,7 +59,7 @@ beforeEach(() => {
useManagedStorageStateMock.mockReturnValue({
data: {},
isLoading: false,
- });
+ } as AsyncState
);
usePartnerAuthDataMock.mockReturnValue(valueToAsyncState(undefined));
});
@@ -166,7 +168,7 @@ describe("useRequiredPartnerAuth", () => {
useManagedStorageStateMock.mockReturnValue({
data: { partnerId: "automation-anywhere" },
isLoading: false,
- });
+ } as AsyncState);
mockAnonymousMeApiResponse();
diff --git a/src/hooks/useTheme.test.ts b/src/hooks/useTheme.test.ts
index 8d0a7b76c3..3c0c970ca6 100644
--- a/src/hooks/useTheme.test.ts
+++ b/src/hooks/useTheme.test.ts
@@ -22,7 +22,7 @@ import { initialTheme } from "@/themes/themeStore";
import { type AsyncState } from "@/types/sliceTypes";
import { themeStorage } from "@/themes/themeUtils";
import { activateTheme } from "@/background/messenger/api";
-import useManagedStorageState from "@/store/enterprise/useManagedStorageState";
+import { readManagedStorage } from "@/store/enterprise/managedStorage";
afterEach(() => {
jest.clearAllMocks();
@@ -30,7 +30,7 @@ afterEach(() => {
jest.mock("@/hooks/useAsyncExternalStore");
jest.mock("@/background/messenger/api");
-jest.mock("@/store/enterprise/useManagedStorageState");
+jest.mock("@/store/enterprise/managedStorage");
const customTheme = {
themeName: "custom",
@@ -49,10 +49,7 @@ describe("useTheme", () => {
jest
.mocked(useAsyncExternalStore)
.mockReturnValue({ data: initialTheme, isLoading: false } as AsyncState);
- jest.mocked(useManagedStorageState).mockReturnValue({
- data: {},
- isLoading: false,
- });
+ jest.mocked(readManagedStorage).mockResolvedValue({});
});
test("calls useAsyncExternalStore and gets current theme state", async () => {
@@ -110,9 +107,8 @@ describe("useTheme", () => {
data: { ...customTheme, showSidebarLogo: themeValue },
isLoading: false,
} as AsyncState);
- jest.mocked(useManagedStorageState).mockReturnValue({
- data: { showSidebarLogo: policyValue },
- isLoading: false,
+ jest.mocked(readManagedStorage).mockResolvedValue({
+ showSidebarLogo: policyValue,
});
const { result } = renderHook(() => useTheme());
@@ -130,9 +126,9 @@ describe("useTheme", () => {
isLoading: false,
} as AsyncState);
- jest.mocked(useManagedStorageState).mockImplementation(() => {
- throw new Error("Managed storage error");
- });
+ jest
+ .mocked(readManagedStorage)
+ .mockRejectedValue(new Error("Managed storage error"));
const { result } = renderHook(() => useTheme());
diff --git a/src/store/enterprise/useManagedStorageState.ts b/src/store/enterprise/useManagedStorageState.ts
index 6a006d2c4b..8260ae8221 100644
--- a/src/store/enterprise/useManagedStorageState.ts
+++ b/src/store/enterprise/useManagedStorageState.ts
@@ -15,21 +15,12 @@
* along with this program. If not, see .
*/
-import { useSyncExternalStore } from "use-sync-external-store/shim";
import {
- getSnapshot,
- initManagedStorage,
managedStorageStateChange,
+ readManagedStorage,
} from "@/store/enterprise/managedStorage";
-import { useEffect } from "react";
-import type { ManagedStorageState } from "@/store/enterprise/managedStorageTypes";
-import type { Nullishable } from "@/utils/nullishUtils";
import { expectContext } from "@/utils/expectContext";
-
-type HookState = {
- data: Nullishable;
- isLoading: boolean;
-};
+import useAsyncExternalStore from "@/hooks/useAsyncExternalStore";
// NOTE: can't share subscribe methods across generators currently for useAsyncExternalStore because it maintains
// a map of subscriptions to state controllers. See https://github.com/pixiebrix/pixiebrix-extension/issues/7789
@@ -46,18 +37,8 @@ function subscribe(callback: () => void): () => void {
/**
* React hook to get the current state of managed storage.
*/
-function useManagedStorageState(): HookState {
- useEffect(() => {
- // `initManagedStorage` is wrapped in once, so safe to call from multiple locations in the tree.
- void initManagedStorage();
- }, []);
-
- const data = useSyncExternalStore(subscribe, getSnapshot);
-
- return {
- data,
- isLoading: data == null,
- };
+function useManagedStorageState() {
+ return useAsyncExternalStore(subscribe, readManagedStorage);
}
export default useManagedStorageState;
From ce8a6ac8037b437d1a40e57ab61e3f18d7f04bb9 Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Fri, 4 Oct 2024 15:08:37 -0700
Subject: [PATCH 15/25] make some test accomodations for hook changes
---
src/hooks/useTheme.test.ts | 105 ++++++++++++++++++++++---------------
1 file changed, 62 insertions(+), 43 deletions(-)
diff --git a/src/hooks/useTheme.test.ts b/src/hooks/useTheme.test.ts
index 3c0c970ca6..c19f07c720 100644
--- a/src/hooks/useTheme.test.ts
+++ b/src/hooks/useTheme.test.ts
@@ -17,23 +17,32 @@
import useTheme from "@/hooks/useTheme";
import { renderHook } from "@/pageEditor/testHelpers";
-import useAsyncExternalStore from "@/hooks/useAsyncExternalStore";
import { initialTheme } from "@/themes/themeStore";
-import { type AsyncState } from "@/types/sliceTypes";
-import { themeStorage } from "@/themes/themeUtils";
+import { type ThemeAssets, themeStorage } from "@/themes/themeUtils";
import { activateTheme } from "@/background/messenger/api";
import { readManagedStorage } from "@/store/enterprise/managedStorage";
+jest.mock("@/themes/themeUtils", () => ({
+ ...jest.requireActual("@/themes/themeUtils"),
+ themeStorage: {
+ get: jest.fn(),
+ onChanged: jest.fn(),
+ },
+}));
+
+jest.mock("@/store/enterprise/managedStorage", () => ({
+ ...jest.requireActual("@/store/enterprise/managedStorage"),
+ readManagedStorage: jest.fn(),
+}));
+
afterEach(() => {
jest.clearAllMocks();
});
-jest.mock("@/hooks/useAsyncExternalStore");
jest.mock("@/background/messenger/api");
-jest.mock("@/store/enterprise/managedStorage");
-const customTheme = {
- themeName: "custom",
+const customTheme: ThemeAssets = {
+ themeName: "default",
showSidebarLogo: true,
customSidebarLogo: "https://example.com/custom-logo.png",
toolbarIcon: "https://example.com/custom-icon.svg",
@@ -46,26 +55,31 @@ const customTheme = {
describe("useTheme", () => {
beforeEach(async () => {
- jest
- .mocked(useAsyncExternalStore)
- .mockReturnValue({ data: initialTheme, isLoading: false } as AsyncState);
+ jest.mocked(themeStorage.get).mockResolvedValue({
+ ...initialTheme,
+ lastFetched: Date.now(),
+ });
jest.mocked(readManagedStorage).mockResolvedValue({});
});
- test("calls useAsyncExternalStore and gets current theme state", async () => {
- const { result: themeResult } = renderHook(() => useTheme());
+ afterEach(() => {
+ jest.useRealTimers();
+ });
- expect(useAsyncExternalStore).toHaveBeenNthCalledWith(
- 1,
- expect.any(Function),
- themeStorage.get,
+ test("calls themeStorage to get the current theme state", async () => {
+ const { result: themeResult, waitForNextUpdate } = renderHook(() =>
+ useTheme(),
);
- expect(themeResult.current).toStrictEqual({
+ await waitForNextUpdate();
+
+ expect(themeStorage.get).toHaveBeenCalledOnce();
+
+ expect(themeResult.current).toMatchObject({
activeTheme: {
themeName: "default",
customSidebarLogo: null,
- lastFetched: null,
+ lastFetched: expect.any(Number),
logo: { regular: "test-file-stub", small: "test-file-stub" },
showSidebarLogo: true,
toolbarIcon: null,
@@ -74,14 +88,8 @@ describe("useTheme", () => {
});
});
- it("calls activateTheme after loading is done and it hasn't been called recently", () => {
+ it("calls activateTheme after loading is done and it hasn't been called recently", async () => {
jest.useFakeTimers();
-
- jest.mocked(useAsyncExternalStore).mockReturnValue({
- data: { ...initialTheme, lastFetched: Date.now() },
- isLoading: false,
- } as AsyncState);
-
renderHook(() => useTheme());
expect(activateTheme).not.toHaveBeenCalled();
@@ -103,37 +111,48 @@ describe("useTheme", () => {
])(
"handles showSidebarLogo policy (policy: $policyValue, theme: $themeValue, expected: $expectedValue)",
async ({ policyValue, themeValue, expectedValue }) => {
- jest.mocked(useAsyncExternalStore).mockReturnValue({
- data: { ...customTheme, showSidebarLogo: themeValue },
- isLoading: false,
- } as AsyncState);
+ jest.mocked(themeStorage.get).mockResolvedValue({
+ ...customTheme,
+ showSidebarLogo: themeValue,
+ lastFetched: Date.now(),
+ });
+
jest.mocked(readManagedStorage).mockResolvedValue({
showSidebarLogo: policyValue,
});
- const { result } = renderHook(() => useTheme());
+ const { result, waitForNextUpdate } = renderHook(() => useTheme());
+
+ await waitForNextUpdate();
expect(result.current.activeTheme).toMatchObject({
...customTheme,
+ lastFetched: expect.any(Number),
showSidebarLogo: expectedValue,
});
},
);
- it("uses activeTheme when an error occurs in managed storage", async () => {
- jest.mocked(useAsyncExternalStore).mockReturnValue({
- data: customTheme,
- isLoading: false,
- } as AsyncState);
+ it.each([{ showSidebarLogo: true }, { showSidebarLogo: false }])(
+ "uses activeTheme when an error occurs in managed storage (showSidebarLogo: $showSidebarLogo)",
+ async ({ showSidebarLogo }) => {
+ const customThemeWithSidebarLogo = {
+ ...customTheme,
+ showSidebarLogo,
+ lastFetched: Date.now(),
+ };
- jest
- .mocked(readManagedStorage)
- .mockRejectedValue(new Error("Managed storage error"));
+ jest
+ .mocked(themeStorage.get)
+ .mockResolvedValue(customThemeWithSidebarLogo);
- const { result } = renderHook(() => useTheme());
+ jest
+ .mocked(readManagedStorage)
+ .mockRejectedValue(new Error("Managed storage error"));
- expect(result.current.activeTheme.showSidebarLogo).toBe(
- customTheme.showSidebarLogo,
- );
- });
+ const { result } = renderHook(() => useTheme());
+
+ expect(result.current.activeTheme.showSidebarLogo).toBe(showSidebarLogo);
+ },
+ );
});
From b584c2acc0b3564b42dc30daec32cc790bdf92e6 Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Mon, 7 Oct 2024 15:18:26 -0700
Subject: [PATCH 16/25] fix one useManagedStorageState unit test
---
.../enterprise/useManagedStorageState.test.ts | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/src/store/enterprise/useManagedStorageState.test.ts b/src/store/enterprise/useManagedStorageState.test.ts
index 8419b25b28..78e4735e20 100644
--- a/src/store/enterprise/useManagedStorageState.test.ts
+++ b/src/store/enterprise/useManagedStorageState.test.ts
@@ -28,8 +28,14 @@ describe("useManagedStorageState", () => {
it("waits on uninitialized state", async () => {
const { result, waitFor } = renderHook(() => useManagedStorageState());
expect(result.current).toStrictEqual({
+ currentData: undefined,
data: undefined,
+ error: undefined,
+ isError: false,
+ isFetching: true,
isLoading: true,
+ isSuccess: false,
+ isUninitialized: false,
});
await waitFor(
@@ -55,10 +61,19 @@ describe("useManagedStorageState", () => {
await waitForNextUpdate();
expect(result.current).toStrictEqual({
+ currentData: {
+ partnerId: "taco-bell",
+ },
data: {
partnerId: "taco-bell",
},
+ error: undefined,
+ isError: false,
+ isFetching: false,
isLoading: false,
+ isSuccess: true,
+ isUninitialized: false,
+ refetch: expect.any(Function),
});
});
From ef2c604ec1812537d7eb5ab4dd61c63fd74437c8 Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 10 Oct 2024 10:41:28 -0700
Subject: [PATCH 17/25] apply lastFetched to test
---
src/hooks/useTheme.test.ts | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/hooks/useTheme.test.ts b/src/hooks/useTheme.test.ts
index c19f07c720..d4e651f340 100644
--- a/src/hooks/useTheme.test.ts
+++ b/src/hooks/useTheme.test.ts
@@ -111,10 +111,11 @@ describe("useTheme", () => {
])(
"handles showSidebarLogo policy (policy: $policyValue, theme: $themeValue, expected: $expectedValue)",
async ({ policyValue, themeValue, expectedValue }) => {
+ const lastFetched = Date.now();
jest.mocked(themeStorage.get).mockResolvedValue({
...customTheme,
showSidebarLogo: themeValue,
- lastFetched: Date.now(),
+ lastFetched,
});
jest.mocked(readManagedStorage).mockResolvedValue({
@@ -127,7 +128,7 @@ describe("useTheme", () => {
expect(result.current.activeTheme).toMatchObject({
...customTheme,
- lastFetched: expect.any(Number),
+ lastFetched,
showSidebarLogo: expectedValue,
});
},
From 165be3a14921d8eb5923084939a4b2895b8f9b58 Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 10 Oct 2024 11:13:49 -0700
Subject: [PATCH 18/25] fix 'waits on uninitialized state' test
---
src/hooks/useTheme.test.ts | 8 ++++-
.../enterprise/useManagedStorageState.test.ts | 33 +++++++------------
2 files changed, 19 insertions(+), 22 deletions(-)
diff --git a/src/hooks/useTheme.test.ts b/src/hooks/useTheme.test.ts
index d4e651f340..9337407fa4 100644
--- a/src/hooks/useTheme.test.ts
+++ b/src/hooks/useTheme.test.ts
@@ -20,7 +20,10 @@ import { renderHook } from "@/pageEditor/testHelpers";
import { initialTheme } from "@/themes/themeStore";
import { type ThemeAssets, themeStorage } from "@/themes/themeUtils";
import { activateTheme } from "@/background/messenger/api";
-import { readManagedStorage } from "@/store/enterprise/managedStorage";
+import {
+ INTERNAL_reset,
+ readManagedStorage,
+} from "@/store/enterprise/managedStorage";
jest.mock("@/themes/themeUtils", () => ({
...jest.requireActual("@/themes/themeUtils"),
@@ -55,6 +58,9 @@ const customTheme: ThemeAssets = {
describe("useTheme", () => {
beforeEach(async () => {
+ await INTERNAL_reset();
+ await browser.storage.managed.clear();
+
jest.mocked(themeStorage.get).mockResolvedValue({
...initialTheme,
lastFetched: Date.now(),
diff --git a/src/store/enterprise/useManagedStorageState.test.ts b/src/store/enterprise/useManagedStorageState.test.ts
index 78e4735e20..c97ee73a59 100644
--- a/src/store/enterprise/useManagedStorageState.test.ts
+++ b/src/store/enterprise/useManagedStorageState.test.ts
@@ -18,6 +18,10 @@
import { INTERNAL_reset } from "@/store/enterprise/managedStorage";
import { renderHook } from "@testing-library/react-hooks";
import useManagedStorageState from "@/store/enterprise/useManagedStorageState";
+import {
+ loadingAsyncStateFactory,
+ valueToAsyncState,
+} from "@/utils/asyncStateUtils";
beforeEach(async () => {
await INTERNAL_reset();
@@ -26,29 +30,16 @@ beforeEach(async () => {
describe("useManagedStorageState", () => {
it("waits on uninitialized state", async () => {
- const { result, waitFor } = renderHook(() => useManagedStorageState());
- expect(result.current).toStrictEqual({
- currentData: undefined,
- data: undefined,
- error: undefined,
- isError: false,
- isFetching: true,
- isLoading: true,
- isSuccess: false,
- isUninitialized: false,
+ const { result, waitForNextUpdate } = renderHook(() =>
+ useManagedStorageState(),
+ );
+ expect(result.current).toStrictEqual(loadingAsyncStateFactory());
+
+ await waitForNextUpdate({
+ timeout: 5000,
});
- await waitFor(
- () => {
- expect(result.current).toStrictEqual({
- data: {},
- isLoading: false,
- });
- },
- // XXX: figure out how to use fake timers to avoid slowing down test suite
- // Must be longer than MAX_MANAGED_STORAGE_WAIT_MILLIS
- { timeout: 5000 },
- );
+ expect(result.current).toStrictEqual(valueToAsyncState({}));
});
it("handles already initialized state", async () => {
From 083ee39afe0f742f24d86b266e4bea5a2fcdb98d Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 10 Oct 2024 11:16:52 -0700
Subject: [PATCH 19/25] add comment
---
.../enterprise/useManagedStorageState.test.ts | 21 +++++--------------
1 file changed, 5 insertions(+), 16 deletions(-)
diff --git a/src/store/enterprise/useManagedStorageState.test.ts b/src/store/enterprise/useManagedStorageState.test.ts
index c97ee73a59..b6b037be74 100644
--- a/src/store/enterprise/useManagedStorageState.test.ts
+++ b/src/store/enterprise/useManagedStorageState.test.ts
@@ -36,6 +36,7 @@ describe("useManagedStorageState", () => {
expect(result.current).toStrictEqual(loadingAsyncStateFactory());
await waitForNextUpdate({
+ // `readManagedStorage` will take a few seconds if there are no policies set
timeout: 5000,
});
@@ -43,7 +44,7 @@ describe("useManagedStorageState", () => {
});
it("handles already initialized state", async () => {
- await browser.storage.managed.set({ partnerId: "taco-bell" });
+ await browser.storage.managed.set({ partnerId: "foo" });
const { result, waitForNextUpdate } = renderHook(() =>
useManagedStorageState(),
@@ -51,21 +52,9 @@ describe("useManagedStorageState", () => {
await waitForNextUpdate();
- expect(result.current).toStrictEqual({
- currentData: {
- partnerId: "taco-bell",
- },
- data: {
- partnerId: "taco-bell",
- },
- error: undefined,
- isError: false,
- isFetching: false,
- isLoading: false,
- isSuccess: true,
- isUninitialized: false,
- refetch: expect.any(Function),
- });
+ expect(result.current).toStrictEqual(
+ valueToAsyncState({ partnerId: "foo" }),
+ );
});
// Can't test because mock doesn't fire change events: https://github.com/clarkbw/jest-webextension-mock/issues/170
From 2dfd26df965bb9c86568e13806e39e8e7e0252c0 Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 10 Oct 2024 11:20:25 -0700
Subject: [PATCH 20/25] fix individual useManagedStorageState tests, no
including test inteference
---
.../enterprise/useManagedStorageState.test.ts | 20 +++++++++----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/src/store/enterprise/useManagedStorageState.test.ts b/src/store/enterprise/useManagedStorageState.test.ts
index b6b037be74..6f4c23d143 100644
--- a/src/store/enterprise/useManagedStorageState.test.ts
+++ b/src/store/enterprise/useManagedStorageState.test.ts
@@ -44,7 +44,8 @@ describe("useManagedStorageState", () => {
});
it("handles already initialized state", async () => {
- await browser.storage.managed.set({ partnerId: "foo" });
+ const expectedPolicy = { partnerId: "foo" };
+ await browser.storage.managed.set(expectedPolicy);
const { result, waitForNextUpdate } = renderHook(() =>
useManagedStorageState(),
@@ -52,22 +53,19 @@ describe("useManagedStorageState", () => {
await waitForNextUpdate();
- expect(result.current).toStrictEqual(
- valueToAsyncState({ partnerId: "foo" }),
- );
+ expect(result.current).toStrictEqual(valueToAsyncState(expectedPolicy));
});
- // Can't test because mock doesn't fire change events: https://github.com/clarkbw/jest-webextension-mock/issues/170
- it.skip("listens for changes", async () => {
+ it("listens for changes", async () => {
const { result, waitForNextUpdate } = renderHook(() =>
useManagedStorageState(),
);
expect(result.current.data).toBeUndefined();
- await browser.storage.managed.set({ partnerId: "taco-bell" });
+
+ const expectedPolicy = { partnerId: "foo" };
+ await browser.storage.managed.set(expectedPolicy);
+
await waitForNextUpdate();
- expect(result.current).toStrictEqual({
- data: { partnerId: "taco-bell" },
- isLoading: false,
- });
+ expect(result.current).toStrictEqual(valueToAsyncState(expectedPolicy));
});
});
From dca94de6ee0f402e53de0538c2510811adb217c6 Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 10 Oct 2024 11:24:27 -0700
Subject: [PATCH 21/25] resolve test interference
---
src/store/enterprise/useManagedStorageState.test.ts | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/store/enterprise/useManagedStorageState.test.ts b/src/store/enterprise/useManagedStorageState.test.ts
index 6f4c23d143..1292cbba8a 100644
--- a/src/store/enterprise/useManagedStorageState.test.ts
+++ b/src/store/enterprise/useManagedStorageState.test.ts
@@ -15,7 +15,8 @@
* along with this program. If not, see .
*/
-import { INTERNAL_reset } from "@/store/enterprise/managedStorage";
+import { INTERNAL_reset as resetManagedStorage } from "@/store/enterprise/managedStorage";
+import { INTERNAL_reset as resetAsyncExternalStore } from "@/hooks/useAsyncExternalStore";
import { renderHook } from "@testing-library/react-hooks";
import useManagedStorageState from "@/store/enterprise/useManagedStorageState";
import {
@@ -24,7 +25,8 @@ import {
} from "@/utils/asyncStateUtils";
beforeEach(async () => {
- await INTERNAL_reset();
+ await resetManagedStorage();
+ resetAsyncExternalStore();
await browser.storage.managed.clear();
});
From f5671b61376893c1d3afa9884bdaf3aec4517199 Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 10 Oct 2024 12:13:03 -0700
Subject: [PATCH 22/25] fix remaining tests:
---
.../pages/BrowserBanner.test.tsx | 2 ++
src/hooks/useTheme.test.ts | 20 ++++++++++---------
2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/src/extensionConsole/pages/BrowserBanner.test.tsx b/src/extensionConsole/pages/BrowserBanner.test.tsx
index 4525e9ce47..6a342c59ce 100644
--- a/src/extensionConsole/pages/BrowserBanner.test.tsx
+++ b/src/extensionConsole/pages/BrowserBanner.test.tsx
@@ -21,9 +21,11 @@ import BrowserBanner from "@/extensionConsole/pages/BrowserBanner";
import { waitForEffect } from "@/testUtils/testHelpers";
import { screen } from "@testing-library/react";
import { INTERNAL_reset } from "@/store/enterprise/managedStorage";
+import { INTERNAL_reset as resetAsyncExternalStore } from "@/hooks/useAsyncExternalStore";
beforeEach(async () => {
await INTERNAL_reset();
+ resetAsyncExternalStore();
await browser.storage.managed.clear();
});
diff --git a/src/hooks/useTheme.test.ts b/src/hooks/useTheme.test.ts
index 9337407fa4..0d8b4659ef 100644
--- a/src/hooks/useTheme.test.ts
+++ b/src/hooks/useTheme.test.ts
@@ -20,10 +20,8 @@ import { renderHook } from "@/pageEditor/testHelpers";
import { initialTheme } from "@/themes/themeStore";
import { type ThemeAssets, themeStorage } from "@/themes/themeUtils";
import { activateTheme } from "@/background/messenger/api";
-import {
- INTERNAL_reset,
- readManagedStorage,
-} from "@/store/enterprise/managedStorage";
+import { readManagedStorage } from "@/store/enterprise/managedStorage";
+import { INTERNAL_reset as resetAsyncExternalStore } from "@/hooks/useAsyncExternalStore";
jest.mock("@/themes/themeUtils", () => ({
...jest.requireActual("@/themes/themeUtils"),
@@ -58,8 +56,7 @@ const customTheme: ThemeAssets = {
describe("useTheme", () => {
beforeEach(async () => {
- await INTERNAL_reset();
- await browser.storage.managed.clear();
+ resetAsyncExternalStore();
jest.mocked(themeStorage.get).mockResolvedValue({
...initialTheme,
@@ -96,13 +93,16 @@ describe("useTheme", () => {
it("calls activateTheme after loading is done and it hasn't been called recently", async () => {
jest.useFakeTimers();
- renderHook(() => useTheme());
+ let result = renderHook(() => useTheme());
+ await result.waitForNextUpdate();
expect(activateTheme).not.toHaveBeenCalled();
jest.advanceTimersByTime(125_000);
+ resetAsyncExternalStore();
- renderHook(() => useTheme());
+ result = renderHook(() => useTheme());
+ await result.waitForNextUpdate();
expect(activateTheme).toHaveBeenCalledOnce();
});
@@ -157,7 +157,9 @@ describe("useTheme", () => {
.mocked(readManagedStorage)
.mockRejectedValue(new Error("Managed storage error"));
- const { result } = renderHook(() => useTheme());
+ const { result, waitForNextUpdate } = renderHook(() => useTheme());
+
+ await waitForNextUpdate();
expect(result.current.activeTheme.showSidebarLogo).toBe(showSidebarLogo);
},
From 5fa559ca3da2a09118ca9d0be2407d6d263fb449 Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 10 Oct 2024 12:16:56 -0700
Subject: [PATCH 23/25] refactor useRequiredPartnerAuth tests
---
src/auth/useRequiredPartnerAuth.test.tsx | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/src/auth/useRequiredPartnerAuth.test.tsx b/src/auth/useRequiredPartnerAuth.test.tsx
index e94b390d13..ddb700a79f 100644
--- a/src/auth/useRequiredPartnerAuth.test.tsx
+++ b/src/auth/useRequiredPartnerAuth.test.tsx
@@ -39,8 +39,6 @@ import usePartnerAuthData from "@/auth/usePartnerAuthData";
import { Milestones } from "@/data/model/UserMilestone";
import { getDeploymentKey } from "@/auth/deploymentKey";
import { getExtensionToken } from "@/auth/authStorage";
-import type { AsyncState } from "@/types/sliceTypes";
-import { type ManagedStorageState } from "@/store/enterprise/managedStorageTypes";
jest.mock("@/store/enterprise/useManagedStorageState");
jest.mock("@/auth/usePartnerAuthData");
@@ -56,10 +54,7 @@ beforeEach(() => {
jest.clearAllMocks();
// eslint-disable-next-line no-restricted-syntax -- we really do want to resolve to undefined
getExtensionTokenMock.mockResolvedValue(undefined);
- useManagedStorageStateMock.mockReturnValue({
- data: {},
- isLoading: false,
- } as AsyncState);
+ useManagedStorageStateMock.mockReturnValue(valueToAsyncState({}));
usePartnerAuthDataMock.mockReturnValue(valueToAsyncState(undefined));
});
@@ -165,10 +160,9 @@ describe("useRequiredPartnerAuth", () => {
});
test("requires integration for managed storage partner", async () => {
- useManagedStorageStateMock.mockReturnValue({
- data: { partnerId: "automation-anywhere" },
- isLoading: false,
- } as AsyncState);
+ useManagedStorageStateMock.mockReturnValue(
+ valueToAsyncState({ partnerId: "automation-anywhere" }),
+ );
mockAnonymousMeApiResponse();
From 726116fd97ea29cb0d81dac4dd009eff4b86987d Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 10 Oct 2024 12:22:29 -0700
Subject: [PATCH 24/25] refactor test in useTheme
---
src/hooks/useTheme.test.ts | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/hooks/useTheme.test.ts b/src/hooks/useTheme.test.ts
index 0d8b4659ef..4f146053f8 100644
--- a/src/hooks/useTheme.test.ts
+++ b/src/hooks/useTheme.test.ts
@@ -93,16 +93,16 @@ describe("useTheme", () => {
it("calls activateTheme after loading is done and it hasn't been called recently", async () => {
jest.useFakeTimers();
- let result = renderHook(() => useTheme());
- await result.waitForNextUpdate();
+ const { rerender, waitForNextUpdate } = renderHook(() => useTheme());
+ await waitForNextUpdate();
expect(activateTheme).not.toHaveBeenCalled();
jest.advanceTimersByTime(125_000);
resetAsyncExternalStore();
- result = renderHook(() => useTheme());
- await result.waitForNextUpdate();
+ rerender();
+ await waitForNextUpdate();
expect(activateTheme).toHaveBeenCalledOnce();
});
From c9ab7713182c085f5c65034171907e8bdaad9556 Mon Sep 17 00:00:00 2001
From: Misha Holtz <36575242+mnholtz@users.noreply.github.com>
Date: Thu, 10 Oct 2024 12:28:23 -0700
Subject: [PATCH 25/25] remove unused getSnapshot
---
src/store/enterprise/managedStorage.ts | 11 -----------
1 file changed, 11 deletions(-)
diff --git a/src/store/enterprise/managedStorage.ts b/src/store/enterprise/managedStorage.ts
index ae929a8e03..0b49c7a15f 100644
--- a/src/store/enterprise/managedStorage.ts
+++ b/src/store/enterprise/managedStorage.ts
@@ -318,17 +318,6 @@ export function isInitialized(): boolean {
return managedStorageSnapshot != null;
}
-/**
- * Get a _synchronous_ snapshot of the managed storage state.
- * @see useManagedStorageState
- * @see readManagedStorage
- */
-export function getSnapshot(): Nullishable {
- expectContext("extension");
-
- return managedStorageSnapshot;
-}
-
/**
* Helper method for resetting the module for testing.
*/