Skip to content

Commit 41d96c3

Browse files
committed
chore: WIP-storage
1 parent 05fd6f1 commit 41d96c3

12 files changed

+730
-890
lines changed

Diff for: eslint.config.mjs

-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import js from '@eslint/js';
55
import packageJson from 'eslint-plugin-package-json/configs/recommended';
66
import typescriptEslintEslintPlugin from '@typescript-eslint/eslint-plugin';
77
import nxEslintPlugin from '@nx/eslint-plugin';
8-
import eslintPluginImport from 'eslint-plugin-import';
98
import typescriptEslintParser from '@typescript-eslint/parser';
109

1110
const compat = new FlatCompat({
@@ -22,7 +21,6 @@ export default [
2221
plugins: {
2322
'@typescript-eslint': typescriptEslintEslintPlugin,
2423
'@nx': nxEslintPlugin,
25-
import: eslintPluginImport,
2624
},
2725
},
2826
{
@@ -36,7 +34,6 @@ export default [
3634
},
3735
{
3836
rules: {
39-
'import/extensions': [2, 'ignorePackages'],
4037
'@typescript-eslint/indent': ['error', 2],
4138
'@typescript-eslint/no-use-before-define': 'warn',
4239
'max-len': [
@@ -57,7 +54,6 @@ export default [
5754
{
5855
files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
5956
rules: {
60-
'import/extensions': [2, 'ignorePackages'],
6157
'@nx/enforce-module-boundaries': [
6258
'warn',
6359
{

Diff for: package.json

-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@
8989
"cz-git": "^1.6.1",
9090
"eslint": "^9.8.0",
9191
"eslint-config-prettier": "10.1.1",
92-
"eslint-plugin-import": "2.31.0",
9392
"eslint-plugin-package-json": "0.26.3",
9493
"eslint-plugin-playwright": "^2.0.0",
9594
"eslint-plugin-prettier": "^5.2.3",

Diff for: packages/effects/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
"dependencies": {
2626
"@forgerock/sdk-utilities": "workspace:*",
2727
"@forgerock/shared-types": "workspace:*",
28-
"@reduxjs/toolkit": "catalog:",
2928
"tslib": "^2.5.0"
3029
},
3130
"devDependencies": {

Diff for: packages/effects/src/lib/local-storage.test.ts

+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/**
2+
*
3+
* Copyright (c) 2025 Ping Identity Corporation. All rights reserved.
4+
*
5+
* This software may be modified and distributed under the terms
6+
* of the MIT license. See the LICENSE file for details.
7+
*
8+
*/
9+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
10+
import {
11+
getLocalStorageTokens,
12+
setLocalStorageTokens,
13+
removeTokensFromLocalStorage,
14+
tokenFactory,
15+
} from './local-storage.js';
16+
import type { ConfigOptions, Tokens } from '@forgerock/shared-types';
17+
18+
// Create a mock global object for tests
19+
const createMockWindow = () => {
20+
const localStorageMock = {
21+
getItem: vi.fn((key: string) => localStorageMock.store[key] || null),
22+
setItem: vi.fn((key: string, value: string) => {
23+
localStorageMock.store[key] = value.toString();
24+
}),
25+
removeItem: vi.fn((key: string) => {
26+
delete localStorageMock.store[key];
27+
}),
28+
clear: vi.fn(() => {
29+
localStorageMock.store = {};
30+
}),
31+
store: {} as Record<string, string>,
32+
};
33+
return localStorageMock;
34+
};
35+
36+
describe('Token Storage Functions', () => {
37+
let localStorageMock: ReturnType<typeof createMockWindow>;
38+
39+
// Mock config
40+
const mockConfig: ConfigOptions = {
41+
clientId: 'test-client',
42+
prefix: 'test-prefix',
43+
};
44+
45+
// Sample tokens
46+
const sampleTokens: Tokens = {
47+
accessToken: 'access-token-123',
48+
idToken: 'id-token-456',
49+
refreshToken: 'refresh-token-789',
50+
tokenExpiry: 3600,
51+
};
52+
53+
beforeEach(() => {
54+
// Setup mock localStorage
55+
localStorageMock = createMockWindow();
56+
57+
// Mock the localStorage globally
58+
vi.stubGlobal('localStorage', localStorageMock);
59+
60+
// Clear mock calls before each test
61+
vi.clearAllMocks();
62+
});
63+
64+
afterEach(() => {
65+
// Restore the original implementations after tests
66+
vi.unstubAllGlobals();
67+
});
68+
69+
describe('getLocalStorageTokens', () => {
70+
it('should return undefined when no tokens exist', () => {
71+
const tokens = getLocalStorageTokens(mockConfig);
72+
73+
expect(localStorageMock.getItem).toHaveBeenCalledWith('test-prefix-test-client');
74+
expect(tokens).toBeUndefined();
75+
});
76+
77+
it('should parse and return tokens when they exist', () => {
78+
localStorageMock.getItem.mockReturnValueOnce(JSON.stringify(sampleTokens));
79+
80+
const tokens = getLocalStorageTokens(mockConfig);
81+
82+
expect(localStorageMock.getItem).toHaveBeenCalledWith('test-prefix-test-client');
83+
expect(tokens).toEqual(sampleTokens);
84+
});
85+
86+
it('should return error object when tokens exist but cannot be parsed', () => {
87+
localStorageMock.getItem.mockReturnValueOnce('invalid-json');
88+
89+
const result = getLocalStorageTokens(mockConfig);
90+
91+
expect(localStorageMock.getItem).toHaveBeenCalledWith('test-prefix-test-client');
92+
expect(result).toEqual({ error: 'Could not parse token from localStorage' });
93+
});
94+
});
95+
96+
describe('setTokens', () => {
97+
it('should stringify and store tokens in localStorage', () => {
98+
setLocalStorageTokens(mockConfig, sampleTokens);
99+
100+
expect(localStorageMock.setItem).toHaveBeenCalledWith(
101+
'test-prefix-test-client',
102+
JSON.stringify(sampleTokens),
103+
);
104+
});
105+
});
106+
107+
describe('removeTokens', () => {
108+
it('should remove tokens from localStorage', () => {
109+
removeTokensFromLocalStorage(mockConfig);
110+
111+
expect(localStorageMock.removeItem).toHaveBeenCalledWith('test-prefix-test-client');
112+
});
113+
});
114+
115+
describe('tokenFactory', () => {
116+
it('should return an object with get, set, and remove methods', () => {
117+
const tokenManager = tokenFactory(mockConfig);
118+
119+
expect(tokenManager).toHaveProperty('get');
120+
expect(tokenManager).toHaveProperty('set');
121+
expect(tokenManager).toHaveProperty('remove');
122+
expect(typeof tokenManager.get).toBe('function');
123+
expect(typeof tokenManager.set).toBe('function');
124+
expect(typeof tokenManager.remove).toBe('function');
125+
});
126+
127+
it('get method should retrieve tokens', () => {
128+
localStorageMock.getItem.mockReturnValueOnce(JSON.stringify(sampleTokens));
129+
130+
const tokenManager = tokenFactory(mockConfig);
131+
const tokens = tokenManager.get();
132+
133+
expect(localStorageMock.getItem).toHaveBeenCalledWith('test-prefix-test-client');
134+
expect(tokens).toEqual(sampleTokens);
135+
});
136+
137+
it('set method should store tokens', () => {
138+
const tokenManager = tokenFactory(mockConfig);
139+
tokenManager.set(sampleTokens);
140+
141+
expect(localStorageMock.setItem).toHaveBeenCalledWith(
142+
'test-prefix-test-client',
143+
JSON.stringify(sampleTokens),
144+
);
145+
});
146+
147+
it('remove method should remove tokens', () => {
148+
const tokenManager = tokenFactory(mockConfig);
149+
tokenManager.remove();
150+
151+
expect(localStorageMock.removeItem).toHaveBeenCalledWith('test-prefix-test-client');
152+
});
153+
});
154+
});

Diff for: packages/effects/src/lib/local-storage.ts

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
*
3+
* Copyright (c) 2025 Ping Identity Corporation. All rights reserved.
4+
*
5+
* This software may be modified and distributed under the terms
6+
* of the MIT license. See the LICENSE file for details.
7+
*
8+
*/
9+
import type { ConfigOptions, Tokens } from '@forgerock/shared-types';
10+
11+
export function getLocalStorageTokens(Config: ConfigOptions) {
12+
const tokenString = localStorage.getItem(`${Config.prefix}-${Config.clientId}`);
13+
if (!tokenString) {
14+
return;
15+
}
16+
try {
17+
const tokens = JSON.parse(tokenString);
18+
return tokens;
19+
} catch (err) {
20+
return {
21+
error: 'Could not parse token from localStorage',
22+
};
23+
}
24+
}
25+
26+
export function setLocalStorageTokens(Config: ConfigOptions, tokens: Tokens) {
27+
const tokenString = JSON.stringify(tokens);
28+
localStorage.setItem(`${Config.prefix}-${Config.clientId}`, tokenString);
29+
}
30+
31+
export function removeTokensFromLocalStorage(Config: ConfigOptions) {
32+
localStorage.removeItem(`${Config.prefix}-${Config.clientId}`);
33+
}
34+
35+
export function tokenFactory(config: ConfigOptions) {
36+
return {
37+
get: () => getLocalStorageTokens(config),
38+
set: (tokens: Tokens) => setLocalStorageTokens(config, tokens),
39+
remove: () => removeTokensFromLocalStorage(config),
40+
};
41+
}

0 commit comments

Comments
 (0)