166 lines
4.6 KiB
JavaScript
166 lines
4.6 KiB
JavaScript
import waitForPromises from 'helpers/wait_for_promises';
|
|
|
|
import * as UserApi from '~/api/user_api';
|
|
import {
|
|
createUserCountsManager,
|
|
userCounts,
|
|
destroyUserCountsManager,
|
|
} from '~/super_sidebar/user_counts_manager';
|
|
|
|
jest.mock('~/api');
|
|
|
|
const USER_ID = 123;
|
|
const userCountDefaults = {
|
|
todos: 1,
|
|
assigned_issues: 2,
|
|
assigned_merge_requests: 3,
|
|
review_requested_merge_requests: 4,
|
|
};
|
|
|
|
const userCountUpdate = {
|
|
todos: 123,
|
|
assigned_issues: 456,
|
|
assigned_merge_requests: 789,
|
|
review_requested_merge_requests: 101112,
|
|
};
|
|
|
|
describe('User Merge Requests', () => {
|
|
let channelMock;
|
|
let newBroadcastChannelMock;
|
|
|
|
beforeEach(() => {
|
|
jest.spyOn(document, 'removeEventListener');
|
|
jest.spyOn(document, 'addEventListener');
|
|
|
|
global.gon.current_user_id = USER_ID;
|
|
|
|
channelMock = {
|
|
postMessage: jest.fn(),
|
|
close: jest.fn(),
|
|
};
|
|
newBroadcastChannelMock = jest.fn().mockImplementation(() => channelMock);
|
|
|
|
Object.assign(userCounts, userCountDefaults, { last_update: 0 });
|
|
|
|
global.BroadcastChannel = newBroadcastChannelMock;
|
|
});
|
|
|
|
describe('createUserCountsManager', () => {
|
|
beforeEach(() => {
|
|
createUserCountsManager();
|
|
});
|
|
|
|
it('creates BroadcastChannel which updates counts on message received', () => {
|
|
expect(newBroadcastChannelMock).toHaveBeenCalledWith(`user_counts_${USER_ID}`);
|
|
});
|
|
|
|
it('closes BroadCastchannel if called while already open', () => {
|
|
expect(channelMock.close).not.toHaveBeenCalled();
|
|
|
|
createUserCountsManager();
|
|
|
|
expect(channelMock.close).toHaveBeenCalled();
|
|
});
|
|
|
|
describe('BroadcastChannel onmessage handler', () => {
|
|
it('updates counts on message received', () => {
|
|
expect(userCounts).toMatchObject(userCountDefaults);
|
|
|
|
channelMock.onmessage({ data: { ...userCountUpdate, last_update: Date.now() } });
|
|
|
|
expect(userCounts).toMatchObject(userCountUpdate);
|
|
});
|
|
|
|
it('ignores updates with older data', () => {
|
|
expect(userCounts).toMatchObject(userCountDefaults);
|
|
userCounts.last_update = Date.now();
|
|
|
|
channelMock.onmessage({
|
|
data: { ...userCountUpdate, last_update: userCounts.last_update - 1000 },
|
|
});
|
|
|
|
expect(userCounts).toMatchObject(userCountDefaults);
|
|
});
|
|
|
|
it('ignores unknown fields', () => {
|
|
expect(userCounts).toMatchObject(userCountDefaults);
|
|
|
|
channelMock.onmessage({ data: { ...userCountUpdate, i_am_unknown: 5 } });
|
|
|
|
expect(userCounts).toMatchObject(userCountUpdate);
|
|
expect(userCounts.i_am_unknown).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
it('broadcasts user counts during initialization', () => {
|
|
expect(channelMock.postMessage).toHaveBeenCalledWith(
|
|
expect.objectContaining(userCountDefaults),
|
|
);
|
|
});
|
|
|
|
it('setups event listener without leaking them', () => {
|
|
expect(document.removeEventListener).toHaveBeenCalledWith(
|
|
'userCounts:fetch',
|
|
expect.any(Function),
|
|
);
|
|
expect(document.addEventListener).toHaveBeenCalledWith(
|
|
'userCounts:fetch',
|
|
expect.any(Function),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('Event listener userCounts:fetch', () => {
|
|
beforeEach(() => {
|
|
jest.spyOn(UserApi, 'getUserCounts').mockResolvedValue({
|
|
data: { ...userCountUpdate, merge_requests: 'FOO' },
|
|
});
|
|
createUserCountsManager();
|
|
});
|
|
|
|
it('fetches counts from API, stores and rebroadcasts them', async () => {
|
|
expect(userCounts).toMatchObject(userCountDefaults);
|
|
|
|
document.dispatchEvent(new CustomEvent('userCounts:fetch'));
|
|
await waitForPromises();
|
|
|
|
expect(UserApi.getUserCounts).toHaveBeenCalled();
|
|
expect(userCounts).toMatchObject(userCountUpdate);
|
|
expect(channelMock.postMessage).toHaveBeenLastCalledWith(userCounts);
|
|
});
|
|
});
|
|
|
|
describe('destroyUserCountsManager', () => {
|
|
it('unregisters event handler', () => {
|
|
expect(document.removeEventListener).not.toHaveBeenCalledWith();
|
|
|
|
destroyUserCountsManager();
|
|
|
|
expect(document.removeEventListener).toHaveBeenCalledWith(
|
|
'userCounts:fetch',
|
|
expect.any(Function),
|
|
);
|
|
});
|
|
|
|
describe('when BroadcastChannel is not opened', () => {
|
|
it('does nothing', () => {
|
|
destroyUserCountsManager();
|
|
expect(channelMock.close).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('when BroadcastChannel is opened', () => {
|
|
beforeEach(() => {
|
|
createUserCountsManager();
|
|
});
|
|
|
|
it('closes BroadcastChannel', () => {
|
|
expect(channelMock.close).not.toHaveBeenCalled();
|
|
|
|
destroyUserCountsManager();
|
|
|
|
expect(channelMock.close).toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|
|
});
|