256 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			256 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| import Vue, { nextTick } from 'vue';
 | |
| import VueApollo from 'vue-apollo';
 | |
| import { GlDatepicker, GlLoadingIcon, GlKeysetPagination } from '@gitlab/ui';
 | |
| import getTimelogsEmptyResponse from 'test_fixtures/graphql/get_timelogs_empty_response.json';
 | |
| import getPaginatedTimelogsResponse from 'test_fixtures/graphql/get_paginated_timelogs_response.json';
 | |
| import getNonPaginatedTimelogsResponse from 'test_fixtures/graphql/get_non_paginated_timelogs_response.json';
 | |
| import GroupSelect from '~/vue_shared/components/entity_select/group_select.vue';
 | |
| import * as Sentry from '~/sentry/sentry_browser_wrapper';
 | |
| import { createAlert } from '~/alert';
 | |
| import { mountExtended, extendedWrapper } from 'helpers/vue_test_utils_helper';
 | |
| import createMockApollo from 'helpers/mock_apollo_helper';
 | |
| import waitForPromises from 'helpers/wait_for_promises';
 | |
| import getTimelogsQuery from '~/time_tracking/components/queries/get_timelogs.query.graphql';
 | |
| import TimelogsApp from '~/time_tracking/components/timelogs_app.vue';
 | |
| import TimelogsTable from '~/time_tracking/components/timelogs_table.vue';
 | |
| 
 | |
| jest.mock('~/alert');
 | |
| jest.mock('~/sentry/sentry_browser_wrapper');
 | |
| 
 | |
| describe('Timelogs app', () => {
 | |
|   Vue.use(VueApollo);
 | |
| 
 | |
|   let wrapper;
 | |
|   let fakeApollo;
 | |
| 
 | |
|   const findForm = () => wrapper.find('form');
 | |
|   const findUsernameInput = () => extendedWrapper(findForm()).findByTestId('form-username');
 | |
|   const findTableContainer = () => wrapper.findByTestId('table-container');
 | |
|   const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
 | |
|   const findTotalTimeSpentContainer = () => wrapper.findByTestId('total-time-spent-container');
 | |
|   const findTable = () => wrapper.findComponent(TimelogsTable);
 | |
|   const findPagination = () => wrapper.findComponent(GlKeysetPagination);
 | |
|   const findGroupSelect = () => findForm().findComponent(GroupSelect);
 | |
| 
 | |
|   const findFormDatePicker = (testId) =>
 | |
|     findForm()
 | |
|       .findAllComponents(GlDatepicker)
 | |
|       .filter((c) => c.attributes('data-testid') === testId);
 | |
|   const findFromDatepicker = () => findFormDatePicker('form-from-date').at(0);
 | |
|   const findToDatepicker = () => findFormDatePicker('form-to-date').at(0);
 | |
| 
 | |
|   const submitForm = () => findForm().trigger('submit');
 | |
| 
 | |
|   const resolvedEmptyListMock = jest.fn().mockResolvedValue(getTimelogsEmptyResponse);
 | |
|   const resolvedPaginatedListMock = jest.fn().mockResolvedValue(getPaginatedTimelogsResponse);
 | |
|   const resolvedNonPaginatedListMock = jest.fn().mockResolvedValue(getNonPaginatedTimelogsResponse);
 | |
|   const rejectedMock = jest.fn().mockRejectedValue({});
 | |
| 
 | |
|   const mountComponent = ({ props, data } = {}, queryResolverMock = resolvedEmptyListMock) => {
 | |
|     fakeApollo = createMockApollo([[getTimelogsQuery, queryResolverMock]]);
 | |
| 
 | |
|     wrapper = mountExtended(TimelogsApp, {
 | |
|       data() {
 | |
|         return {
 | |
|           ...data,
 | |
|         };
 | |
|       },
 | |
|       propsData: {
 | |
|         limitToHours: false,
 | |
|         ...props,
 | |
|       },
 | |
|       apolloProvider: fakeApollo,
 | |
|     });
 | |
|   };
 | |
| 
 | |
|   beforeEach(() => {
 | |
|     createAlert.mockClear();
 | |
|     Sentry.captureException.mockClear();
 | |
|   });
 | |
| 
 | |
|   afterEach(() => {
 | |
|     fakeApollo = null;
 | |
|   });
 | |
| 
 | |
|   describe('the content', () => {
 | |
|     it('shows the form and the loading icon when loading', () => {
 | |
|       mountComponent();
 | |
| 
 | |
|       expect(findForm().exists()).toBe(true);
 | |
|       expect(findLoadingIcon().exists()).toBe(true);
 | |
|       expect(findTableContainer().exists()).toBe(false);
 | |
|     });
 | |
| 
 | |
|     it('shows the form and the table container when finished loading', async () => {
 | |
|       mountComponent();
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(findForm().exists()).toBe(true);
 | |
|       expect(findLoadingIcon().exists()).toBe(false);
 | |
|       expect(findTableContainer().exists()).toBe(true);
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('the filter form', () => {
 | |
|     it('runs the query with the correct data', async () => {
 | |
|       mountComponent();
 | |
| 
 | |
|       const username = 'johnsmith';
 | |
|       const fromDateTime = new Date('2023-02-28');
 | |
|       const toDateTime = new Date('2023-03-28');
 | |
| 
 | |
|       findUsernameInput().vm.$emit('input', username);
 | |
|       findFromDatepicker().vm.$emit('input', fromDateTime);
 | |
|       findToDatepicker().vm.$emit('input', toDateTime);
 | |
|       findGroupSelect().vm.$emit('input', { id: 123 });
 | |
| 
 | |
|       resolvedEmptyListMock.mockClear();
 | |
| 
 | |
|       submitForm();
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(resolvedEmptyListMock).toHaveBeenCalledWith({
 | |
|         username,
 | |
|         startTime: fromDateTime,
 | |
|         endTime: toDateTime,
 | |
|         groupId: 'gid://gitlab/Group/123',
 | |
|         projectId: null,
 | |
|         first: 20,
 | |
|         last: null,
 | |
|         after: null,
 | |
|         before: null,
 | |
|       });
 | |
| 
 | |
|       expect(`${wrapper.vm.queryVariables.startTime}`).toEqual(
 | |
|         'Tue Feb 28 2023 00:00:00 GMT+0000 (Greenwich Mean Time)',
 | |
|       );
 | |
|       // should be 1 day ahead of the initial To Date value
 | |
|       expect(`${wrapper.vm.queryVariables.endTime}`).toEqual(
 | |
|         'Tue Mar 28 2023 23:59:59 GMT+0000 (Greenwich Mean Time)',
 | |
|       );
 | |
| 
 | |
|       expect(createAlert).not.toHaveBeenCalled();
 | |
|       expect(Sentry.captureException).not.toHaveBeenCalled();
 | |
|     });
 | |
| 
 | |
|     it('runs the query with the correct data after the date filters are cleared', async () => {
 | |
|       mountComponent();
 | |
| 
 | |
|       const username = 'johnsmith';
 | |
| 
 | |
|       findUsernameInput().vm.$emit('input', username);
 | |
|       findGroupSelect().vm.$emit('input', { id: 123 });
 | |
| 
 | |
|       await nextTick();
 | |
| 
 | |
|       findFromDatepicker().vm.$emit('clear');
 | |
|       findToDatepicker().vm.$emit('clear');
 | |
|       findGroupSelect().vm.$emit('clear');
 | |
| 
 | |
|       resolvedEmptyListMock.mockClear();
 | |
| 
 | |
|       submitForm();
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(resolvedEmptyListMock).toHaveBeenCalledWith({
 | |
|         username,
 | |
|         startTime: null,
 | |
|         endTime: null,
 | |
|         groupId: null,
 | |
|         projectId: null,
 | |
|         first: 20,
 | |
|         last: null,
 | |
|         after: null,
 | |
|         before: null,
 | |
|       });
 | |
|       expect(createAlert).not.toHaveBeenCalled();
 | |
|       expect(Sentry.captureException).not.toHaveBeenCalled();
 | |
|     });
 | |
| 
 | |
|     it('shows an alert an logs to sentry when the mutation is rejected', async () => {
 | |
|       mountComponent({}, rejectedMock);
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(createAlert).toHaveBeenCalledWith({
 | |
|         message: 'Something went wrong. Please try again.',
 | |
|       });
 | |
|       expect(Sentry.captureException).toHaveBeenCalled();
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('the total time spent container', () => {
 | |
|     it('is not visible when there are no timelogs', async () => {
 | |
|       mountComponent();
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(findTotalTimeSpentContainer().exists()).toBe(false);
 | |
|     });
 | |
| 
 | |
|     it('shows the correct value when `limitToHours` is false', async () => {
 | |
|       mountComponent({}, resolvedNonPaginatedListMock);
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(findTotalTimeSpentContainer().exists()).toBe(true);
 | |
|       expect(findTotalTimeSpentContainer().text()).toBe('3d');
 | |
|     });
 | |
| 
 | |
|     it('shows the correct value when `limitToHours` is true', async () => {
 | |
|       mountComponent({ props: { limitToHours: true } }, resolvedNonPaginatedListMock);
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(findTotalTimeSpentContainer().exists()).toBe(true);
 | |
|       expect(findTotalTimeSpentContainer().text()).toBe('24h');
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('the table', () => {
 | |
|     it('gets created with the right props when `limitToHours` is false', async () => {
 | |
|       mountComponent({}, resolvedNonPaginatedListMock);
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(findTable().props()).toMatchObject({
 | |
|         limitToHours: false,
 | |
|         entries: getNonPaginatedTimelogsResponse.data.timelogs.nodes,
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     it('gets created with the right props when `limitToHours` is true', async () => {
 | |
|       mountComponent({ props: { limitToHours: true } }, resolvedNonPaginatedListMock);
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(findTable().props()).toMatchObject({
 | |
|         limitToHours: true,
 | |
|         entries: getNonPaginatedTimelogsResponse.data.timelogs.nodes,
 | |
|       });
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('the pagination element', () => {
 | |
|     it('is not visible whene there is no pagination data', async () => {
 | |
|       mountComponent({}, resolvedNonPaginatedListMock);
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(findPagination().exists()).toBe(false);
 | |
|     });
 | |
| 
 | |
|     it('is visible whene there is pagination data', async () => {
 | |
|       mountComponent({}, resolvedPaginatedListMock);
 | |
| 
 | |
|       await waitForPromises();
 | |
|       await nextTick();
 | |
| 
 | |
|       expect(findPagination().exists()).toBe(true);
 | |
|     });
 | |
|   });
 | |
| });
 |