2022-06-27 15:09:33 +00:00
|
|
|
import { nextTick } from 'vue';
|
|
|
|
import { GlButton, GlSprintf } from '@gitlab/ui';
|
|
|
|
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
|
|
|
import { mockTracking } from 'helpers/tracking_helper';
|
|
|
|
import { makeMockUserCalloutDismisser } from 'helpers/mock_user_callout_dismisser';
|
|
|
|
import MergeRequestExperienceSurveyApp from '~/surveys/merge_request_experience/app.vue';
|
|
|
|
import SatisfactionRate from '~/surveys/components/satisfaction_rate.vue';
|
|
|
|
|
2022-08-31 12:13:01 +00:00
|
|
|
const createRenderTrackedArguments = () => [
|
|
|
|
undefined,
|
|
|
|
'survey:mr_experience',
|
|
|
|
{
|
|
|
|
label: 'render',
|
|
|
|
extra: {
|
|
|
|
accountAge: 0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
2022-06-27 15:09:33 +00:00
|
|
|
describe('MergeRequestExperienceSurveyApp', () => {
|
|
|
|
let trackingSpy;
|
|
|
|
let wrapper;
|
|
|
|
let dismiss;
|
|
|
|
let dismisserComponent;
|
|
|
|
|
|
|
|
const findCloseButton = () =>
|
|
|
|
wrapper
|
|
|
|
.findAllComponents(GlButton)
|
|
|
|
.filter((button) => button.attributes('aria-label') === 'Close')
|
|
|
|
.at(0);
|
|
|
|
|
|
|
|
const createWrapper = ({ shouldShowCallout = true } = {}) => {
|
|
|
|
dismiss = jest.fn();
|
|
|
|
dismisserComponent = makeMockUserCalloutDismisser({
|
|
|
|
dismiss,
|
|
|
|
shouldShowCallout,
|
|
|
|
});
|
2022-08-31 12:13:01 +00:00
|
|
|
trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
|
2022-06-27 15:09:33 +00:00
|
|
|
wrapper = shallowMountExtended(MergeRequestExperienceSurveyApp, {
|
2022-07-26 12:10:14 +00:00
|
|
|
propsData: {
|
|
|
|
accountAge: 0,
|
|
|
|
},
|
2022-06-27 15:09:33 +00:00
|
|
|
stubs: {
|
|
|
|
UserCalloutDismisser: dismisserComponent,
|
|
|
|
GlSprintf,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2022-08-31 12:13:01 +00:00
|
|
|
beforeEach(() => {
|
|
|
|
localStorage.clear();
|
|
|
|
});
|
|
|
|
|
2022-06-27 15:09:33 +00:00
|
|
|
describe('when user callout is visible', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
createWrapper();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('shows survey', async () => {
|
|
|
|
expect(wrapper.html()).toContain('Overall, how satisfied are you with merge requests?');
|
|
|
|
expect(wrapper.findComponent(SatisfactionRate).exists()).toBe(true);
|
|
|
|
expect(wrapper.emitted().close).toBe(undefined);
|
|
|
|
});
|
|
|
|
|
2022-08-31 12:13:01 +00:00
|
|
|
it('tracks render once', async () => {
|
|
|
|
expect(trackingSpy).toHaveBeenCalledWith(...createRenderTrackedArguments());
|
|
|
|
});
|
|
|
|
|
|
|
|
it("doesn't track subsequent renders", async () => {
|
|
|
|
createWrapper();
|
|
|
|
expect(trackingSpy).toHaveBeenCalledWith(...createRenderTrackedArguments());
|
|
|
|
expect(trackingSpy).toHaveBeenCalledTimes(1);
|
|
|
|
});
|
|
|
|
|
2022-08-25 12:12:20 +00:00
|
|
|
describe('when close button clicked', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
findCloseButton().vm.$emit('click');
|
|
|
|
});
|
2022-06-27 15:09:33 +00:00
|
|
|
|
2022-08-25 12:12:20 +00:00
|
|
|
it('triggers user callout on close', async () => {
|
|
|
|
expect(dismiss).toHaveBeenCalledTimes(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('emits close event on close button click', async () => {
|
|
|
|
expect(wrapper.emitted()).toMatchObject({ close: [[]] });
|
|
|
|
});
|
|
|
|
|
|
|
|
it('tracks dismissal', async () => {
|
|
|
|
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'survey:mr_experience', {
|
|
|
|
label: 'dismiss',
|
|
|
|
extra: {
|
|
|
|
accountAge: 0,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
2022-08-31 12:13:01 +00:00
|
|
|
|
|
|
|
it('tracks subsequent renders', async () => {
|
|
|
|
createWrapper();
|
|
|
|
expect(trackingSpy.mock.calls).toEqual([
|
|
|
|
createRenderTrackedArguments(),
|
|
|
|
expect.anything(),
|
|
|
|
createRenderTrackedArguments(),
|
|
|
|
]);
|
|
|
|
});
|
2022-06-27 15:09:33 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('applies correct feature name for user callout', () => {
|
|
|
|
expect(wrapper.findComponent(dismisserComponent).props('featureName')).toBe(
|
|
|
|
'mr_experience_survey',
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('dismisses user callout on survey rate', async () => {
|
|
|
|
const rate = wrapper.findComponent(SatisfactionRate);
|
|
|
|
expect(dismiss).not.toHaveBeenCalled();
|
|
|
|
rate.vm.$emit('rate', 5);
|
|
|
|
expect(dismiss).toHaveBeenCalledTimes(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('steps through survey steps', async () => {
|
|
|
|
const rate = wrapper.findComponent(SatisfactionRate);
|
|
|
|
rate.vm.$emit('rate', 5);
|
|
|
|
await nextTick();
|
|
|
|
expect(wrapper.text()).toContain(
|
|
|
|
'How satisfied are you with speed/performance of merge requests?',
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('tracks survey rates', async () => {
|
|
|
|
const rate = wrapper.findComponent(SatisfactionRate);
|
|
|
|
rate.vm.$emit('rate', 5);
|
|
|
|
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'survey:mr_experience', {
|
|
|
|
value: 5,
|
|
|
|
label: 'overall',
|
2022-07-26 12:10:14 +00:00
|
|
|
extra: {
|
|
|
|
accountAge: 0,
|
|
|
|
},
|
2022-06-27 15:09:33 +00:00
|
|
|
});
|
|
|
|
rate.vm.$emit('rate', 4);
|
|
|
|
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'survey:mr_experience', {
|
|
|
|
value: 4,
|
|
|
|
label: 'performance',
|
2022-07-26 12:10:14 +00:00
|
|
|
extra: {
|
|
|
|
accountAge: 0,
|
|
|
|
},
|
2022-06-27 15:09:33 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('shows legal note', async () => {
|
|
|
|
expect(wrapper.text()).toContain(
|
|
|
|
'By continuing, you acknowledge that responses will be used to improve GitLab and in accordance with the GitLab Privacy Policy.',
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('hides legal note after first step', async () => {
|
|
|
|
const rate = wrapper.findComponent(SatisfactionRate);
|
|
|
|
rate.vm.$emit('rate', 5);
|
|
|
|
await nextTick();
|
|
|
|
expect(wrapper.text()).not.toContain(
|
|
|
|
'By continuing, you acknowledge that responses will be used to improve GitLab and in accordance with the GitLab Privacy Policy.',
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('shows disappearing thanks message', async () => {
|
|
|
|
const rate = wrapper.findComponent(SatisfactionRate);
|
|
|
|
rate.vm.$emit('rate', 5);
|
|
|
|
await nextTick();
|
|
|
|
rate.vm.$emit('rate', 5);
|
|
|
|
await nextTick();
|
|
|
|
expect(wrapper.text()).toContain('Thank you for your feedback!');
|
|
|
|
expect(wrapper.emitted()).toMatchObject({});
|
|
|
|
jest.runOnlyPendingTimers();
|
|
|
|
expect(wrapper.emitted()).toMatchObject({ close: [[]] });
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('when user callout is hidden', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
createWrapper({ shouldShowCallout: false });
|
|
|
|
});
|
|
|
|
|
|
|
|
it('emits close event', async () => {
|
|
|
|
expect(wrapper.emitted()).toMatchObject({ close: [[]] });
|
|
|
|
});
|
2022-08-31 12:13:01 +00:00
|
|
|
|
|
|
|
it("doesn't track anything", async () => {
|
|
|
|
expect(trackingSpy).toHaveBeenCalledTimes(0);
|
|
|
|
});
|
2022-06-27 15:09:33 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
describe('when Escape key is pressed', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
createWrapper();
|
|
|
|
const event = new KeyboardEvent('keyup', { key: 'Escape' });
|
|
|
|
document.dispatchEvent(event);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('emits close event', async () => {
|
|
|
|
expect(wrapper.emitted()).toMatchObject({ close: [[]] });
|
|
|
|
expect(dismiss).toHaveBeenCalledTimes(1);
|
|
|
|
});
|
2022-08-25 12:12:20 +00:00
|
|
|
|
|
|
|
it('tracks dismissal', async () => {
|
|
|
|
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'survey:mr_experience', {
|
|
|
|
label: 'dismiss',
|
|
|
|
extra: {
|
|
|
|
accountAge: 0,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
2022-06-27 15:09:33 +00:00
|
|
|
});
|
|
|
|
});
|