Skip to content
Merged
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
10 changes: 7 additions & 3 deletions lib/sessionManager/stores/memory.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it, expect, beforeEach } from "vitest";
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { MemoryStorage } from "./memory";
import { StorageKeys } from "../types";

Expand Down Expand Up @@ -146,6 +146,10 @@ describe("MemoryStorage subscription/listening mechanism", () => {
sessionManager = new MemoryStorage();
});

afterEach(() => {
vi.useRealTimers();
});

it("should call listener when item is set", async () => {
let listenerCalled = false;
const listener = () => {
Expand Down Expand Up @@ -259,13 +263,13 @@ describe("MemoryStorage subscription/listening mechanism", () => {
asyncCalled = true;
};

vi.useFakeTimers();
sessionManager.subscribe(syncListener);
sessionManager.subscribe(asyncListener);

await sessionManager.setSessionItem(StorageKeys.idToken, "mixedTest");

// Wait for setTimeout to fire and async listener to complete
await new Promise((resolve) => setTimeout(resolve, 10));
await vi.runAllTimersAsync();

Comment thread
dtoxvanilla1991 marked this conversation as resolved.
expect(syncCalled).toBe(true);
expect(asyncCalled).toBe(true);
Expand Down
4 changes: 2 additions & 2 deletions lib/utils/generateAuthUrl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ describe("generateAuthUrl", () => {

await expect(
generateAuthUrl(domain, IssuerRouteTypes.login, options),
).rejects.toThrow(/Error handing reauth state:/);
).rejects.toThrow(/Error handling reauth state:/);
});

it("invalid reauthState", async () => {
Expand All @@ -443,7 +443,7 @@ describe("generateAuthUrl", () => {
expect(() =>
generateAuthUrl(domain, IssuerRouteTypes.login, options),
).rejects.toThrow(
/Error handing reauth state: Expected property name or '}' in JSON/,
/Error handling reauth state: Expected property name or '}' in JSON/,
);
});

Expand Down
6 changes: 4 additions & 2 deletions lib/utils/generateAuthUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ export const generateAuthUrl = async (
} catch (ex: unknown) {
const errorDescription =
ex instanceof Error ? ex.message : "Unknown error";
throw new Error(`Error handing reauth state: ${errorDescription}`);
throw new Error(`Error handling reauth state: ${errorDescription}`, {
cause: ex,
});
}
}

Expand Down Expand Up @@ -161,7 +163,7 @@ export async function generatePKCEPair(): Promise<{
}> {
const codeVerifier = generateRandomString(52);
const data = new TextEncoder().encode(codeVerifier);
let codeChallenge = "";
let codeChallenge: string;
if (!crypto) {
codeChallenge = base64UrlEncode(codeVerifier);
} else {
Expand Down
5 changes: 4 additions & 1 deletion lib/utils/generatePortalUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ export const generatePortalUrl = async ({
};
} catch (error) {
console.error(error);
throw new Error(`Invalid URL format received from API: ${fetchResult.url}`);
throw new Error(
`Invalid URL format received from API: ${fetchResult.url}`,
{ cause: error },
);
}
};
15 changes: 15 additions & 0 deletions lib/utils/navigateToKinde.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,21 @@ describe("navigateToKinde", () => {
expect(searchParams.get("error")).toBe("access_denied");
expect(searchParams.get("error_description")).toBe("User denied access");
});

it("should throw 'Popup authentication failed' when the message listener throws", async () => {
vi.spyOn(window, "addEventListener").mockImplementationOnce(() => {
throw new Error("Listener registration failed");
});

const err = await createPopup({
url: "https://auth.example.com",
}).catch((e) => e);

expect(err).toBeInstanceOf(Error);
expect(err.message).toContain("Popup authentication failed");
expect(err.cause).toBeInstanceOf(Error);
expect((err.cause as Error).message).toBe("Listener registration failed");
});
});

describe("waitForPopupClose", () => {
Expand Down
2 changes: 1 addition & 1 deletion lib/utils/navigateToKinde.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export const createPopup = async ({
try {
await waitForMessage();
} catch (error) {
throw new Error("Popup authentication failed: " + error);
throw new Error("Popup authentication failed", { cause: error });
}
return popup;
};
Expand Down
19 changes: 19 additions & 0 deletions lib/utils/token/accountApi/callAccountApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,23 @@ describe("callAccountApi", () => {
}),
);
});

it("throws error with cause if fetch throws a network error", async () => {
const token = createMockAccessToken();
await store.setSessionItem(StorageKeys.accessToken, token);

const networkError = new Error("Network failure");
fetchMock.mockRejectOnce(networkError);

const caughtError = await callAccountApi("account_api/test").catch(
(e) => e,
);
expect(caughtError).toBeInstanceOf(Error);
const actualError = caughtError as Error;

expect(actualError.message).toContain(
"Failed to fetch from https://kinde.com/account_api/test",
);
expect(actualError.cause).toBe(networkError);
});
});
7 changes: 4 additions & 3 deletions lib/utils/token/accountApi/callAccountApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ export async function callAccountApi<T>(route: AccountApiRoute): Promise<T> {
},
});
} catch (error) {
throw new Error(`Failed to fetch from ${domain.value}/${route}: ${error}`);
throw new Error(`Failed to fetch from ${domain.value}/${route}`, {
cause: error,
});
}

if (!response.ok) {
Expand All @@ -47,9 +49,8 @@ export const callAccountApiPaginated = async <T extends BaseAccountResponse>({
}: {
url: AccountApiRoute;
}): Promise<T["data"]> => {
let items: T["data"] = [];
let returnValue = await callAccountApi<T>(url);
items = returnValue.data;
let items: T["data"] = returnValue.data;
if (returnValue.metadata?.has_more) {
let nextPageStartingAfter = returnValue.metadata.next_page_starting_after;
while (returnValue.metadata.has_more) {
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,18 @@
},
"sideEffects": false,
"devDependencies": {
"@eslint/js": "^9.9.1",
"@eslint/js": "^10.0.0",
"@types/chrome": "^0.1.0",
"@types/node": "^24.0.0",
"@vitejs/plugin-react": "^6.0.0",
"expo-secure-store": "55.0.13",
"@vitest/coverage-v8": "^4.0.3",
"eslint": "^9.9.1",
"eslint": "^10.0.0",
"globals": "^17.0.0",
"jsdom": "^29.0.0",
"prettier": "^3.3.3",
"typescript": "^6.0.0",
"typescript-eslint": "^8.3.0",
"typescript-eslint": "^8.59.0",
"vite": "^8.0.0",
"vite-plugin-dts": "^4.0.3",
"vitest": "^4.0.3",
Expand Down
Loading
Loading