gitlab-ce/spec/frontend/todos/components/toggle_snoozed_status_spec.js

297 lines
9.3 KiB
JavaScript

import { GlTooltip } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ToggleSnoozedStatus from '~/todos/components/toggle_snoozed_status.vue';
import { TODO_STATE_PENDING } from '~/todos/constants';
import createMockApollo from 'helpers/mock_apollo_helper';
import snoozeTodoMutation from '~/todos/components/mutations/snooze_todo.mutation.graphql';
import unSnoozeTodoMutation from '~/todos/components/mutations/un_snooze_todo.mutation.graphql';
import waitForPromises from 'helpers/wait_for_promises';
import { useFakeDate } from 'helpers/fake_date';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { mockTracking, unmockTracking } from 'jest/__helpers__/tracking_helper';
Vue.use(VueApollo);
describe('ToggleSnoozedStatus', () => {
let wrapper;
const mockTodo = {
id: 'gid://gitlab/Todo/1',
state: TODO_STATE_PENDING,
};
const mockCurrentTime = new Date('2024-12-18T13:24:00');
const mockToastShow = jest.fn();
useFakeDate(mockCurrentTime);
const snoozeTodoMutationSuccessHandler = jest.fn().mockResolvedValue({
data: {
todoSnooze: {
todo: {
...mockTodo,
snoozedUntil: mockCurrentTime,
},
errors: [],
},
},
});
const unSnoozeTodoMutationSuccessHandler = jest.fn().mockResolvedValue({
data: {
todoUnSnooze: {
todo: { ...mockTodo, snoozedUntil: mockCurrentTime },
errors: [],
},
},
});
const findSnoozeDropdown = () => wrapper.findByTestId('snooze-dropdown');
const findGlTooltip = () => wrapper.findComponent(GlTooltip);
const getPredefinedSnoozingOption = (index) =>
findSnoozeDropdown().props('items')[0].items[index];
const findUnSnoozeButton = () => wrapper.findByTestId('un-snooze-button');
const createComponent = ({
props = {},
snoozeTodoMutationHandler = snoozeTodoMutationSuccessHandler,
unSnoozeTodoMutationHandler = unSnoozeTodoMutationSuccessHandler,
} = {}) => {
const mockApollo = createMockApollo();
mockApollo.defaultClient.setRequestHandler(snoozeTodoMutation, snoozeTodoMutationHandler);
mockApollo.defaultClient.setRequestHandler(unSnoozeTodoMutation, unSnoozeTodoMutationHandler);
wrapper = shallowMountExtended(ToggleSnoozedStatus, {
apolloProvider: mockApollo,
propsData: {
todo: mockTodo,
...props,
},
provide: {
currentTime: mockCurrentTime,
},
directives: {
GlTooltip: createMockDirective('gl-tooltip'),
},
mocks: {
$toast: {
show: mockToastShow,
},
},
});
};
describe('snoozing dropdown', () => {
it('renders the dropdown if `isSnoozed` is `false` and the todo is pending', () => {
createComponent({ props: { isSnoozed: false, isPending: true } });
expect(findSnoozeDropdown().exists()).toBe(true);
});
it('does not render the dropdown if `isSnoozed` is `true` and the todo is pending', () => {
createComponent({ props: { isSnoozed: true, isPending: true } });
expect(findSnoozeDropdown().exists()).toBe(false);
});
it('does not render the dropdown if `isSnoozed` is `false` and the todo is done', () => {
createComponent({
props: { isSnoozed: false, isPending: false },
});
expect(findSnoozeDropdown().exists()).toBe(false);
});
});
it('renders the snoozing options', () => {
createComponent({ props: { isSnoozed: false, isPending: true } });
expect(findSnoozeDropdown().props('items')).toEqual([
{
items: [
expect.objectContaining({
formattedDate: 'Today, 2:24 PM',
text: 'For one hour',
}),
expect.objectContaining({
formattedDate: 'Today, 5:24 PM',
text: 'Until later today',
}),
expect.objectContaining({
formattedDate: 'Tomorrow, 8:00 AM',
text: 'Until tomorrow',
}),
],
name: 'Snooze',
},
]);
});
it('has the correct props', () => {
createComponent({ props: { isSnoozed: false, isPending: true } });
expect(findSnoozeDropdown().props()).toMatchObject({
toggleText: 'Snooze',
icon: 'clock',
placement: 'bottom-end',
textSrOnly: true,
noCaret: true,
fluidWidth: true,
});
});
it.each`
index | expectedDate | expectedTrackingLabel
${0} | ${'2024-12-18T14:24:00.000Z'} | ${'snooze_for_one_hour'}
${1} | ${'2024-12-18T17:24:00.000Z'} | ${'snooze_until_later_today'}
${2} | ${'2024-12-19T08:00:00.000Z'} | ${'snooze_until_tomorrow'}
`(
'triggers the snooze action with snoozeUntil = $expectedDate when clicking option #$index',
({ index, expectedDate, expectedTrackingLabel }) => {
createComponent({ props: { isSnoozed: false, isPending: true } });
const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
getPredefinedSnoozingOption(index).action();
expect(snoozeTodoMutationSuccessHandler).toHaveBeenCalledWith({
snoozeUntil: new Date(expectedDate),
todoId: mockTodo.id,
});
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_todo_item_action', {
label: expectedTrackingLabel,
});
unmockTracking();
},
);
it('shows an error when the to snooze mutation returns some errors', async () => {
createComponent({
props: { isSnoozed: false, isPending: true },
snoozeTodoMutationHandler: jest.fn().mockResolvedValue({
data: {
todoSnooze: {
todo: { ...mockTodo },
errors: ['Could not snooze todo-item.'],
},
},
}),
});
getPredefinedSnoozingOption(0).action();
await waitForPromises();
expect(mockToastShow).toHaveBeenCalledWith('Failed to snooze todo. Try again later.', {
variant: 'danger',
});
});
it('shows an error when it fails to snooze the to-do item', async () => {
createComponent({
props: { isSnoozed: false, isPending: true },
snoozeTodoMutationHandler: jest.fn().mockRejectedValue(),
});
getPredefinedSnoozingOption(0).action();
await waitForPromises();
expect(mockToastShow).toHaveBeenCalledWith('Failed to snooze todo. Try again later.', {
variant: 'danger',
});
});
it('attaches a tooltip to the dropdown toggle', () => {
createComponent({ props: { isSnoozed: false, isPending: true } });
const tooltip = findGlTooltip();
expect(tooltip.exists()).toBe(true);
expect(tooltip.text()).toBe('Snooze');
});
it('only shows the tooltip when the dropdown is closed', async () => {
createComponent({ props: { isSnoozed: false, isPending: true } });
findSnoozeDropdown().vm.$emit('shown');
await nextTick();
expect(findGlTooltip().exists()).toBe(false);
findSnoozeDropdown().vm.$emit('hidden');
await nextTick();
expect(findGlTooltip().exists()).toBe(true);
});
describe('un-snooze button', () => {
it('renders if the to-do item is snoozed', () => {
createComponent({ props: { isSnoozed: true, isPending: true } });
expect(findUnSnoozeButton().exists()).toBe(true);
});
it('has the correct attributes', () => {
createComponent({ props: { isSnoozed: true, isPending: true } });
expect(findUnSnoozeButton().attributes()).toMatchObject({
icon: 'time-out',
title: 'Remove snooze',
'aria-label': 'Remove snooze',
});
});
it('triggers the un-snooze mutation', () => {
createComponent({ props: { isSnoozed: true, isPending: true } });
findUnSnoozeButton().vm.$emit('click');
expect(unSnoozeTodoMutationSuccessHandler).toHaveBeenCalledWith({
todoId: mockTodo.id,
});
});
it('shows an error when the to un-snooze mutation returns some errors', async () => {
createComponent({
props: { isSnoozed: true, isPending: true },
unSnoozeTodoMutationHandler: jest.fn().mockResolvedValue({
data: {
todoUnSnooze: {
todo: { ...mockTodo },
errors: ['Could not un-snooze todo-item.'],
},
},
}),
});
findUnSnoozeButton().vm.$emit('click');
await waitForPromises();
expect(mockToastShow).toHaveBeenCalledWith('Failed to un-snooze todo. Try again later.', {
variant: 'danger',
});
});
it('shows an error when it fails to un-snooze the to-do item', async () => {
createComponent({
props: { isSnoozed: true, isPending: true },
unSnoozeTodoMutationHandler: jest.fn().mockRejectedValue(),
});
const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
findUnSnoozeButton().vm.$emit('click');
await waitForPromises();
expect(mockToastShow).toHaveBeenCalledWith('Failed to un-snooze todo. Try again later.', {
variant: 'danger',
});
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_todo_item_action', {
label: 'remove_snooze',
});
unmockTracking();
});
it('has a tooltip attached', () => {
createComponent({ props: { isSnoozed: true, isPending: true } });
const tooltip = getBinding(findUnSnoozeButton().element, 'gl-tooltip');
expect(tooltip).toBeDefined();
});
});
});