summaryrefslogtreecommitdiff
path: root/spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js')
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js353
1 files changed, 236 insertions, 117 deletions
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js
index ec047fe0714..9bd46267daa 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js
@@ -1,54 +1,101 @@
-import { mount } from '@vue/test-utils';
-import { nextTick } from 'vue';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import { GlModal } from '@gitlab/ui';
+import BoldText from '~/vue_merge_request_widget/components/bold_text.vue';
import WidgetRebase from '~/vue_merge_request_widget/components/states/mr_widget_rebase.vue';
+import rebaseQuery from '~/vue_merge_request_widget/queries/states/rebase.query.graphql';
import eventHub from '~/vue_merge_request_widget/event_hub';
+import StateContainer from '~/vue_merge_request_widget/components/state_container.vue';
import toast from '~/vue_shared/plugins/global_toast';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { stubComponent } from 'helpers/stub_component';
jest.mock('~/vue_shared/plugins/global_toast');
let wrapper;
-
-function createWrapper(propsData) {
- wrapper = mount(WidgetRebase, {
- propsData,
- data() {
- return {
- state: {
- rebaseInProgress: propsData.mr.rebaseInProgress,
- targetBranch: propsData.mr.targetBranch,
+const showMock = jest.fn();
+
+const mockPipelineNodes = [
+ {
+ id: '1',
+ project: {
+ id: '2',
+ fullPath: 'user/forked',
+ },
+ },
+];
+
+const mockQueryHandler = ({
+ rebaseInProgress = false,
+ targetBranch = '',
+ pushToSourceBranch = false,
+ nodes = mockPipelineNodes,
+} = {}) =>
+ jest.fn().mockResolvedValue({
+ data: {
+ project: {
+ id: '1',
+ mergeRequest: {
+ id: '2',
+ rebaseInProgress,
+ targetBranch,
userPermissions: {
- pushToSourceBranch: propsData.mr.canPushToSourceBranch,
+ pushToSourceBranch,
+ },
+ pipelines: {
+ nodes,
},
},
- };
+ },
+ },
+ });
+
+const createMockApolloProvider = (handler) => {
+ Vue.use(VueApollo);
+
+ return createMockApollo([[rebaseQuery, handler]]);
+};
+
+function createWrapper({ propsData = {}, provideData = {}, handler = mockQueryHandler() } = {}) {
+ wrapper = shallowMountExtended(WidgetRebase, {
+ apolloProvider: createMockApolloProvider(handler),
+ provide: {
+ ...provideData,
+ },
+ propsData: {
+ mr: {},
+ service: {},
+ ...propsData,
},
- mocks: {
- $apollo: {
- queries: {
- state: { loading: false },
+ stubs: {
+ StateContainer,
+ GlModal: stubComponent(GlModal, {
+ methods: {
+ show: showMock,
},
- },
+ }),
},
});
}
describe('Merge request widget rebase component', () => {
- const findRebaseMessage = () => wrapper.find('[data-testid="rebase-message"]');
+ const findRebaseMessage = () => wrapper.findByTestId('rebase-message');
+ const findBoldText = () => wrapper.findComponent(BoldText);
const findRebaseMessageText = () => findRebaseMessage().text();
- const findStandardRebaseButton = () => wrapper.find('[data-testid="standard-rebase-button"]');
- const findRebaseWithoutCiButton = () => wrapper.find('[data-testid="rebase-without-ci-button"]');
+ const findStandardRebaseButton = () => wrapper.findByTestId('standard-rebase-button');
+ const findRebaseWithoutCiButton = () => wrapper.findByTestId('rebase-without-ci-button');
+ const findModal = () => wrapper.findComponent(GlModal);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
describe('while rebasing', () => {
- it('should show progress message', () => {
+ it('should show progress message', async () => {
createWrapper({
- mr: { rebaseInProgress: true },
- service: {},
+ handler: mockQueryHandler({ rebaseInProgress: true }),
});
+ await waitForPromises();
+
expect(findRebaseMessageText()).toContain('Rebase in progress');
});
});
@@ -57,95 +104,110 @@ describe('Merge request widget rebase component', () => {
const rebaseMock = jest.fn().mockResolvedValue();
const pollMock = jest.fn().mockResolvedValue({});
- it('renders the warning message', () => {
+ it('renders the warning message', async () => {
createWrapper({
- mr: {
+ handler: mockQueryHandler({
rebaseInProgress: false,
- canPushToSourceBranch: true,
- },
- service: {
- rebase: rebaseMock,
- poll: pollMock,
- },
+ pushToSourceBranch: false,
+ }),
});
- const text = findRebaseMessageText();
+ await waitForPromises();
- expect(text).toContain('Merge blocked');
- expect(text.replace(/\s\s+/g, ' ')).toContain(
+ expect(findBoldText().props('message')).toContain('Merge blocked');
+ expect(findBoldText().props('message').replace(/\s\s+/g, ' ')).toContain(
'the source branch must be rebased onto the target branch',
);
});
it('renders an error message when rebasing has failed', async () => {
createWrapper({
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
- },
- service: {
- rebase: rebaseMock,
- poll: pollMock,
+ propsData: {
+ service: {
+ rebase: jest.fn().mockRejectedValue({
+ response: {
+ data: {
+ merge_error: 'Something went wrong!',
+ },
+ },
+ }),
+ },
},
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
});
+ await waitForPromises();
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ rebasingError: 'Something went wrong!' });
+ findStandardRebaseButton().vm.$emit('click');
- await nextTick();
+ await waitForPromises();
expect(findRebaseMessageText()).toContain('Something went wrong!');
});
describe('Rebase buttons', () => {
- beforeEach(() => {
+ it('renders both buttons', async () => {
createWrapper({
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
- },
- service: {
- rebase: rebaseMock,
- poll: pollMock,
- },
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
});
- });
- it('renders both buttons', () => {
+ await waitForPromises();
+
expect(findRebaseWithoutCiButton().exists()).toBe(true);
expect(findStandardRebaseButton().exists()).toBe(true);
});
it('starts the rebase when clicking', async () => {
- findStandardRebaseButton().vm.$emit('click');
+ createWrapper({
+ propsData: {
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
+ },
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
+ });
- await nextTick();
+ await waitForPromises();
+
+ findStandardRebaseButton().vm.$emit('click');
expect(rebaseMock).toHaveBeenCalledWith({ skipCi: false });
});
it('starts the CI-skipping rebase when clicking on "Rebase without CI"', async () => {
- findRebaseWithoutCiButton().vm.$emit('click');
+ createWrapper({
+ propsData: {
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
+ },
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
+ });
- await nextTick();
+ await waitForPromises();
+
+ findRebaseWithoutCiButton().vm.$emit('click');
expect(rebaseMock).toHaveBeenCalledWith({ skipCi: true });
});
});
describe('Rebase when pipelines must succeed is enabled', () => {
- beforeEach(() => {
+ beforeEach(async () => {
createWrapper({
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
- onlyAllowMergeIfPipelineSucceeds: true,
- },
- service: {
- rebase: rebaseMock,
- poll: pollMock,
+ propsData: {
+ mr: {
+ onlyAllowMergeIfPipelineSucceeds: true,
+ },
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
},
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
});
+
+ await waitForPromises();
});
it('renders only the rebase button', () => {
@@ -163,19 +225,22 @@ describe('Merge request widget rebase component', () => {
});
describe('Rebase when pipelines must succeed and skipped pipelines are considered successful are enabled', () => {
- beforeEach(() => {
+ beforeEach(async () => {
createWrapper({
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
- onlyAllowMergeIfPipelineSucceeds: true,
- allowMergeOnSkippedPipeline: true,
- },
- service: {
- rebase: rebaseMock,
- poll: pollMock,
+ propsData: {
+ mr: {
+ onlyAllowMergeIfPipelineSucceeds: true,
+ allowMergeOnSkippedPipeline: true,
+ },
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
},
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
});
+
+ await waitForPromises();
});
it('renders both rebase buttons', () => {
@@ -199,48 +264,99 @@ describe('Merge request widget rebase component', () => {
expect(rebaseMock).toHaveBeenCalledWith({ skipCi: true });
});
});
+
+ describe('security modal', () => {
+ it('displays modal and rebases after confirming', async () => {
+ createWrapper({
+ propsData: {
+ mr: {
+ sourceProjectFullPath: 'user/forked',
+ targetProjectFullPath: 'root/original',
+ },
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
+ },
+ provideData: { canCreatePipelineInTargetProject: true },
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
+ });
+
+ await waitForPromises();
+
+ findStandardRebaseButton().vm.$emit('click');
+ expect(showMock).toHaveBeenCalled();
+
+ findModal().vm.$emit('primary');
+
+ expect(rebaseMock).toHaveBeenCalled();
+ });
+
+ it('does not display modal', async () => {
+ createWrapper({
+ propsData: {
+ mr: {
+ sourceProjectFullPath: 'user/forked',
+ targetProjectFullPath: 'root/original',
+ },
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
+ },
+ provideData: { canCreatePipelineInTargetProject: false },
+ handler: mockQueryHandler({ pushToSourceBranch: true }),
+ });
+
+ await waitForPromises();
+
+ findStandardRebaseButton().vm.$emit('click');
+
+ expect(showMock).not.toHaveBeenCalled();
+ expect(rebaseMock).toHaveBeenCalled();
+ });
+ });
});
describe('without permissions', () => {
const exampleTargetBranch = 'fake-branch-to-test-with';
describe('UI text', () => {
- beforeEach(() => {
+ beforeEach(async () => {
createWrapper({
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: false,
+ handler: mockQueryHandler({
+ pushToSourceBranch: false,
targetBranch: exampleTargetBranch,
- },
- service: {},
+ }),
});
+
+ await waitForPromises();
});
it('renders a message explaining user does not have permissions', () => {
- const text = findRebaseMessageText();
-
- expect(text).toContain('Merge blocked:');
- expect(text).toContain('the source branch must be rebased');
+ expect(findBoldText().props('message')).toContain('Merge blocked');
+ expect(findBoldText().props('message')).toContain('the source branch must be rebased');
});
it('renders the correct target branch name', () => {
- const text = findRebaseMessageText();
-
- expect(text).toContain('Merge blocked:');
- expect(text).toContain('the source branch must be rebased onto the target branch.');
+ expect(findBoldText().props('message')).toContain('Merge blocked:');
+ expect(findBoldText().props('message')).toContain(
+ 'the source branch must be rebased onto the target branch.',
+ );
});
});
- it('does render the "Rebase without pipeline" button', () => {
+ it('does render the "Rebase without pipeline" button', async () => {
createWrapper({
- mr: {
+ handler: mockQueryHandler({
rebaseInProgress: false,
- canPushToSourceBranch: false,
+ pushToSourceBranch: false,
targetBranch: exampleTargetBranch,
- },
- service: {},
+ }),
});
+ await waitForPromises();
+
expect(findRebaseWithoutCiButton().exists()).toBe(true);
});
});
@@ -249,24 +365,27 @@ describe('Merge request widget rebase component', () => {
it('checkRebaseStatus', async () => {
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
createWrapper({
- mr: {},
- service: {
- rebase() {
- return Promise.resolve();
- },
- poll() {
- return Promise.resolve({
- data: {
- rebase_in_progress: false,
- should_be_rebased: false,
- merge_error: null,
- },
- });
+ propsData: {
+ service: {
+ rebase() {
+ return Promise.resolve();
+ },
+ poll() {
+ return Promise.resolve({
+ data: {
+ rebase_in_progress: false,
+ should_be_rebased: false,
+ merge_error: null,
+ },
+ });
+ },
},
},
});
- wrapper.vm.rebase();
+ await waitForPromises();
+
+ findRebaseWithoutCiButton().vm.$emit('click');
// Wait for the rebase request
await nextTick();