-
Notifications
You must be signed in to change notification settings - Fork 392
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'devel' into feat/cb-3456/form-template
- Loading branch information
Showing
5 changed files
with
490 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
webapp/packages/core-sdk/src/Resource/CachedDataResource.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
/* | ||
* CloudBeaver - Cloud Database Manager | ||
* Copyright (C) 2020-2023 DBeaver Corp and others | ||
* | ||
* Licensed under the Apache License, Version 2.0. | ||
* you may not use this file except in compliance with the License. | ||
*/ | ||
import { CachedDataResource } from './CachedDataResource'; | ||
|
||
interface IEntityData { | ||
id: string; | ||
value: number; | ||
} | ||
|
||
const DEFAULT_STATE_GETTER: () => IEntityData[] = () => []; | ||
const DATA_MOCK_GETTER: () => IEntityData[] = () => [ | ||
{ | ||
id: '1', | ||
value: 1, | ||
}, | ||
{ | ||
id: '2', | ||
value: 2, | ||
}, | ||
]; | ||
|
||
async function fetchMock(): Promise<IEntityData[]> { | ||
return new Promise(resolve => { | ||
setTimeout(() => { | ||
resolve(DATA_MOCK_GETTER()); | ||
}, 1); | ||
}); | ||
} | ||
|
||
class TestDataResource extends CachedDataResource<IEntityData[]> { | ||
constructor() { | ||
super(DEFAULT_STATE_GETTER); | ||
} | ||
|
||
protected async loader() { | ||
const data = await fetchMock(); | ||
return data; | ||
} | ||
} | ||
|
||
describe('CachedDataResource', () => { | ||
let dataResource: TestDataResource; | ||
|
||
beforeEach(() => { | ||
dataResource = new TestDataResource(); | ||
}); | ||
|
||
test('should instantiate correctly', () => { | ||
expect(dataResource).toBeInstanceOf(CachedDataResource); | ||
}); | ||
|
||
test('should initialize with the default state', () => { | ||
expect(dataResource.data).toEqual(DEFAULT_STATE_GETTER()); | ||
}); | ||
|
||
test('should load data', async () => { | ||
await dataResource.load(); | ||
expect(dataResource.data).toEqual(DATA_MOCK_GETTER()); | ||
}); | ||
|
||
test('should be able to outdate the data', () => { | ||
dataResource.markOutdated(); | ||
expect(dataResource.isOutdated()).toBe(true); | ||
}); | ||
|
||
test('should run onDataOutdated handlers on data outdate', () => { | ||
const handler = jest.fn(); | ||
|
||
dataResource.onDataOutdated.addHandler(handler); | ||
dataResource.markOutdated(); | ||
|
||
expect(handler).toHaveBeenCalled(); | ||
}); | ||
|
||
test('should run onDataUpdate handlers on data update', () => { | ||
const handler = jest.fn(); | ||
|
||
dataResource.onDataUpdate.addHandler(handler); | ||
dataResource.dataUpdate(); | ||
|
||
expect(handler).toHaveBeenCalled(); | ||
}); | ||
|
||
test('should be able to clear the data', async () => { | ||
await dataResource.load(); | ||
dataResource.clear(); | ||
|
||
expect(dataResource.data).toEqual([]); | ||
}); | ||
}); |
254 changes: 254 additions & 0 deletions
254
webapp/packages/core-sdk/src/Resource/CachedMapResource.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
/* | ||
* CloudBeaver - Cloud Database Manager | ||
* Copyright (C) 2020-2023 DBeaver Corp and others | ||
* | ||
* Licensed under the Apache License, Version 2.0. | ||
* you may not use this file except in compliance with the License. | ||
*/ | ||
import { toJS } from 'mobx'; | ||
|
||
import { CachedMapResource } from './CachedMapResource'; | ||
import type { ResourceKey } from './ResourceKey'; | ||
import { resourceKeyList } from './ResourceKeyList'; | ||
|
||
interface IEntityData { | ||
id: string; | ||
value: number; | ||
} | ||
|
||
const ERROR_ITEM_ID = 'error'; | ||
|
||
const DATA_MOCK_GETTER: () => IEntityData[] = () => [ | ||
{ | ||
id: '1', | ||
value: 1, | ||
}, | ||
{ | ||
id: '2', | ||
value: 2, | ||
}, | ||
{ | ||
id: ERROR_ITEM_ID, | ||
value: 3, | ||
}, | ||
]; | ||
|
||
const TEST_ERROR_MESSAGE = 'Test error'; | ||
const DEFAULT_STATE_GETTER = () => new Map(); | ||
|
||
async function fetchMock(key: ResourceKey<string> | undefined): Promise<IEntityData[]> { | ||
const data = DATA_MOCK_GETTER(); | ||
|
||
return new Promise((resolve, reject) => { | ||
setTimeout(() => { | ||
if (key) { | ||
if (key === ERROR_ITEM_ID) { | ||
reject(new Error(TEST_ERROR_MESSAGE)); | ||
} | ||
|
||
const item = data.find(d => d.id === key); | ||
if (item) { | ||
resolve([item]); | ||
} | ||
} else { | ||
resolve(data); | ||
} | ||
}, 1); | ||
}); | ||
} | ||
|
||
class TestMapResource extends CachedMapResource<string, IEntityData> { | ||
constructor() { | ||
super(DEFAULT_STATE_GETTER); | ||
} | ||
|
||
protected async loader(key: ResourceKey<string>) { | ||
const data = await fetchMock(key); | ||
this.replace(resourceKeyList(data.map(d => d.id)), data); | ||
return this.data; | ||
} | ||
|
||
protected validateKey(key: string): boolean { | ||
return typeof key === 'string'; | ||
} | ||
} | ||
|
||
describe('CachedMapResource', () => { | ||
let mapResource: TestMapResource; | ||
|
||
beforeEach(() => { | ||
mapResource = new TestMapResource(); | ||
}); | ||
|
||
test('should instantiate correctly', () => { | ||
expect(mapResource).toBeInstanceOf(CachedMapResource); | ||
}); | ||
|
||
test('should initialize with the initial value', () => { | ||
expect(toJS(mapResource.data)).toEqual(DEFAULT_STATE_GETTER()); | ||
}); | ||
|
||
test('should return all entries', () => { | ||
mapResource.set('key1', { id: 'key1', value: 1 }); | ||
mapResource.set('key2', { id: 'key2', value: 2 }); | ||
expect(mapResource.entries).toEqual([ | ||
['key1', { id: 'key1', value: 1 }], | ||
['key2', { id: 'key2', value: 2 }], | ||
]); | ||
}); | ||
|
||
test('should return all values', () => { | ||
mapResource.set('key1', { id: 'key1', value: 1 }); | ||
mapResource.set('key2', { id: 'key2', value: 2 }); | ||
expect(mapResource.values).toEqual([ | ||
{ id: 'key1', value: 1 }, | ||
{ id: 'key2', value: 2 }, | ||
]); | ||
}); | ||
|
||
test('should return all keys', () => { | ||
mapResource.set('key1', { id: 'key1', value: 1 }); | ||
mapResource.set('key2', { id: 'key2', value: 2 }); | ||
expect(mapResource.keys).toEqual(['key1', 'key2']); | ||
}); | ||
|
||
test('should load data for a specific key', async () => { | ||
await mapResource.load('1'); | ||
expect(mapResource.get('1')).toEqual({ id: '1', value: 1 }); | ||
expect(mapResource.get('2')).toBeUndefined(); // This key was not loaded | ||
}); | ||
|
||
test('should NOT load data for a key that produces an error', async () => { | ||
await expect(mapResource.load(ERROR_ITEM_ID)).rejects.toThrow(TEST_ERROR_MESSAGE); | ||
expect(mapResource.get(ERROR_ITEM_ID)).toBeUndefined(); | ||
}); | ||
|
||
test('should mark loaded data as loaded', async () => { | ||
await mapResource.load('1'); | ||
expect(mapResource.isLoaded('1')).toBe(true); | ||
}); | ||
|
||
test('should set and get a value', () => { | ||
mapResource.set('key1', { id: 'key1', value: 1 }); | ||
expect(mapResource.get('key1')).toStrictEqual({ id: 'key1', value: 1 }); | ||
}); | ||
|
||
test('should delete a value', () => { | ||
mapResource.set('key1', { id: 'key1', value: 1 }); | ||
mapResource.delete('key1'); | ||
expect(mapResource.get('key1')).toBeUndefined(); | ||
}); | ||
|
||
test('should check if a key exists', () => { | ||
mapResource.set('key1', { id: 'key1', value: 1 }); | ||
expect(mapResource.has('key1')).toBe(true); | ||
expect(mapResource.has('key2')).toBe(false); | ||
}); | ||
|
||
test('should replace multiple keys', () => { | ||
mapResource.set('key1', { id: 'key1', value: 1 }); | ||
mapResource.set('key2', { id: 'key2', value: 2 }); | ||
mapResource.set('key4', { id: 'key4', value: 4 }); | ||
|
||
mapResource.replace(resourceKeyList(['key1', 'key3']), [ | ||
{ id: 'key1', value: 11 }, | ||
{ id: 'key3', value: 33 }, | ||
]); | ||
|
||
expect(mapResource.get('key1')).toStrictEqual({ id: 'key1', value: 11 }); | ||
expect(mapResource.get('key2')).toBeUndefined(); | ||
expect(mapResource.get('key3')).toStrictEqual({ id: 'key3', value: 33 }); | ||
expect(mapResource.data.size).toBe(2); | ||
}); | ||
|
||
test('should outdated certain keys', () => { | ||
mapResource.set('key1', { id: 'key1', value: 1 }); | ||
mapResource.set('key2', { id: 'key2', value: 2 }); | ||
|
||
mapResource.markOutdated('key1'); | ||
|
||
expect(mapResource.isOutdated('key1')).toBe(true); | ||
expect(mapResource.isOutdated('key2')).toBe(false); | ||
}); | ||
|
||
test('should run onDataOutdated handlers on data outdate', () => { | ||
const handler = jest.fn(); | ||
|
||
mapResource.set('key1', { id: 'key1', value: 1 }); | ||
mapResource.set('key2', { id: 'key2', value: 2 }); | ||
|
||
mapResource.onDataOutdated.addHandler(key => { | ||
handler(); | ||
expect(key).toBe('key1'); | ||
}); | ||
|
||
mapResource.markOutdated('key1'); | ||
expect(handler).toHaveBeenCalled(); | ||
}); | ||
|
||
test('should run onDataUpdate handlers on data update', () => { | ||
const handler = jest.fn(); | ||
|
||
mapResource.set('key1', { id: 'key1', value: 1 }); | ||
mapResource.set('key2', { id: 'key2', value: 2 }); | ||
|
||
mapResource.onDataUpdate.addHandler(key => { | ||
handler(); | ||
expect(key).toBe('key2'); | ||
}); | ||
|
||
mapResource.dataUpdate('key2'); | ||
expect(handler).toHaveBeenCalled(); | ||
}); | ||
|
||
test('should run onItemDelete handlers on data delete', () => { | ||
const handler = jest.fn(); | ||
|
||
mapResource.set('key1', { id: 'key1', value: 1 }); | ||
mapResource.set('key2', { id: 'key2', value: 2 }); | ||
|
||
mapResource.onItemDelete.addHandler(key => { | ||
handler(); | ||
expect(key).toBe('key1'); | ||
}); | ||
|
||
mapResource.delete('key1'); | ||
expect(handler).toHaveBeenCalled(); | ||
}); | ||
|
||
test('should run onItemUpdate handlers on item update', () => { | ||
const handler = jest.fn(); | ||
|
||
mapResource.set('key1', { id: 'key1', value: 1 }); | ||
mapResource.set('key2', { id: 'key2', value: 2 }); | ||
|
||
mapResource.onItemUpdate.addHandler(key => { | ||
handler(); | ||
expect(key).toBe('key2'); | ||
}); | ||
|
||
mapResource.set('key2', { id: 'key2', value: 22 }); | ||
expect(handler).toHaveBeenCalled(); | ||
}); | ||
|
||
test('should run onDataError handlers on data error', async () => { | ||
const handler = jest.fn(); | ||
|
||
mapResource.set('key1', { id: 'key1', value: 1 }); | ||
mapResource.set('key2', { id: 'key2', value: 2 }); | ||
|
||
mapResource.onDataError.addHandler(data => { | ||
handler(); | ||
expect(data.param).toBe(ERROR_ITEM_ID); | ||
expect(data.exception.message).toBe(TEST_ERROR_MESSAGE); | ||
}); | ||
|
||
await expect(mapResource.load(ERROR_ITEM_ID)).rejects.toThrow(TEST_ERROR_MESSAGE); | ||
expect(handler).toHaveBeenCalled(); | ||
}); | ||
|
||
test('should be able to get an exception if the one occurred for the key', async () => { | ||
await expect(mapResource.load(ERROR_ITEM_ID)).rejects.toThrow(TEST_ERROR_MESSAGE); | ||
expect(mapResource.getException(ERROR_ITEM_ID)?.message).toBe(TEST_ERROR_MESSAGE); | ||
}); | ||
}); |
Oops, something went wrong.