Handle QuotaExceededError in StyleStore (#1253)

## Launch Checklist

<!-- Thanks for the PR! Feel free to add or remove items from the
checklist. -->

When localStorage is full you start getting a "QuotaExceededError".
RIght now Maputnik does not handle this situation gracefully, it just
fails loading the style with a non-descriptive error message.

This PR purges localStorage and tries again when this particular error
happens.

It still does not show a descriptive error message. If you try to load a
style that is larger than what localStorage can handle, it will still
fail with a non-descriptive error message.

Increased the size of `example-style.json` so that it causes a
QuotaExceededError when running the regression test (try it before and
after this PR).


 - [x] Briefly describe the changes in this PR.
 - [x] Link to related issues. N/A
- [x] Include before/after visuals or gifs if this PR includes visual
changes. N/A
 - [x] Write tests for all new functionality.
 - [x] Add an entry to `CHANGELOG.md` under the `## main` section.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Bart Louwers
2025-07-04 10:27:00 +02:00
committed by GitHub
parent f5b7eccf52
commit 599240033a
5 changed files with 179 additions and 14 deletions
+4 -2
View File
@@ -8,8 +8,10 @@ const baseUrl = "http://localhost:8888/";
const styleFromWindow = (win: Window) => {
const styleId = win.localStorage.getItem("maputnik:latest_style");
const styleItem = win.localStorage.getItem(`maputnik:style:${styleId}`);
const obj = JSON.parse(styleItem || "");
const styleItemKey = `maputnik:style:${styleId}`;
const styleItem = win.localStorage.getItem(styleItemKey);
if (!styleItem) throw new Error("Could not get styleItem from localStorage");
const obj = JSON.parse(styleItem);
return obj;
};
+40
View File
@@ -275,4 +275,44 @@ describe("modals", () => {
describe("sources", () => {
it("toggle");
});
describe("Handle localStorage QuotaExceededError", () => {
it("handles quota exceeded error when opening style from URL", () => {
// Clear localStorage to start fresh
cy.clearLocalStorage();
// fill localStorage until we get a QuotaExceededError
cy.window().then(win => {
let chunkSize = 1000;
const chunk = new Array(chunkSize).join("x");
let index = 0;
// Keep adding until we hit the quota
while (true) {
try {
const key = `maputnik:fill-${index++}`;
win.localStorage.setItem(key, chunk);
} catch (e: any) {
// Verify it's a quota error
if (e.name === 'QuotaExceededError') {
if (chunkSize <= 1) return;
else {
chunkSize /= 2;
continue;
}
}
throw e; // Unexpected error
}
}
});
// Open the style via URL input
when.click("nav:open");
when.setValue("modal:open.url.input", get.exampleFileUrl());
when.click("modal:open.url.button");
then(get.responseBody("example-style.json")).shouldEqualToStoredStyle();
then(get.styleFromLocalStorage()).shouldExist();
});
});
});