Merge pull request #15089 from backstage/rugvip/storage-fix

core-app-api: tests + fix for WebStorage event notifications
This commit is contained in:
Patrik Oldsberg
2022-12-07 19:04:27 +01:00
committed by GitHub
2 changed files with 69 additions and 5 deletions
@@ -15,7 +15,13 @@
*/
import { WebStorage } from './WebStorage';
import { ErrorApi, StorageApi } from '@backstage/core-plugin-api';
import {
ErrorApi,
StorageApi,
StorageValueSnapshot,
} from '@backstage/core-plugin-api';
import { buckets } from './WebStorage';
import { JsonValue } from '@backstage/types';
describe('WebStorage Storage API', () => {
const mockErrorApi = { post: jest.fn(), error$: jest.fn() };
@@ -30,6 +36,11 @@ describe('WebStorage Storage API', () => {
...args,
});
};
afterEach(() => {
buckets.clear();
});
it('should return undefined for values which are unset', async () => {
const storage = createWebStorage();
@@ -250,4 +261,50 @@ describe('WebStorage Storage API', () => {
snapshot.value.baz.push({ foo: 'buzz' });
}).toThrow(/Cannot add property 1, object is not extensible/);
});
it('should forward storage events accurately', async () => {
const storage = createWebStorage();
const bucket = storage.forBucket('foo');
localStorage.setItem('/foo/bar%2Fbaz', '"x"');
localStorage.setItem('/foo/bar/baz', '"y"');
expect(bucket.snapshot('bar/baz').value).toBe('x');
expect(bucket.forBucket('bar').snapshot('baz').value).toBe('y');
const notifyPromise = new Promise<StorageValueSnapshot<JsonValue>>(
resolve => {
const subscription = bucket.observe$('bar/baz').subscribe({
next: snapshot => {
resolve(snapshot);
subscription.unsubscribe();
},
});
},
);
await expect(
Promise.race([notifyPromise, 'not-yet-resolved']),
).resolves.toBe('not-yet-resolved');
window.dispatchEvent(new StorageEvent('storage', { key: '/foo/bar/baz' }));
localStorage.setItem('/foo/bar%2Fbaz', '"z"');
await expect(
Promise.race([notifyPromise, 'not-yet-resolved']),
).resolves.toBe('not-yet-resolved');
window.dispatchEvent(
new StorageEvent('storage', { key: '/foo/bar%2Fbaz' }),
);
await expect(notifyPromise).resolves.toEqual({
key: 'bar/baz',
presence: 'present',
value: 'z',
});
expect(bucket.snapshot('bar/baz').value).toEqual('z');
});
});
@@ -22,7 +22,7 @@ import {
import { JsonValue, Observable } from '@backstage/types';
import ObservableImpl from 'zen-observable';
const buckets = new Map<string, WebStorage>();
export const buckets = new Map<string, WebStorage>();
/**
* An implementation of the storage API, that uses the browser's local storage.
@@ -109,9 +109,16 @@ export class WebStorage implements StorageApi {
}
private handleStorageChange(eventKey: StorageEvent['key']) {
if (!eventKey?.startsWith(this.namespace)) return;
const key = eventKey?.replace(`${this.namespace}/`, '');
this.notifyChanges(key);
if (!eventKey?.startsWith(this.namespace)) {
return;
}
// Grab the part of this key that is local to this bucket
const trimmedKey = eventKey?.slice(`${this.namespace}/`.length);
// If the key still contains a slash, it means it's a sub-bucket
if (!trimmedKey.includes('/')) {
this.notifyChanges(decodeURIComponent(trimmedKey));
}
}
private getKeyName(key: string) {