Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-05-03 03:09:11 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-05-03 03:09:11 +0300
commita0754ad291e60e9411897ae4e05e01a600037ee9 (patch)
treed23b71bd0d4db9245aaa12d2fc81da20bcf0f105 /spec/frontend/super_sidebar
parent90693cc231ba6e1645dc57f2a9111a7b5a5ceae0 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/super_sidebar')
-rw-r--r--spec/frontend/super_sidebar/components/counter_spec.js11
-rw-r--r--spec/frontend/super_sidebar/components/merge_request_menu_spec.js23
-rw-r--r--spec/frontend/super_sidebar/components/user_bar_spec.js17
-rw-r--r--spec/frontend/super_sidebar/mock_data.js10
-rw-r--r--spec/frontend/super_sidebar/user_counts_manager_spec.js166
5 files changed, 211 insertions, 16 deletions
diff --git a/spec/frontend/super_sidebar/components/counter_spec.js b/spec/frontend/super_sidebar/components/counter_spec.js
index 8f514540413..77f77eae1c2 100644
--- a/spec/frontend/super_sidebar/components/counter_spec.js
+++ b/spec/frontend/super_sidebar/components/counter_spec.js
@@ -49,4 +49,15 @@ describe('Counter component', () => {
expect(findButton().exists()).toBe(false);
});
});
+
+ it.each([
+ ['99+', '99+'],
+ ['110%', '110%'],
+ [100, '99+'],
+ [10, '10'],
+ [0, ''],
+ ])('formats count %p as %p', (count, result) => {
+ createWrapper({ count });
+ expect(findButton().text()).toBe(result);
+ });
});
diff --git a/spec/frontend/super_sidebar/components/merge_request_menu_spec.js b/spec/frontend/super_sidebar/components/merge_request_menu_spec.js
index 9c8fd0556f1..53d47397eb3 100644
--- a/spec/frontend/super_sidebar/components/merge_request_menu_spec.js
+++ b/spec/frontend/super_sidebar/components/merge_request_menu_spec.js
@@ -1,6 +1,7 @@
import { GlBadge, GlDisclosureDropdown } from '@gitlab/ui';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import MergeRequestMenu from '~/super_sidebar/components/merge_request_menu.vue';
+import { userCounts } from '~/super_sidebar/user_counts_manager';
import { mergeRequestMenuGroup } from '../mock_data';
describe('MergeRequestMenu component', () => {
@@ -10,17 +11,17 @@ describe('MergeRequestMenu component', () => {
const findGlDisclosureDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
const findLink = (name) => wrapper.findByRole('link', { name });
- const createWrapper = () => {
+ const createWrapper = (items) => {
wrapper = mountExtended(MergeRequestMenu, {
propsData: {
- items: mergeRequestMenuGroup,
+ items,
},
});
};
describe('default', () => {
beforeEach(() => {
- createWrapper();
+ createWrapper(mergeRequestMenuGroup);
});
it('passes the items to the disclosure dropdown', () => {
@@ -49,5 +50,21 @@ describe('MergeRequestMenu component', () => {
it('renders 0 string when count is empty', () => {
expect(findGlBadge(1).text()).toBe(String(0));
});
+
+ it('renders value from userCounts if `userCount` prop is defined', () => {
+ userCounts.assigned_merge_requests = 5;
+ mergeRequestMenuGroup[0].items[0].userCount = 'assigned_merge_requests';
+ createWrapper(mergeRequestMenuGroup);
+
+ expect(findGlBadge(0).text()).toBe(String(userCounts.assigned_merge_requests));
+ });
+
+ it('renders item count if unknown `userCount` prop is defined', () => {
+ const { count } = mergeRequestMenuGroup[0].items[0];
+ mergeRequestMenuGroup[0].items[0].userCount = 'foobar';
+ createWrapper(mergeRequestMenuGroup);
+
+ expect(findGlBadge(0).text()).toBe(String(count));
+ });
});
});
diff --git a/spec/frontend/super_sidebar/components/user_bar_spec.js b/spec/frontend/super_sidebar/components/user_bar_spec.js
index 7abd64ca108..25f699bddb5 100644
--- a/spec/frontend/super_sidebar/components/user_bar_spec.js
+++ b/spec/frontend/super_sidebar/components/user_bar_spec.js
@@ -10,14 +10,10 @@ import Counter from '~/super_sidebar/components/counter.vue';
import UserBar from '~/super_sidebar/components/user_bar.vue';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import waitForPromises from 'helpers/wait_for_promises';
-import { highCountTrim } from '~/lib/utils/text_utility';
+import { userCounts } from '~/super_sidebar/user_counts_manager';
import { sidebarData } from '../mock_data';
import { MOCK_DEFAULT_SEARCH_OPTIONS } from './global_search/mock_data';
-jest.mock('~/lib/utils/text_utility', () => ({
- highCountTrim: jest.fn().mockReturnValue('99+'),
-}));
-
describe('UserBar component', () => {
let wrapper;
@@ -78,7 +74,7 @@ describe('UserBar component', () => {
it('renders issues counter', () => {
const isuesCounter = findIssuesCounter();
- expect(isuesCounter.props('count')).toBe(sidebarData.assigned_open_issues_count);
+ expect(isuesCounter.props('count')).toBe(userCounts.assigned_issues);
expect(isuesCounter.props('href')).toBe(sidebarData.issues_dashboard_path);
expect(isuesCounter.props('label')).toBe(__('Issues'));
expect(isuesCounter.attributes('data-track-action')).toBe('click_link');
@@ -89,7 +85,9 @@ describe('UserBar component', () => {
it('renders merge requests counter', () => {
const mrsCounter = findMRsCounter();
- expect(mrsCounter.props('count')).toBe(sidebarData.total_merge_requests_count);
+ expect(mrsCounter.props('count')).toBe(
+ userCounts.assigned_merge_requests + userCounts.review_requested_merge_requests,
+ );
expect(mrsCounter.props('label')).toBe(__('Merge requests'));
expect(mrsCounter.attributes('data-track-action')).toBe('click_dropdown');
expect(mrsCounter.attributes('data-track-label')).toBe('merge_requests_menu');
@@ -107,13 +105,12 @@ describe('UserBar component', () => {
expect(todosCounter.attributes('class')).toContain('shortcuts-todos');
});
- it('should format and update todo counter when event is emitted', async () => {
+ it('should update todo counter when event is emitted', async () => {
createWrapper();
const count = 100;
document.dispatchEvent(new CustomEvent('todo:toggle', { detail: { count } }));
await nextTick();
- expect(highCountTrim).toHaveBeenCalledWith(count);
- expect(findTodosCounter().props('count')).toBe('99+');
+ expect(findTodosCounter().props('count')).toBe(count);
});
});
diff --git a/spec/frontend/super_sidebar/mock_data.js b/spec/frontend/super_sidebar/mock_data.js
index ecb662be481..d42bc24098d 100644
--- a/spec/frontend/super_sidebar/mock_data.js
+++ b/spec/frontend/super_sidebar/mock_data.js
@@ -81,10 +81,14 @@ export const sidebarData = {
username: 'root',
avatar_url: 'path/to/img_administrator',
logo_url: 'path/to/logo',
- assigned_open_issues_count: 1,
- todos_pending_count: 3,
+ user_counts: {
+ last_update: Date.now(),
+ todos: 3,
+ assigned_issues: 1,
+ assigned_merge_requests: 3,
+ review_requested_merge_requests: 1,
+ },
issues_dashboard_path: 'path/to/issues',
- total_merge_requests_count: 4,
create_new_menu_groups: createNewMenuGroups,
merge_request_menu: mergeRequestMenuGroup,
projects_path: 'path/to/projects',
diff --git a/spec/frontend/super_sidebar/user_counts_manager_spec.js b/spec/frontend/super_sidebar/user_counts_manager_spec.js
new file mode 100644
index 00000000000..b5074620195
--- /dev/null
+++ b/spec/frontend/super_sidebar/user_counts_manager_spec.js
@@ -0,0 +1,166 @@
+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();
+ });
+ });
+ });
+});