Add frontend UsersCache class (!11404)
This commit is contained in:
parent
c102656736
commit
d7f9b408bf
2 changed files with 164 additions and 0 deletions
28
app/assets/javascripts/lib/utils/users_cache.js
Normal file
28
app/assets/javascripts/lib/utils/users_cache.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
import Api from '../../api';
|
||||
import Cache from './cache';
|
||||
|
||||
class UsersCache extends Cache {
|
||||
retrieve(username) {
|
||||
if (this.hasData(username)) {
|
||||
return Promise.resolve(this.get(username));
|
||||
}
|
||||
|
||||
return Api.users('', { username })
|
||||
.then((users) => {
|
||||
if (!users.length) {
|
||||
throw new Error(`User "${username}" could not be found!`);
|
||||
}
|
||||
|
||||
if (users.length > 1) {
|
||||
throw new Error(`Expected username "${username}" to be unique!`);
|
||||
}
|
||||
|
||||
const user = users[0];
|
||||
this.internalStorage[username] = user;
|
||||
return user;
|
||||
});
|
||||
// missing catch is intentional, error handling depends on use case
|
||||
}
|
||||
}
|
||||
|
||||
export default new UsersCache();
|
136
spec/javascripts/lib/utils/users_cache_spec.js
Normal file
136
spec/javascripts/lib/utils/users_cache_spec.js
Normal file
|
@ -0,0 +1,136 @@
|
|||
import Api from '~/api';
|
||||
import UsersCache from '~/lib/utils/users_cache';
|
||||
|
||||
describe('UsersCache', () => {
|
||||
const dummyUsername = 'win';
|
||||
const dummyUser = 'has a farm';
|
||||
|
||||
beforeEach(() => {
|
||||
UsersCache.internalStorage = { };
|
||||
});
|
||||
|
||||
describe('get', () => {
|
||||
it('returns undefined for empty cache', () => {
|
||||
expect(UsersCache.internalStorage).toEqual({ });
|
||||
|
||||
const user = UsersCache.get(dummyUsername);
|
||||
|
||||
expect(user).toBe(undefined);
|
||||
});
|
||||
|
||||
it('returns undefined for missing user', () => {
|
||||
UsersCache.internalStorage['no body'] = 'no data';
|
||||
|
||||
const user = UsersCache.get(dummyUsername);
|
||||
|
||||
expect(user).toBe(undefined);
|
||||
});
|
||||
|
||||
it('returns matching user', () => {
|
||||
UsersCache.internalStorage[dummyUsername] = dummyUser;
|
||||
|
||||
const user = UsersCache.get(dummyUsername);
|
||||
|
||||
expect(user).toBe(dummyUser);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasData', () => {
|
||||
it('returns false for empty cache', () => {
|
||||
expect(UsersCache.internalStorage).toEqual({ });
|
||||
|
||||
expect(UsersCache.hasData(dummyUsername)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for missing user', () => {
|
||||
UsersCache.internalStorage['no body'] = 'no data';
|
||||
|
||||
expect(UsersCache.hasData(dummyUsername)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns true for matching user', () => {
|
||||
UsersCache.internalStorage[dummyUsername] = dummyUser;
|
||||
|
||||
expect(UsersCache.hasData(dummyUsername)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('remove', () => {
|
||||
it('does nothing if cache is empty', () => {
|
||||
expect(UsersCache.internalStorage).toEqual({ });
|
||||
|
||||
UsersCache.remove(dummyUsername);
|
||||
|
||||
expect(UsersCache.internalStorage).toEqual({ });
|
||||
});
|
||||
|
||||
it('does nothing if cache contains no matching data', () => {
|
||||
UsersCache.internalStorage['no body'] = 'no data';
|
||||
|
||||
UsersCache.remove(dummyUsername);
|
||||
|
||||
expect(UsersCache.internalStorage['no body']).toBe('no data');
|
||||
});
|
||||
|
||||
it('removes matching data', () => {
|
||||
UsersCache.internalStorage[dummyUsername] = dummyUser;
|
||||
|
||||
UsersCache.remove(dummyUsername);
|
||||
|
||||
expect(UsersCache.internalStorage).toEqual({ });
|
||||
});
|
||||
});
|
||||
|
||||
describe('retrieve', () => {
|
||||
let apiSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(Api, 'users').and.callFake((query, options) => apiSpy(query, options));
|
||||
});
|
||||
|
||||
it('stores and returns data from API call if cache is empty', (done) => {
|
||||
apiSpy = (query, options) => {
|
||||
expect(query).toBe('');
|
||||
expect(options).toEqual({ username: dummyUsername });
|
||||
return Promise.resolve([dummyUser]);
|
||||
};
|
||||
|
||||
UsersCache.retrieve(dummyUsername)
|
||||
.then((user) => {
|
||||
expect(user).toBe(dummyUser);
|
||||
expect(UsersCache.internalStorage[dummyUsername]).toBe(dummyUser);
|
||||
})
|
||||
.then(done)
|
||||
.catch(done.fail);
|
||||
});
|
||||
|
||||
it('returns undefined if Ajax call fails and cache is empty', (done) => {
|
||||
const dummyError = new Error('server exploded');
|
||||
apiSpy = (query, options) => {
|
||||
expect(query).toBe('');
|
||||
expect(options).toEqual({ username: dummyUsername });
|
||||
return Promise.reject(dummyError);
|
||||
};
|
||||
|
||||
UsersCache.retrieve(dummyUsername)
|
||||
.then(user => fail(`Received unexpected user: ${JSON.stringify(user)}`))
|
||||
.catch((error) => {
|
||||
expect(error).toBe(dummyError);
|
||||
})
|
||||
.then(done)
|
||||
.catch(done.fail);
|
||||
});
|
||||
|
||||
it('makes no Ajax call if matching data exists', (done) => {
|
||||
UsersCache.internalStorage[dummyUsername] = dummyUser;
|
||||
apiSpy = () => fail(new Error('expected no Ajax call!'));
|
||||
|
||||
UsersCache.retrieve(dummyUsername)
|
||||
.then((user) => {
|
||||
expect(user).toBe(dummyUser);
|
||||
})
|
||||
.then(done)
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue