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:
Diffstat (limited to 'spec/frontend/jira_connect/subscriptions')
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/groups_list_item_spec.js116
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/app_spec.js67
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/sign_in_oauth_button_spec.js35
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/subscriptions_list_spec.js7
-rw-r--r--spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_com_spec.js (renamed from spec/frontend/jira_connect/subscriptions/pages/sign_in_spec.js)8
-rw-r--r--spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index_spec.js83
-rw-r--r--spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form_spec.js69
-rw-r--r--spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_page_spec.js82
-rw-r--r--spec/frontend/jira_connect/subscriptions/pages/subscriptions_page_spec.js71
-rw-r--r--spec/frontend/jira_connect/subscriptions/pages/subscriptions_spec.js56
-rw-r--r--spec/frontend/jira_connect/subscriptions/store/actions_spec.js172
-rw-r--r--spec/frontend/jira_connect/subscriptions/store/mutations_spec.js67
12 files changed, 683 insertions, 150 deletions
diff --git a/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/groups_list_item_spec.js b/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/groups_list_item_spec.js
index 3d7bf7acb41..5df54abfc05 100644
--- a/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/groups_list_item_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/components/add_namespace_modal/groups_list_item_spec.js
@@ -7,21 +7,35 @@ import * as JiraConnectApi from '~/jira_connect/subscriptions/api';
import GroupItemName from '~/jira_connect/subscriptions/components/group_item_name.vue';
import GroupsListItem from '~/jira_connect/subscriptions/components/add_namespace_modal/groups_list_item.vue';
import { persistAlert, reloadPage } from '~/jira_connect/subscriptions/utils';
+import {
+ I18N_ADD_SUBSCRIPTION_SUCCESS_ALERT_TITLE,
+ I18N_ADD_SUBSCRIPTION_SUCCESS_ALERT_MESSAGE,
+ INTEGRATIONS_DOC_LINK,
+} from '~/jira_connect/subscriptions/constants';
+import createStore from '~/jira_connect/subscriptions/store';
import { mockGroup1 } from '../../mock_data';
jest.mock('~/jira_connect/subscriptions/utils');
describe('GroupsListItem', () => {
let wrapper;
- const mockSubscriptionPath = 'subscriptionPath';
+ let store;
+
+ const mockAddSubscriptionsPath = '/addSubscriptionsPath';
+
+ const createComponent = ({ mountFn = shallowMount, provide } = {}) => {
+ store = createStore();
+
+ jest.spyOn(store, 'dispatch').mockImplementation();
- const createComponent = ({ mountFn = shallowMount } = {}) => {
wrapper = mountFn(GroupsListItem, {
+ store,
propsData: {
group: mockGroup1,
},
provide: {
- subscriptionsPath: mockSubscriptionPath,
+ addSubscriptionsPath: mockAddSubscriptionsPath,
+ ...provide,
},
});
};
@@ -51,62 +65,88 @@ describe('GroupsListItem', () => {
});
describe('on Link button click', () => {
- let addSubscriptionSpy;
+ describe('when jiraConnectOauth feature flag is disabled', () => {
+ let addSubscriptionSpy;
- beforeEach(() => {
- createComponent({ mountFn: mount });
+ beforeEach(() => {
+ createComponent({ mountFn: mount });
- addSubscriptionSpy = jest.spyOn(JiraConnectApi, 'addSubscription').mockResolvedValue();
- });
+ addSubscriptionSpy = jest.spyOn(JiraConnectApi, 'addSubscription').mockResolvedValue();
+ });
- it('sets button to loading and sends request', async () => {
- expect(findLinkButton().props('loading')).toBe(false);
+ it('sets button to loading and sends request', async () => {
+ expect(findLinkButton().props('loading')).toBe(false);
+
+ clickLinkButton();
+ await nextTick();
- clickLinkButton();
+ expect(findLinkButton().props('loading')).toBe(true);
+ await waitForPromises();
- await nextTick();
+ expect(addSubscriptionSpy).toHaveBeenCalledWith(
+ mockAddSubscriptionsPath,
+ mockGroup1.full_path,
+ );
+ expect(persistAlert).toHaveBeenCalledWith({
+ linkUrl: INTEGRATIONS_DOC_LINK,
+ message: I18N_ADD_SUBSCRIPTION_SUCCESS_ALERT_MESSAGE,
+ title: I18N_ADD_SUBSCRIPTION_SUCCESS_ALERT_TITLE,
+ variant: 'success',
+ });
+ });
- expect(findLinkButton().props('loading')).toBe(true);
+ describe('when request is successful', () => {
+ it('reloads the page', async () => {
+ clickLinkButton();
- await waitForPromises();
+ await waitForPromises();
- expect(addSubscriptionSpy).toHaveBeenCalledWith(mockSubscriptionPath, mockGroup1.full_path);
- expect(persistAlert).toHaveBeenCalledWith({
- linkUrl: '/help/integration/jira_development_panel.html#use-the-integration',
- message:
- 'You should now see GitLab.com activity inside your Jira Cloud issues. %{linkStart}Learn more%{linkEnd}',
- title: 'Namespace successfully linked',
- variant: 'success',
+ expect(reloadPage).toHaveBeenCalled();
+ });
});
- });
- describe('when request is successful', () => {
- it('reloads the page', async () => {
- clickLinkButton();
+ describe('when request has errors', () => {
+ const mockErrorMessage = 'error message';
+ const mockError = { response: { data: { error: mockErrorMessage } } };
- await waitForPromises();
+ beforeEach(() => {
+ addSubscriptionSpy = jest
+ .spyOn(JiraConnectApi, 'addSubscription')
+ .mockRejectedValue(mockError);
+ });
- expect(reloadPage).toHaveBeenCalled();
+ it('emits `error` event', async () => {
+ clickLinkButton();
+
+ await waitForPromises();
+
+ expect(reloadPage).not.toHaveBeenCalled();
+ expect(wrapper.emitted('error')[0][0]).toBe(mockErrorMessage);
+ });
});
});
- describe('when request has errors', () => {
- const mockErrorMessage = 'error message';
- const mockError = { response: { data: { error: mockErrorMessage } } };
+ describe('when jiraConnectOauth feature flag is enabled', () => {
+ const mockSubscriptionsPath = '/subscriptions';
beforeEach(() => {
- addSubscriptionSpy = jest
- .spyOn(JiraConnectApi, 'addSubscription')
- .mockRejectedValue(mockError);
+ createComponent({
+ mountFn: mount,
+ provide: {
+ subscriptionsPath: mockSubscriptionsPath,
+ glFeatures: { jiraConnectOauth: true },
+ },
+ });
});
- it('emits `error` event', async () => {
+ it('dispatches `addSubscription` action', async () => {
clickLinkButton();
+ await nextTick();
- await waitForPromises();
-
- expect(reloadPage).not.toHaveBeenCalled();
- expect(wrapper.emitted('error')[0][0]).toBe(mockErrorMessage);
+ expect(store.dispatch).toHaveBeenCalledWith('addSubscription', {
+ namespacePath: mockGroup1.full_path,
+ subscriptionsPath: mockSubscriptionsPath,
+ });
});
});
});
diff --git a/spec/frontend/jira_connect/subscriptions/components/app_spec.js b/spec/frontend/jira_connect/subscriptions/components/app_spec.js
index ce02144f22f..9894141be5a 100644
--- a/spec/frontend/jira_connect/subscriptions/components/app_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/components/app_spec.js
@@ -3,8 +3,8 @@ import { nextTick } from 'vue';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import JiraConnectApp from '~/jira_connect/subscriptions/components/app.vue';
-import SignInPage from '~/jira_connect/subscriptions/pages/sign_in.vue';
-import SubscriptionsPage from '~/jira_connect/subscriptions/pages/subscriptions.vue';
+import SignInPage from '~/jira_connect/subscriptions/pages/sign_in/sign_in_page.vue';
+import SubscriptionsPage from '~/jira_connect/subscriptions/pages/subscriptions_page.vue';
import UserLink from '~/jira_connect/subscriptions/components/user_link.vue';
import BrowserSupportAlert from '~/jira_connect/subscriptions/components/browser_support_alert.vue';
import createStore from '~/jira_connect/subscriptions/store';
@@ -12,6 +12,7 @@ import { SET_ALERT } from '~/jira_connect/subscriptions/store/mutation_types';
import { I18N_DEFAULT_SIGN_IN_ERROR_MESSAGE } from '~/jira_connect/subscriptions/constants';
import { __ } from '~/locale';
import AccessorUtilities from '~/lib/utils/accessor';
+import * as api from '~/jira_connect/subscriptions/api';
import { mockSubscription } from '../mock_data';
jest.mock('~/jira_connect/subscriptions/utils', () => ({
@@ -31,7 +32,8 @@ describe('JiraConnectApp', () => {
const findBrowserSupportAlert = () => wrapper.findComponent(BrowserSupportAlert);
const createComponent = ({ provide, mountFn = shallowMountExtended } = {}) => {
- store = createStore();
+ store = createStore({ subscriptions: [mockSubscription] });
+ jest.spyOn(store, 'dispatch').mockImplementation();
wrapper = mountFn(JiraConnectApp, {
store,
@@ -53,7 +55,6 @@ describe('JiraConnectApp', () => {
createComponent({
provide: {
usersPath,
- subscriptions: [mockSubscription],
},
});
});
@@ -79,14 +80,13 @@ describe('JiraConnectApp', () => {
createComponent({
provide: {
usersPath: '/user',
- subscriptions: [],
},
});
const userLink = findUserLink();
expect(userLink.exists()).toBe(true);
expect(userLink.props()).toEqual({
- hasSubscriptions: false,
+ hasSubscriptions: true,
user: null,
userSignedIn: false,
});
@@ -161,39 +161,11 @@ describe('JiraConnectApp', () => {
});
describe('when user signed out', () => {
- describe('when sign in page emits `sign-in-oauth` event', () => {
- const mockUser = { name: 'test' };
- beforeEach(async () => {
- createComponent({
- provide: {
- usersPath: '/mock',
- subscriptions: [],
- },
- });
- findSignInPage().vm.$emit('sign-in-oauth', mockUser);
-
- await nextTick();
- });
-
- it('hides sign in page and renders subscriptions page', () => {
- expect(findSignInPage().exists()).toBe(false);
- expect(findSubscriptionsPage().exists()).toBe(true);
- });
-
- it('sets correct UserLink props', () => {
- expect(findUserLink().props()).toMatchObject({
- user: mockUser,
- userSignedIn: true,
- });
- });
- });
-
describe('when sign in page emits `error` event', () => {
beforeEach(async () => {
createComponent({
provide: {
usersPath: '/mock',
- subscriptions: [],
},
});
findSignInPage().vm.$emit('error');
@@ -235,4 +207,31 @@ describe('JiraConnectApp', () => {
});
},
);
+
+ describe('when `jiraConnectOauth` feature flag is enabled', () => {
+ const mockSubscriptionsPath = '/mockSubscriptionsPath';
+
+ beforeEach(() => {
+ jest.spyOn(api, 'fetchSubscriptions').mockResolvedValue({ data: { subscriptions: [] } });
+
+ createComponent({
+ provide: {
+ glFeatures: { jiraConnectOauth: true },
+ subscriptionsPath: mockSubscriptionsPath,
+ },
+ });
+ });
+
+ describe('when component mounts', () => {
+ it('dispatches `fetchSubscriptions` action', async () => {
+ expect(store.dispatch).toHaveBeenCalledWith('fetchSubscriptions', mockSubscriptionsPath);
+ });
+ });
+
+ describe('when oauth button emits `sign-in-oauth` event', () => {
+ it('dispatches `fetchSubscriptions` action', () => {
+ expect(store.dispatch).toHaveBeenCalledWith('fetchSubscriptions', mockSubscriptionsPath);
+ });
+ });
+ });
});
diff --git a/spec/frontend/jira_connect/subscriptions/components/sign_in_oauth_button_spec.js b/spec/frontend/jira_connect/subscriptions/components/sign_in_oauth_button_spec.js
index 18274cd4362..8730e124ae7 100644
--- a/spec/frontend/jira_connect/subscriptions/components/sign_in_oauth_button_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/components/sign_in_oauth_button_spec.js
@@ -11,9 +11,14 @@ import axios from '~/lib/utils/axios_utils';
import waitForPromises from 'helpers/wait_for_promises';
import httpStatus from '~/lib/utils/http_status';
import AccessorUtilities from '~/lib/utils/accessor';
+import { getCurrentUser } from '~/rest_api';
+import createStore from '~/jira_connect/subscriptions/store';
+import { SET_ACCESS_TOKEN } from '~/jira_connect/subscriptions/store/mutation_types';
jest.mock('~/lib/utils/accessor');
jest.mock('~/jira_connect/subscriptions/utils');
+jest.mock('~/jira_connect/subscriptions/api');
+jest.mock('~/rest_api');
jest.mock('~/jira_connect/subscriptions/pkce', () => ({
createCodeVerifier: jest.fn().mockReturnValue('mock-verifier'),
createCodeChallenge: jest.fn().mockResolvedValue('mock-challenge'),
@@ -28,9 +33,15 @@ const mockOauthMetadata = {
describe('SignInOauthButton', () => {
let wrapper;
let mockAxios;
+ let store;
const createComponent = ({ slots } = {}) => {
+ store = createStore();
+ jest.spyOn(store, 'dispatch').mockImplementation();
+ jest.spyOn(store, 'commit').mockImplementation();
+
wrapper = shallowMount(SignInOauthButton, {
+ store,
slots,
provide: {
oauthMetadata: mockOauthMetadata,
@@ -114,10 +125,6 @@ describe('SignInOauthButton', () => {
await waitForPromises();
});
- it('emits `error` event', () => {
- expect(wrapper.emitted('error')).toBeTruthy();
- });
-
it('does not emit `sign-in` event', () => {
expect(wrapper.emitted('sign-in')).toBeFalsy();
});
@@ -147,7 +154,7 @@ describe('SignInOauthButton', () => {
mockAxios
.onPost(mockOauthMetadata.oauth_token_url)
.replyOnce(httpStatus.OK, { access_token: mockAccessToken });
- mockAxios.onGet('/api/v4/user').replyOnce(httpStatus.OK, mockUser);
+ getCurrentUser.mockResolvedValue({ data: mockUser });
window.dispatchEvent(new MessageEvent('message', mockEvent));
@@ -161,25 +168,25 @@ describe('SignInOauthButton', () => {
});
});
- it('executes GET request to fetch user data', () => {
- expect(axios.get).toHaveBeenCalledWith('/api/v4/user', {
- headers: { Authorization: `Bearer ${mockAccessToken}` },
- });
+ it('dispatches loadCurrentUser action', () => {
+ expect(store.dispatch).toHaveBeenCalledWith('loadCurrentUser', mockAccessToken);
+ });
+
+ it('commits SET_ACCESS_TOKEN mutation with correct access token', () => {
+ expect(store.commit).toHaveBeenCalledWith(SET_ACCESS_TOKEN, mockAccessToken);
});
it('emits `sign-in` event with user data', () => {
- expect(wrapper.emitted('sign-in')[0]).toEqual([mockUser]);
+ expect(wrapper.emitted('sign-in')[0]).toBeTruthy();
});
});
describe('when API requests fail', () => {
beforeEach(async () => {
jest.spyOn(axios, 'post');
- jest.spyOn(axios, 'get');
mockAxios
.onPost(mockOauthMetadata.oauth_token_url)
- .replyOnce(httpStatus.INTERNAL_SERVER_ERROR, { access_token: mockAccessToken });
- mockAxios.onGet('/api/v4/user').replyOnce(httpStatus.INTERNAL_SERVER_ERROR, mockUser);
+ .replyOnce(httpStatus.INTERNAL_SERVER_ERROR);
window.dispatchEvent(new MessageEvent('message', mockEvent));
@@ -187,7 +194,7 @@ describe('SignInOauthButton', () => {
});
it('emits `error` event', () => {
- expect(wrapper.emitted('error')).toBeTruthy();
+ expect(wrapper.emitted('error')[0]).toEqual([]);
});
it('does not emit `sign-in` event', () => {
diff --git a/spec/frontend/jira_connect/subscriptions/components/subscriptions_list_spec.js b/spec/frontend/jira_connect/subscriptions/components/subscriptions_list_spec.js
index 2aad533f677..2d7c58fc278 100644
--- a/spec/frontend/jira_connect/subscriptions/components/subscriptions_list_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/components/subscriptions_list_spec.js
@@ -20,12 +20,11 @@ describe('SubscriptionsList', () => {
let store;
const createComponent = () => {
- store = createStore();
+ store = createStore({
+ subscriptions: [mockSubscription],
+ });
wrapper = mount(SubscriptionsList, {
- provide: {
- subscriptions: [mockSubscription],
- },
store,
});
};
diff --git a/spec/frontend/jira_connect/subscriptions/pages/sign_in_spec.js b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_com_spec.js
index 97d1b077164..1649920b48b 100644
--- a/spec/frontend/jira_connect/subscriptions/pages/sign_in_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_com_spec.js
@@ -1,6 +1,6 @@
import { shallowMount } from '@vue/test-utils';
-import SignInPage from '~/jira_connect/subscriptions/pages/sign_in.vue';
+import SignInGitlabCom from '~/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_com.vue';
import SignInLegacyButton from '~/jira_connect/subscriptions/components/sign_in_legacy_button.vue';
import SignInOauthButton from '~/jira_connect/subscriptions/components/sign_in_oauth_button.vue';
import SubscriptionsList from '~/jira_connect/subscriptions/components/subscriptions_list.vue';
@@ -15,7 +15,7 @@ const defaultProvide = {
usersPath: mockUsersPath,
};
-describe('SignInPage', () => {
+describe('SignInGitlabCom', () => {
let wrapper;
let store;
@@ -26,7 +26,7 @@ describe('SignInPage', () => {
const createComponent = ({ props, jiraConnectOauthEnabled } = {}) => {
store = createStore();
- wrapper = shallowMount(SignInPage, {
+ wrapper = shallowMount(SignInGitlabCom, {
store,
provide: {
...defaultProvide,
@@ -49,7 +49,7 @@ describe('SignInPage', () => {
describe('template', () => {
describe.each`
scenario | hasSubscriptions | signInButtonText
- ${'with subscriptions'} | ${true} | ${SignInPage.i18n.signInButtonTextWithSubscriptions}
+ ${'with subscriptions'} | ${true} | ${SignInGitlabCom.i18n.signInButtonTextWithSubscriptions}
${'without subscriptions'} | ${false} | ${I18N_DEFAULT_SIGN_IN_BUTTON_TEXT}
`('$scenario', ({ hasSubscriptions, signInButtonText }) => {
describe('when `jiraConnectOauthEnabled` feature flag is disabled', () => {
diff --git a/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index_spec.js b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index_spec.js
new file mode 100644
index 00000000000..f4be8bf121d
--- /dev/null
+++ b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index_spec.js
@@ -0,0 +1,83 @@
+import { nextTick } from 'vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+
+import SignInGitlabMultiversion from '~/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index.vue';
+import VersionSelectForm from '~/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form.vue';
+import SignInOauthButton from '~/jira_connect/subscriptions/components/sign_in_oauth_button.vue';
+
+describe('SignInGitlabMultiversion', () => {
+ let wrapper;
+
+ const findVersionSelectForm = () => wrapper.findComponent(VersionSelectForm);
+ const findSignInOauthButton = () => wrapper.findComponent(SignInOauthButton);
+ const findSubtitle = () => wrapper.findByTestId('subtitle');
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(SignInGitlabMultiversion);
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when version is not selected', () => {
+ describe('VersionSelectForm', () => {
+ it('renders version select form', () => {
+ createComponent();
+
+ expect(findVersionSelectForm().exists()).toBe(true);
+ });
+
+ describe('when form emits "submit" event', () => {
+ it('hides the version select form and shows the sign in button', async () => {
+ createComponent();
+
+ findVersionSelectForm().vm.$emit('submit', 'gitlab.mycompany.com');
+ await nextTick();
+
+ expect(findVersionSelectForm().exists()).toBe(false);
+ expect(findSignInOauthButton().exists()).toBe(true);
+ });
+ });
+ });
+ });
+
+ describe('when version is selected', () => {
+ beforeEach(async () => {
+ createComponent();
+
+ findVersionSelectForm().vm.$emit('submit', 'gitlab.mycompany.com');
+ await nextTick();
+ });
+
+ describe('sign in button', () => {
+ it('renders sign in button', () => {
+ expect(findSignInOauthButton().exists()).toBe(true);
+ });
+
+ describe('when button emits `sign-in` event', () => {
+ it('emits `sign-in-oauth` event', () => {
+ const button = findSignInOauthButton();
+
+ const mockUser = { name: 'test' };
+ button.vm.$emit('sign-in', mockUser);
+
+ expect(wrapper.emitted('sign-in-oauth')[0]).toEqual([mockUser]);
+ });
+ });
+
+ describe('when button emits `error` event', () => {
+ it('emits `error` event', () => {
+ const button = findSignInOauthButton();
+ button.vm.$emit('error');
+
+ expect(wrapper.emitted('error')).toBeTruthy();
+ });
+ });
+ });
+
+ it('renders correct subtitle', () => {
+ expect(findSubtitle().text()).toBe(SignInGitlabMultiversion.i18n.signInSubtitle);
+ });
+ });
+});
diff --git a/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form_spec.js b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form_spec.js
new file mode 100644
index 00000000000..29e7fe7a5b2
--- /dev/null
+++ b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form_spec.js
@@ -0,0 +1,69 @@
+import { GlFormInput, GlFormRadioGroup, GlForm } from '@gitlab/ui';
+import { nextTick } from 'vue';
+
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import VersionSelectForm from '~/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/version_select_form.vue';
+
+describe('VersionSelectForm', () => {
+ let wrapper;
+
+ const findFormRadioGroup = () => wrapper.findComponent(GlFormRadioGroup);
+ const findForm = () => wrapper.findComponent(GlForm);
+ const findInput = () => wrapper.findComponent(GlFormInput);
+
+ const submitForm = () => findForm().vm.$emit('submit', new Event('submit'));
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(VersionSelectForm);
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('default state', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('selects saas radio option by default', () => {
+ expect(findFormRadioGroup().vm.$attrs.checked).toBe(VersionSelectForm.radioOptions.saas);
+ });
+
+ it('does not render instance input', () => {
+ expect(findInput().exists()).toBe(false);
+ });
+
+ describe('when form is submitted', () => {
+ it('emits "submit" event with gitlab.com as the payload', () => {
+ submitForm();
+
+ expect(wrapper.emitted('submit')[0][0]).toBe('https://gitlab.com');
+ });
+ });
+ });
+
+ describe('when "self-managed" radio option is selected', () => {
+ beforeEach(async () => {
+ createComponent();
+
+ findFormRadioGroup().vm.$emit('input', VersionSelectForm.radioOptions.selfManaged);
+ await nextTick();
+ });
+
+ it('reveals the self-managed input field', () => {
+ expect(findInput().exists()).toBe(true);
+ });
+
+ describe('when form is submitted', () => {
+ it('emits "submit" event with the input field value as the payload', () => {
+ const mockInstanceUrl = 'https://gitlab.example.com';
+
+ findInput().vm.$emit('input', mockInstanceUrl);
+ submitForm();
+
+ expect(wrapper.emitted('submit')[0][0]).toBe(mockInstanceUrl);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_page_spec.js b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_page_spec.js
new file mode 100644
index 00000000000..65b08fba592
--- /dev/null
+++ b/spec/frontend/jira_connect/subscriptions/pages/sign_in/sign_in_page_spec.js
@@ -0,0 +1,82 @@
+import { shallowMount } from '@vue/test-utils';
+
+import SignInPage from '~/jira_connect/subscriptions/pages/sign_in/sign_in_page.vue';
+import SignInGitlabCom from '~/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_com.vue';
+import SignInGitlabMultiversion from '~/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index.vue';
+import createStore from '~/jira_connect/subscriptions/store';
+
+describe('SignInPage', () => {
+ let wrapper;
+ let store;
+
+ const findSignInGitlabCom = () => wrapper.findComponent(SignInGitlabCom);
+ const findSignInGitabMultiversion = () => wrapper.findComponent(SignInGitlabMultiversion);
+
+ const createComponent = ({
+ props = {},
+ jiraConnectOauthEnabled,
+ jiraConnectOauthSelfManagedEnabled,
+ } = {}) => {
+ store = createStore();
+
+ wrapper = shallowMount(SignInPage, {
+ store,
+ provide: {
+ glFeatures: {
+ jiraConnectOauth: jiraConnectOauthEnabled,
+ jiraConnectOauthSelfManaged: jiraConnectOauthSelfManagedEnabled,
+ },
+ },
+ propsData: { hasSubscriptions: false, ...props },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it.each`
+ jiraConnectOauthEnabled | jiraConnectOauthSelfManagedEnabled | shouldRenderDotCom | shouldRenderMultiversion
+ ${false} | ${false} | ${true} | ${false}
+ ${false} | ${true} | ${true} | ${false}
+ ${true} | ${false} | ${true} | ${false}
+ ${true} | ${true} | ${false} | ${true}
+ `(
+ 'renders correct component when jiraConnectOauth is $jiraConnectOauthEnabled and jiraConnectOauthSelfManaged is $jiraConnectOauthSelfManagedEnabled',
+ ({
+ jiraConnectOauthEnabled,
+ jiraConnectOauthSelfManagedEnabled,
+ shouldRenderDotCom,
+ shouldRenderMultiversion,
+ }) => {
+ createComponent({ jiraConnectOauthEnabled, jiraConnectOauthSelfManagedEnabled });
+
+ expect(findSignInGitlabCom().exists()).toBe(shouldRenderDotCom);
+ expect(findSignInGitabMultiversion().exists()).toBe(shouldRenderMultiversion);
+ },
+ );
+
+ describe('when jiraConnectOauthSelfManaged is false', () => {
+ beforeEach(() => {
+ createComponent({ jiraConnectOauthSelfManaged: false, props: { hasSubscriptions: true } });
+ });
+
+ it('renders SignInGitlabCom with correct props', () => {
+ expect(findSignInGitlabCom().props()).toEqual({ hasSubscriptions: true });
+ });
+
+ describe('when error event is emitted', () => {
+ it('emits another error event', () => {
+ findSignInGitlabCom().vm.$emit('error');
+ expect(wrapper.emitted('error')[0]).toBeTruthy();
+ });
+ });
+
+ describe('when sign-in-oauth event is emitted', () => {
+ it('emits another sign-in-oauth event', () => {
+ findSignInGitlabCom().vm.$emit('sign-in-oauth');
+ expect(wrapper.emitted('sign-in-oauth')[0]).toEqual([]);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/jira_connect/subscriptions/pages/subscriptions_page_spec.js b/spec/frontend/jira_connect/subscriptions/pages/subscriptions_page_spec.js
new file mode 100644
index 00000000000..4956af76ead
--- /dev/null
+++ b/spec/frontend/jira_connect/subscriptions/pages/subscriptions_page_spec.js
@@ -0,0 +1,71 @@
+import { GlEmptyState, GlLoadingIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import SubscriptionsPage from '~/jira_connect/subscriptions/pages/subscriptions_page.vue';
+import AddNamespaceButton from '~/jira_connect/subscriptions/components/add_namespace_button.vue';
+import SubscriptionsList from '~/jira_connect/subscriptions/components/subscriptions_list.vue';
+import createStore from '~/jira_connect/subscriptions/store';
+
+describe('SubscriptionsPage', () => {
+ let wrapper;
+ let store;
+
+ const findAddNamespaceButton = () => wrapper.findComponent(AddNamespaceButton);
+ const findGlLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findSubscriptionsList = () => wrapper.findComponent(SubscriptionsList);
+ const findEmptyState = () => wrapper.findComponent(GlEmptyState);
+
+ const createComponent = ({ props, initialState } = {}) => {
+ store = createStore(initialState);
+
+ wrapper = shallowMount(SubscriptionsPage, {
+ store,
+ propsData: { hasSubscriptions: false, ...props },
+ stubs: {
+ GlEmptyState,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('template', () => {
+ describe.each`
+ scenario | subscriptionsLoading | hasSubscriptions | expectSubscriptionsList | expectEmptyState
+ ${'with subscriptions loading'} | ${true} | ${false} | ${false} | ${false}
+ ${'with subscriptions'} | ${false} | ${true} | ${true} | ${false}
+ ${'without subscriptions'} | ${false} | ${false} | ${false} | ${true}
+ `(
+ '$scenario',
+ ({ subscriptionsLoading, hasSubscriptions, expectEmptyState, expectSubscriptionsList }) => {
+ beforeEach(() => {
+ createComponent({
+ initialState: { subscriptionsLoading },
+ props: {
+ hasSubscriptions,
+ },
+ });
+ });
+
+ it(`${
+ subscriptionsLoading ? 'does not render' : 'renders'
+ } button to add namespace`, () => {
+ expect(findAddNamespaceButton().exists()).toBe(!subscriptionsLoading);
+ });
+
+ it(`${subscriptionsLoading ? 'renders' : 'does not render'} GlLoadingIcon`, () => {
+ expect(findGlLoadingIcon().exists()).toBe(subscriptionsLoading);
+ });
+
+ it(`${expectEmptyState ? 'renders' : 'does not render'} empty state`, () => {
+ expect(findEmptyState().exists()).toBe(expectEmptyState);
+ });
+
+ it(`${expectSubscriptionsList ? 'renders' : 'does not render'} subscriptions list`, () => {
+ expect(findSubscriptionsList().exists()).toBe(expectSubscriptionsList);
+ });
+ },
+ );
+ });
+});
diff --git a/spec/frontend/jira_connect/subscriptions/pages/subscriptions_spec.js b/spec/frontend/jira_connect/subscriptions/pages/subscriptions_spec.js
deleted file mode 100644
index 198278efc1f..00000000000
--- a/spec/frontend/jira_connect/subscriptions/pages/subscriptions_spec.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import { GlEmptyState } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import SubscriptionsPage from '~/jira_connect/subscriptions/pages/subscriptions.vue';
-import AddNamespaceButton from '~/jira_connect/subscriptions/components/add_namespace_button.vue';
-import SubscriptionsList from '~/jira_connect/subscriptions/components/subscriptions_list.vue';
-import createStore from '~/jira_connect/subscriptions/store';
-
-describe('SubscriptionsPage', () => {
- let wrapper;
- let store;
-
- const findAddNamespaceButton = () => wrapper.findComponent(AddNamespaceButton);
- const findSubscriptionsList = () => wrapper.findComponent(SubscriptionsList);
- const findEmptyState = () => wrapper.findComponent(GlEmptyState);
-
- const createComponent = ({ props } = {}) => {
- store = createStore();
-
- wrapper = shallowMount(SubscriptionsPage, {
- store,
- propsData: props,
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('template', () => {
- describe.each`
- scenario | expectSubscriptionsList | expectEmptyState
- ${'with subscriptions'} | ${true} | ${false}
- ${'without subscriptions'} | ${false} | ${true}
- `('$scenario', ({ expectEmptyState, expectSubscriptionsList }) => {
- beforeEach(() => {
- createComponent({
- props: {
- hasSubscriptions: expectSubscriptionsList,
- },
- });
- });
-
- it('renders button to add namespace', () => {
- expect(findAddNamespaceButton().exists()).toBe(true);
- });
-
- it(`${expectEmptyState ? 'renders' : 'does not render'} empty state`, () => {
- expect(findEmptyState().exists()).toBe(expectEmptyState);
- });
-
- it(`${expectSubscriptionsList ? 'renders' : 'does not render'} subscriptions list`, () => {
- expect(findSubscriptionsList().exists()).toBe(expectSubscriptionsList);
- });
- });
- });
-});
diff --git a/spec/frontend/jira_connect/subscriptions/store/actions_spec.js b/spec/frontend/jira_connect/subscriptions/store/actions_spec.js
new file mode 100644
index 00000000000..53b5d8e70af
--- /dev/null
+++ b/spec/frontend/jira_connect/subscriptions/store/actions_spec.js
@@ -0,0 +1,172 @@
+import testAction from 'helpers/vuex_action_helper';
+
+import * as types from '~/jira_connect/subscriptions/store/mutation_types';
+import {
+ fetchSubscriptions,
+ loadCurrentUser,
+ addSubscription,
+} from '~/jira_connect/subscriptions/store/actions';
+import state from '~/jira_connect/subscriptions/store/state';
+import * as api from '~/jira_connect/subscriptions/api';
+import * as userApi from '~/api/user_api';
+import * as integrationsApi from '~/api/integrations_api';
+import {
+ I18N_DEFAULT_SUBSCRIPTIONS_ERROR_MESSAGE,
+ I18N_ADD_SUBSCRIPTION_SUCCESS_ALERT_TITLE,
+ I18N_ADD_SUBSCRIPTION_SUCCESS_ALERT_MESSAGE,
+ INTEGRATIONS_DOC_LINK,
+} from '~/jira_connect/subscriptions/constants';
+import * as utils from '~/jira_connect/subscriptions/utils';
+
+describe('JiraConnect actions', () => {
+ let mockedState;
+
+ beforeEach(() => {
+ mockedState = state();
+ });
+
+ describe('fetchSubscriptions', () => {
+ const mockUrl = '/mock-url';
+
+ describe('when API request is successful', () => {
+ it('should commit SET_SUBSCRIPTIONS_LOADING and SET_SUBSCRIPTIONS mutations', async () => {
+ jest.spyOn(api, 'fetchSubscriptions').mockResolvedValue({ data: { subscriptions: [] } });
+
+ await testAction(
+ fetchSubscriptions,
+ mockUrl,
+ mockedState,
+ [
+ { type: types.SET_SUBSCRIPTIONS_LOADING, payload: true },
+ { type: types.SET_SUBSCRIPTIONS, payload: [] },
+ { type: types.SET_SUBSCRIPTIONS_LOADING, payload: false },
+ ],
+ [],
+ );
+
+ expect(api.fetchSubscriptions).toHaveBeenCalledWith(mockUrl);
+ });
+ });
+
+ describe('when API request fails', () => {
+ it('should commit SET_SUBSCRIPTIONS_LOADING, SET_SUBSCRIPTIONS_ERROR and SET_ALERT mutations', async () => {
+ jest.spyOn(api, 'fetchSubscriptions').mockRejectedValue();
+
+ await testAction(
+ fetchSubscriptions,
+ mockUrl,
+ mockedState,
+ [
+ { type: types.SET_SUBSCRIPTIONS_LOADING, payload: true },
+ { type: types.SET_SUBSCRIPTIONS_ERROR, payload: true },
+ {
+ type: types.SET_ALERT,
+ payload: { message: I18N_DEFAULT_SUBSCRIPTIONS_ERROR_MESSAGE, variant: 'danger' },
+ },
+ { type: types.SET_SUBSCRIPTIONS_LOADING, payload: false },
+ ],
+ [],
+ );
+
+ expect(api.fetchSubscriptions).toHaveBeenCalledWith(mockUrl);
+ });
+ });
+ });
+
+ describe('loadCurrentUser', () => {
+ const mockAccessToken = 'abcd1234';
+
+ describe('when API request succeeds', () => {
+ it('commits the SET_ACCESS_TOKEN and SET_CURRENT_USER mutations', async () => {
+ const mockUser = { name: 'root' };
+ jest.spyOn(userApi, 'getCurrentUser').mockResolvedValue({ data: mockUser });
+
+ await testAction(
+ loadCurrentUser,
+ mockAccessToken,
+ mockedState,
+ [{ type: types.SET_CURRENT_USER, payload: mockUser }],
+ [],
+ );
+
+ expect(userApi.getCurrentUser).toHaveBeenCalledWith({
+ headers: { Authorization: `Bearer ${mockAccessToken}` },
+ });
+ });
+ });
+
+ describe('when API request fails', () => {
+ it('commits the SET_CURRENT_USER_ERROR mutation', async () => {
+ jest.spyOn(userApi, 'getCurrentUser').mockRejectedValue();
+
+ await testAction(
+ loadCurrentUser,
+ mockAccessToken,
+ mockedState,
+ [{ type: types.SET_CURRENT_USER_ERROR }],
+ [],
+ );
+ });
+ });
+ });
+
+ describe('addSubscription', () => {
+ const mockNamespace = 'gitlab-org/gitlab';
+ const mockSubscriptionsPath = '/subscriptions';
+
+ beforeEach(() => {
+ jest.spyOn(utils, 'getJwt').mockReturnValue('1234');
+ });
+
+ describe('when API request succeeds', () => {
+ it('commits the SET_ACCESS_TOKEN and SET_CURRENT_USER mutations', async () => {
+ jest
+ .spyOn(integrationsApi, 'addJiraConnectSubscription')
+ .mockResolvedValue({ success: true });
+
+ await testAction(
+ addSubscription,
+ { namespacePath: mockNamespace, subscriptionsPath: mockSubscriptionsPath },
+ mockedState,
+ [
+ { type: types.ADD_SUBSCRIPTION_LOADING, payload: true },
+ {
+ type: types.SET_ALERT,
+ payload: {
+ title: I18N_ADD_SUBSCRIPTION_SUCCESS_ALERT_TITLE,
+ message: I18N_ADD_SUBSCRIPTION_SUCCESS_ALERT_MESSAGE,
+ linkUrl: INTEGRATIONS_DOC_LINK,
+ variant: 'success',
+ },
+ },
+ { type: types.ADD_SUBSCRIPTION_LOADING, payload: false },
+ ],
+ [{ type: 'fetchSubscriptions', payload: mockSubscriptionsPath }],
+ );
+
+ expect(integrationsApi.addJiraConnectSubscription).toHaveBeenCalledWith(mockNamespace, {
+ accessToken: null,
+ jwt: '1234',
+ });
+ });
+ });
+
+ describe('when API request fails', () => {
+ it('commits the SET_CURRENT_USER_ERROR mutation', async () => {
+ jest.spyOn(integrationsApi, 'addJiraConnectSubscription').mockRejectedValue();
+
+ await testAction(
+ addSubscription,
+ mockNamespace,
+ mockedState,
+ [
+ { type: types.ADD_SUBSCRIPTION_LOADING, payload: true },
+ { type: types.ADD_SUBSCRIPTION_ERROR },
+ { type: types.ADD_SUBSCRIPTION_LOADING, payload: false },
+ ],
+ [],
+ );
+ });
+ });
+ });
+});
diff --git a/spec/frontend/jira_connect/subscriptions/store/mutations_spec.js b/spec/frontend/jira_connect/subscriptions/store/mutations_spec.js
index 84a33dbf0b5..aeb136a76b9 100644
--- a/spec/frontend/jira_connect/subscriptions/store/mutations_spec.js
+++ b/spec/frontend/jira_connect/subscriptions/store/mutations_spec.js
@@ -25,4 +25,71 @@ describe('JiraConnect store mutations', () => {
});
});
});
+
+ describe('SET_SUBSCRIPTIONS', () => {
+ it('sets subscriptions loading flag', () => {
+ const mockSubscriptions = [{ name: 'test' }];
+ mutations.SET_SUBSCRIPTIONS(localState, mockSubscriptions);
+
+ expect(localState.subscriptions).toBe(mockSubscriptions);
+ });
+ });
+
+ describe('SET_SUBSCRIPTIONS_LOADING', () => {
+ it('sets subscriptions loading flag', () => {
+ mutations.SET_SUBSCRIPTIONS_LOADING(localState, true);
+
+ expect(localState.subscriptionsLoading).toBe(true);
+ });
+ });
+
+ describe('SET_SUBSCRIPTIONS_ERROR', () => {
+ it('sets subscriptions error', () => {
+ mutations.SET_SUBSCRIPTIONS_ERROR(localState, true);
+
+ expect(localState.subscriptionsError).toBe(true);
+ });
+ });
+
+ describe('ADD_SUBSCRIPTION_LOADING', () => {
+ it('sets addSubscriptionLoading', () => {
+ mutations.ADD_SUBSCRIPTION_LOADING(localState, true);
+
+ expect(localState.addSubscriptionLoading).toBe(true);
+ });
+ });
+
+ describe('ADD_SUBSCRIPTION_ERROR', () => {
+ it('sets addSubscriptionError', () => {
+ mutations.ADD_SUBSCRIPTION_ERROR(localState, true);
+
+ expect(localState.addSubscriptionError).toBe(true);
+ });
+ });
+
+ describe('SET_CURRENT_USER', () => {
+ it('sets currentUser', () => {
+ const mockUser = { name: 'root' };
+ mutations.SET_CURRENT_USER(localState, mockUser);
+
+ expect(localState.currentUser).toBe(mockUser);
+ });
+ });
+
+ describe('SET_CURRENT_USER_ERROR', () => {
+ it('sets currentUserError', () => {
+ mutations.SET_CURRENT_USER_ERROR(localState, true);
+
+ expect(localState.currentUserError).toBe(true);
+ });
+ });
+
+ describe('SET_ACCESS_TOKEN', () => {
+ it('sets accessToken', () => {
+ const mockAccessToken = 'asdf1234';
+ mutations.SET_ACCESS_TOKEN(localState, mockAccessToken);
+
+ expect(localState.accessToken).toBe(mockAccessToken);
+ });
+ });
});