@alwatr/local-storage 5.5.10 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -0
- package/README.md +227 -28
- package/dist/local-storage.provider.d.ts +75 -0
- package/dist/local-storage.provider.d.ts.map +1 -0
- package/dist/main.cjs +91 -87
- package/dist/main.cjs.map +3 -3
- package/dist/main.d.ts +25 -66
- package/dist/main.d.ts.map +1 -1
- package/dist/main.mjs +88 -87
- package/dist/main.mjs.map +3 -3
- package/dist/type.d.ts +18 -0
- package/dist/type.d.ts.map +1 -0
- package/package.json +5 -4
- package/src/main.test.js +234 -0
package/src/main.test.js
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import {describe, beforeEach, afterEach, it, expect, jest} from '@jest/globals';
|
|
2
|
+
import {createLocalStorageProvider, LocalStorageProvider} from '@alwatr/local-storage';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @jest-environment jsdom
|
|
6
|
+
*/
|
|
7
|
+
describe('LocalStorageProvider', () => {
|
|
8
|
+
/**
|
|
9
|
+
* @type {jest.Mocked<Pick<Storage, "getItem" | "setItem" | "removeItem">>}
|
|
10
|
+
*/
|
|
11
|
+
let mockLocalStorage;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
mockLocalStorage = {
|
|
15
|
+
getItem: jest.fn(),
|
|
16
|
+
setItem: jest.fn(),
|
|
17
|
+
removeItem: jest.fn(),
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(globalThis, 'localStorage', {
|
|
20
|
+
value: mockLocalStorage,
|
|
21
|
+
writable: true,
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
jest.clearAllMocks();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('static getKey', () => {
|
|
30
|
+
it('should generate the correct versioned key', () => {
|
|
31
|
+
const key = LocalStorageProvider.getKey({name: 'test', version: 1});
|
|
32
|
+
expect(key).toBe('test.v1');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should handle different names and versions', () => {
|
|
36
|
+
const key1 = LocalStorageProvider.getKey({name: 'user-settings', version: 2});
|
|
37
|
+
expect(key1).toBe('user-settings.v2');
|
|
38
|
+
const key2 = LocalStorageProvider.getKey({name: 'form-data', version: 5});
|
|
39
|
+
expect(key2).toBe('form-data.v5');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('static has', () => {
|
|
44
|
+
it('should return true if item exists', () => {
|
|
45
|
+
mockLocalStorage.getItem.mockReturnValue('{"value": "test"}');
|
|
46
|
+
const exists = LocalStorageProvider.has({name: 'test', version: 1});
|
|
47
|
+
expect(exists).toBe(true);
|
|
48
|
+
expect(mockLocalStorage.getItem).toHaveBeenCalledWith('test.v1');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should return false if item does not exist', () => {
|
|
52
|
+
mockLocalStorage.getItem.mockReturnValue(null);
|
|
53
|
+
const exists = LocalStorageProvider.has({name: 'test', version: 1});
|
|
54
|
+
expect(exists).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should return false for null value', () => {
|
|
58
|
+
mockLocalStorage.getItem.mockReturnValue(null);
|
|
59
|
+
const exists = LocalStorageProvider.has({name: 'test', version: 1});
|
|
60
|
+
expect(exists).toBe(false);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('constructor and migration', () => {
|
|
65
|
+
it('should initialize with config and migrate old versions', () => {
|
|
66
|
+
const provider = createLocalStorageProvider({
|
|
67
|
+
name: 'test',
|
|
68
|
+
version: 3,
|
|
69
|
+
defaultValue: {key: 'value'},
|
|
70
|
+
});
|
|
71
|
+
expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('test.v1');
|
|
72
|
+
expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('test.v2');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should not migrate if version is 1', () => {
|
|
76
|
+
const provider = createLocalStorageProvider({
|
|
77
|
+
name: 'test',
|
|
78
|
+
version: 1,
|
|
79
|
+
defaultValue: {key: 'value'},
|
|
80
|
+
});
|
|
81
|
+
expect(mockLocalStorage.removeItem).not.toHaveBeenCalled();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should migrate multiple old versions for higher version', () => {
|
|
85
|
+
const provider = createLocalStorageProvider({
|
|
86
|
+
name: 'test',
|
|
87
|
+
version: 5,
|
|
88
|
+
defaultValue: {key: 'value'},
|
|
89
|
+
});
|
|
90
|
+
expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('test.v1');
|
|
91
|
+
expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('test.v2');
|
|
92
|
+
expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('test.v3');
|
|
93
|
+
expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('test.v4');
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('read', () => {
|
|
98
|
+
it('should return default value if no item exists', () => {
|
|
99
|
+
mockLocalStorage.getItem.mockReturnValue(null);
|
|
100
|
+
const provider = createLocalStorageProvider({
|
|
101
|
+
name: 'test',
|
|
102
|
+
version: 1,
|
|
103
|
+
defaultValue: {key: 'default'},
|
|
104
|
+
});
|
|
105
|
+
const result = provider.read();
|
|
106
|
+
expect(result).toEqual({key: 'default'});
|
|
107
|
+
expect(mockLocalStorage.setItem).toHaveBeenCalledWith('test.v1', '{"key":"default"}');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should return parsed value if item exists', () => {
|
|
111
|
+
mockLocalStorage.getItem.mockReturnValue('{"key":"stored"}');
|
|
112
|
+
const provider = createLocalStorageProvider({
|
|
113
|
+
name: 'test',
|
|
114
|
+
version: 1,
|
|
115
|
+
defaultValue: {key: 'default'},
|
|
116
|
+
});
|
|
117
|
+
const result = provider.read();
|
|
118
|
+
expect(result).toEqual({key: 'stored'});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should return default value on invalid JSON', () => {
|
|
122
|
+
mockLocalStorage.getItem.mockReturnValue('invalid json');
|
|
123
|
+
const provider = createLocalStorageProvider({
|
|
124
|
+
name: 'test',
|
|
125
|
+
version: 1,
|
|
126
|
+
defaultValue: {key: 'default'},
|
|
127
|
+
});
|
|
128
|
+
const result = provider.read();
|
|
129
|
+
expect(result).toEqual({key: 'default'});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should handle complex default values', () => {
|
|
133
|
+
mockLocalStorage.getItem.mockReturnValue(null);
|
|
134
|
+
const provider = createLocalStorageProvider({
|
|
135
|
+
name: 'test',
|
|
136
|
+
version: 1,
|
|
137
|
+
defaultValue: {theme: 'dark', lastLogin: Date.now(), settings: [1, 2, 3]},
|
|
138
|
+
});
|
|
139
|
+
const result = provider.read();
|
|
140
|
+
expect(result.theme).toBe('dark');
|
|
141
|
+
expect(Array.isArray(result.settings)).toBe(true);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe('write', () => {
|
|
146
|
+
it('should serialize and store the value', () => {
|
|
147
|
+
const provider = createLocalStorageProvider({
|
|
148
|
+
name: 'test',
|
|
149
|
+
version: 1,
|
|
150
|
+
defaultValue: {key: 'default'},
|
|
151
|
+
});
|
|
152
|
+
provider.write({key: 'newValue'});
|
|
153
|
+
expect(mockLocalStorage.setItem).toHaveBeenCalledWith('test.v1', '{"key":"newValue"}');
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should handle write errors gracefully', () => {
|
|
157
|
+
mockLocalStorage.setItem.mockImplementation(() => {
|
|
158
|
+
throw new Error('Storage full');
|
|
159
|
+
});
|
|
160
|
+
const provider = createLocalStorageProvider({
|
|
161
|
+
name: 'test',
|
|
162
|
+
version: 1,
|
|
163
|
+
defaultValue: {key: 'default'},
|
|
164
|
+
});
|
|
165
|
+
expect(() => provider.write({key: 'value'})).not.toThrow();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('should write different data types', () => {
|
|
169
|
+
const provider = createLocalStorageProvider({
|
|
170
|
+
name: 'test',
|
|
171
|
+
version: 1,
|
|
172
|
+
/**
|
|
173
|
+
* @type {string|number|Array<number>}
|
|
174
|
+
*/
|
|
175
|
+
defaultValue: '',
|
|
176
|
+
});
|
|
177
|
+
provider.write('string value');
|
|
178
|
+
expect(mockLocalStorage.setItem).toHaveBeenCalledWith('test.v1', '"string value"');
|
|
179
|
+
provider.write(42);
|
|
180
|
+
expect(mockLocalStorage.setItem).toHaveBeenCalledWith('test.v1', '42');
|
|
181
|
+
provider.write([1, 2, 3]);
|
|
182
|
+
expect(mockLocalStorage.setItem).toHaveBeenCalledWith('test.v1', '[1,2,3]');
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe('remove', () => {
|
|
187
|
+
it('should remove the item from storage', () => {
|
|
188
|
+
const provider = createLocalStorageProvider({
|
|
189
|
+
name: 'test',
|
|
190
|
+
version: 1,
|
|
191
|
+
defaultValue: {key: 'default'},
|
|
192
|
+
});
|
|
193
|
+
provider.remove();
|
|
194
|
+
expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('test.v1');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('should not throw if item does not exist', () => {
|
|
198
|
+
const provider = createLocalStorageProvider({
|
|
199
|
+
name: 'test',
|
|
200
|
+
version: 1,
|
|
201
|
+
defaultValue: {key: 'default'},
|
|
202
|
+
});
|
|
203
|
+
expect(() => provider.remove()).not.toThrow();
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
describe('createLocalStorageProvider factory', () => {
|
|
208
|
+
it('should create a provider instance', () => {
|
|
209
|
+
const provider = createLocalStorageProvider({
|
|
210
|
+
name: 'factory-test',
|
|
211
|
+
version: 1,
|
|
212
|
+
defaultValue: {created: true},
|
|
213
|
+
});
|
|
214
|
+
expect(provider).toBeInstanceOf(LocalStorageProvider);
|
|
215
|
+
const result = provider.read();
|
|
216
|
+
expect(result.created).toBe(true);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('should handle different configurations', () => {
|
|
220
|
+
const provider1 = createLocalStorageProvider({
|
|
221
|
+
name: 'config1',
|
|
222
|
+
version: 2,
|
|
223
|
+
defaultValue: 'default1',
|
|
224
|
+
});
|
|
225
|
+
const provider2 = createLocalStorageProvider({
|
|
226
|
+
name: 'config2',
|
|
227
|
+
version: 1,
|
|
228
|
+
defaultValue: {key: 'default2'},
|
|
229
|
+
});
|
|
230
|
+
expect(provider1.read()).toBe('default1');
|
|
231
|
+
expect(provider2.read().key).toBe('default2');
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
});
|