Skip to content

Commit 5ade776

Browse files
committed
make setItem closer to real Storage implementation
1 parent 8a74abe commit 5ade776

3 files changed

Lines changed: 146 additions & 3 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"build:rolldown": "rolldown -c rolldown.config.js",
2121
"build:types": "tsc --emitDeclarationOnly --outDir dist",
2222
"clean": "rm -rf dist",
23-
"test": "vitest",
23+
"test": "vitest run",
2424
"type-check": "tsc --noEmit",
2525
"type-check:watch": "tsc --noEmit --watch",
2626
"prepublishOnly": "npm run build",

src/index.mjs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,20 @@ export function wrapStorage(originalStorage, { expiresInSeconds } = {}) {
6969

7070
/**
7171
* @param {string} key
72-
* @param {string} value
72+
* @param {any} value
7373
*/
7474
setItem(key, value) {
75-
originalStorage.setItem(key, JSON.stringify(createWrappedItem(value)));
75+
if (arguments.length < 2) {
76+
throw new TypeError(
77+
`Failed to execute 'setItem' on 'Storage': 2 arguments required, but only ${arguments.length} present.`
78+
);
79+
}
80+
81+
const stringValue = String(value);
82+
originalStorage.setItem(
83+
key,
84+
JSON.stringify(createWrappedItem(stringValue))
85+
);
7686
},
7787

7888
/**

src/storage.test.mjs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,139 @@ describe("Ephemeral Storage", () => {
153153
const parsed = JSON.parse(rawValue ?? "");
154154
expect(parsed.ed).toBe(CURRENT_TIME + 999999999 * 1000);
155155
});
156+
157+
it("handles non-string values the same as native localStorage", () => {
158+
const storage = wrapStorage(window.localStorage);
159+
const testKey = "test-non-string";
160+
161+
// Test null
162+
const nullValue = null;
163+
localStorage.setItem(testKey, nullValue);
164+
const nativeNullResult = localStorage.getItem(testKey);
165+
localStorage.removeItem(testKey);
166+
167+
storage.setItem(testKey, nullValue);
168+
const wrappedNullResult = storage.getItem(testKey);
169+
storage.removeItem(testKey);
170+
171+
expect(wrappedNullResult).toBe(nativeNullResult);
172+
expect(wrappedNullResult).toBe("null");
173+
174+
// Test undefined
175+
const undefinedValue = undefined;
176+
localStorage.setItem(testKey, undefinedValue);
177+
const nativeUndefinedResult = localStorage.getItem(testKey);
178+
localStorage.removeItem(testKey);
179+
180+
storage.setItem(testKey, undefinedValue);
181+
const wrappedUndefinedResult = storage.getItem(testKey);
182+
storage.removeItem(testKey);
183+
184+
expect(wrappedUndefinedResult).toBe(nativeUndefinedResult);
185+
expect(wrappedUndefinedResult).toBe("undefined");
186+
187+
// Test number
188+
const numberValue = 42;
189+
localStorage.setItem(testKey, numberValue);
190+
const nativeNumberResult = localStorage.getItem(testKey);
191+
localStorage.removeItem(testKey);
192+
193+
storage.setItem(testKey, numberValue);
194+
const wrappedNumberResult = storage.getItem(testKey);
195+
storage.removeItem(testKey);
196+
197+
expect(wrappedNumberResult).toBe(nativeNumberResult);
198+
expect(wrappedNumberResult).toBe("42");
199+
200+
// Test boolean
201+
const booleanValue = true;
202+
localStorage.setItem(testKey, booleanValue);
203+
const nativeBooleanResult = localStorage.getItem(testKey);
204+
localStorage.removeItem(testKey);
205+
206+
storage.setItem(testKey, booleanValue);
207+
const wrappedBooleanResult = storage.getItem(testKey);
208+
storage.removeItem(testKey);
209+
210+
expect(wrappedBooleanResult).toBe(nativeBooleanResult);
211+
expect(wrappedBooleanResult).toBe("true");
212+
213+
// Test object (should become "[object Object]")
214+
const objectValue = { name: "test" };
215+
localStorage.setItem(testKey, objectValue);
216+
const nativeObjectResult = localStorage.getItem(testKey);
217+
localStorage.removeItem(testKey);
218+
219+
storage.setItem(testKey, objectValue);
220+
const wrappedObjectResult = storage.getItem(testKey);
221+
storage.removeItem(testKey);
222+
223+
expect(wrappedObjectResult).toBe(nativeObjectResult);
224+
expect(wrappedObjectResult).toBe("[object Object]");
225+
226+
// Test array (should become comma-separated values)
227+
const arrayValue = [1, 2, 3];
228+
localStorage.setItem(testKey, arrayValue);
229+
const nativeArrayResult = localStorage.getItem(testKey);
230+
localStorage.removeItem(testKey);
231+
232+
storage.setItem(testKey, arrayValue);
233+
const wrappedArrayResult = storage.getItem(testKey);
234+
storage.removeItem(testKey);
235+
236+
expect(wrappedArrayResult).toBe(nativeArrayResult);
237+
expect(wrappedArrayResult).toBe("1,2,3");
238+
239+
// Test function (should become function string)
240+
const functionValue = function () {
241+
return "test";
242+
};
243+
localStorage.setItem(testKey, functionValue);
244+
const nativeFunctionResult = localStorage.getItem(testKey);
245+
localStorage.removeItem(testKey);
246+
247+
storage.setItem(testKey, functionValue);
248+
const wrappedFunctionResult = storage.getItem(testKey);
249+
storage.removeItem(testKey);
250+
251+
expect(wrappedFunctionResult).toBe(nativeFunctionResult);
252+
expect(wrappedFunctionResult).toContain("function");
253+
});
254+
255+
it("handles missing value parameter the same as native localStorage", () => {
256+
const storage = wrapStorage(window.localStorage);
257+
const testKey = "test-missing-value";
258+
259+
// Test what happens when setItem is called with no second argument
260+
// Native localStorage throws an error when only one argument is provided
261+
expect(() => {
262+
localStorage.setItem(testKey);
263+
}).toThrow(
264+
"Failed to execute 'setItem' on 'Storage': 2 arguments required, but only 1 present."
265+
);
266+
267+
// Our wrapped storage should also throw an error or behave consistently
268+
expect(() => {
269+
storage.setItem(testKey);
270+
}).toThrow();
271+
});
272+
273+
it("handles no arguments the same as native localStorage", () => {
274+
const storage = wrapStorage(window.localStorage);
275+
276+
// Test what happens when setItem is called with no arguments at all
277+
expect(() => {
278+
localStorage.setItem();
279+
}).toThrow(
280+
"Failed to execute 'setItem' on 'Storage': 2 arguments required, but only 0 present."
281+
);
282+
283+
expect(() => {
284+
storage.setItem();
285+
}).toThrow(
286+
"Failed to execute 'setItem' on 'Storage': 2 arguments required, but only 0 present."
287+
);
288+
});
156289
});
157290

158291
describe("getItem", () => {

0 commit comments

Comments
 (0)