diff --git a/src/store.js b/src/store.js index 73ace45..d774eab 100644 --- a/src/store.js +++ b/src/store.js @@ -11,6 +11,7 @@ export class Store { if (!storage) throw new Error('Store requires a storage object'); this.storage = storage; this.onWarn = onWarn; + this._saveDisabled = false; this.targets = this._loadJson(KEY_TARGETS, {}); this.history = this._loadJson(KEY_HISTORY, {}); this.prefs = this._mergePrefs(this._loadJson(KEY_PREFS, null)); @@ -34,11 +35,13 @@ export class Store { } _saveJson(key, value) { + if (this._saveDisabled) return false; try { this.storage.setItem(key, JSON.stringify(value)); return true; } catch (e) { - this.onWarn(`[tat] failed to persist ${key}: ${e.message}`); + this.onWarn(`[tat] failed to persist ${key}: ${e.message}; further saves disabled for this session`); + this._saveDisabled = true; return false; } } diff --git a/tests/store.test.js b/tests/store.test.js index 286e2a9..9d5c982 100644 --- a/tests/store.test.js +++ b/tests/store.test.js @@ -48,4 +48,25 @@ test('Store: corrupted JSON is wiped with a warning', () => { const s = new Store({ storage, onWarn: (m) => warnings.push(m) }); assert.equal(s.getTarget('strength'), null); assert.equal(warnings.length, 1); + assert.equal(storage.getItem('tat.targets'), null); + const warningsBefore = warnings.length; + new Store({ storage, onWarn: (m) => warnings.push(m) }); + assert.equal(warnings.length, warningsBefore); +}); + +test('Store: latches off further saves after a storage write failure', () => { + const data = new Map(); + const throwingStorage = { + getItem(k) { return data.has(k) ? data.get(k) : null; }, + setItem() { throw new Error('quota exceeded'); }, + removeItem(k) { data.delete(k); }, + clear() { data.clear(); }, + }; + const warnings = []; + const s = new Store({ storage: throwingStorage, onWarn: (m) => warnings.push(m) }); + assert.equal(s.setTarget('strength', 25_000_000), false); + assert.equal(s.setTarget('speed', 50_000_000), false); + assert.equal(warnings.length, 1); + assert.equal(s.getTarget('strength'), 25_000_000); + assert.equal(s.getTarget('speed'), 50_000_000); });