summaryrefslogtreecommitdiff
path: root/spec/frontend
diff options
context:
space:
mode:
authorMike Greiling <mike@pixelcog.com>2019-06-04 21:20:31 +0000
committerMike Greiling <mike@pixelcog.com>2019-06-04 21:20:31 +0000
commit2e32e39350671e9d059592f91827a58ad04f0269 (patch)
tree2eef9d0bb7c18f9e851e03c05085a3e7688277cf /spec/frontend
parent632427bcc24403be21df5afe8e6bae9cf41c8bc7 (diff)
parenta9850b25c3624fe31d0230ad3f0df00fec6b7d48 (diff)
downloadgitlab-ce-2e32e39350671e9d059592f91827a58ad04f0269.tar.gz
Merge branch 'fe-jestify-specs-starting-with-a-1' into 'master'
Jestify some specs that start with "A" See merge request gitlab-org/gitlab-ce!28727
Diffstat (limited to 'spec/frontend')
-rw-r--r--spec/frontend/activities_spec.js70
-rw-r--r--spec/frontend/api_spec.js477
-rw-r--r--spec/frontend/autosave_spec.js151
-rw-r--r--spec/frontend/helpers/local_storage_helper.js41
4 files changed, 739 insertions, 0 deletions
diff --git a/spec/frontend/activities_spec.js b/spec/frontend/activities_spec.js
new file mode 100644
index 00000000000..d14be3a1f26
--- /dev/null
+++ b/spec/frontend/activities_spec.js
@@ -0,0 +1,70 @@
+/* eslint-disable no-unused-expressions, no-prototype-builtins, no-new, no-shadow */
+
+import $ from 'jquery';
+import Activities from '~/activities';
+import Pager from '~/pager';
+
+describe('Activities', () => {
+ window.gon || (window.gon = {});
+ const fixtureTemplate = 'static/event_filter.html';
+ const filters = [
+ {
+ id: 'all',
+ },
+ {
+ id: 'push',
+ name: 'push events',
+ },
+ {
+ id: 'merged',
+ name: 'merge events',
+ },
+ {
+ id: 'comments',
+ },
+ {
+ id: 'team',
+ },
+ ];
+
+ function getEventName(index) {
+ const filter = filters[index];
+ return filter.hasOwnProperty('name') ? filter.name : filter.id;
+ }
+
+ function getSelector(index) {
+ const filter = filters[index];
+ return `#${filter.id}_event_filter`;
+ }
+
+ beforeEach(() => {
+ loadFixtures(fixtureTemplate);
+ jest.spyOn(Pager, 'init').mockImplementation(() => {});
+ new Activities();
+ });
+
+ for (let i = 0; i < filters.length; i += 1) {
+ (i => {
+ describe(`when selecting ${getEventName(i)}`, () => {
+ beforeEach(() => {
+ $(getSelector(i)).click();
+ });
+
+ for (let x = 0; x < filters.length; x += 1) {
+ (x => {
+ const shouldHighlight = i === x;
+ const testName = shouldHighlight ? 'should highlight' : 'should not highlight';
+
+ it(`${testName} ${getEventName(x)}`, () => {
+ expect(
+ $(getSelector(x))
+ .parent()
+ .hasClass('active'),
+ ).toEqual(shouldHighlight);
+ });
+ })(x);
+ }
+ });
+ })(i);
+ }
+});
diff --git a/spec/frontend/api_spec.js b/spec/frontend/api_spec.js
new file mode 100644
index 00000000000..6010488d9e0
--- /dev/null
+++ b/spec/frontend/api_spec.js
@@ -0,0 +1,477 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import Api from '~/api';
+
+describe('Api', () => {
+ const dummyApiVersion = 'v3000';
+ const dummyUrlRoot = '/gitlab';
+ const dummyGon = {
+ api_version: dummyApiVersion,
+ relative_url_root: dummyUrlRoot,
+ };
+ let originalGon;
+ let mock;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ originalGon = window.gon;
+ window.gon = Object.assign({}, dummyGon);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ window.gon = originalGon;
+ });
+
+ describe('buildUrl', () => {
+ it('adds URL root and fills in API version', () => {
+ const input = '/api/:version/foo/bar';
+ const expectedOutput = `${dummyUrlRoot}/api/${dummyApiVersion}/foo/bar`;
+
+ const builtUrl = Api.buildUrl(input);
+
+ expect(builtUrl).toEqual(expectedOutput);
+ });
+
+ [null, '', '/'].forEach(root => {
+ it(`works when relative_url_root is ${root}`, () => {
+ window.gon.relative_url_root = root;
+ const input = '/api/:version/foo/bar';
+ const expectedOutput = `/api/${dummyApiVersion}/foo/bar`;
+
+ const builtUrl = Api.buildUrl(input);
+
+ expect(builtUrl).toEqual(expectedOutput);
+ });
+ });
+ });
+
+ describe('group', () => {
+ it('fetches a group', done => {
+ const groupId = '123456';
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${groupId}`;
+ mock.onGet(expectedUrl).reply(200, {
+ name: 'test',
+ });
+
+ Api.group(groupId, response => {
+ expect(response.name).toBe('test');
+ done();
+ });
+ });
+ });
+
+ describe('groupMembers', () => {
+ it('fetches group members', done => {
+ const groupId = '54321';
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${groupId}/members`;
+ const expectedData = [{ id: 7 }];
+ mock.onGet(expectedUrl).reply(200, expectedData);
+
+ Api.groupMembers(groupId)
+ .then(({ data }) => {
+ expect(data).toEqual(expectedData);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('groups', () => {
+ it('fetches groups', done => {
+ const query = 'dummy query';
+ const options = { unused: 'option' };
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups.json`;
+ mock.onGet(expectedUrl).reply(200, [
+ {
+ name: 'test',
+ },
+ ]);
+
+ Api.groups(query, options, response => {
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
+ done();
+ });
+ });
+ });
+
+ describe('namespaces', () => {
+ it('fetches namespaces', done => {
+ const query = 'dummy query';
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/namespaces.json`;
+ mock.onGet(expectedUrl).reply(200, [
+ {
+ name: 'test',
+ },
+ ]);
+
+ Api.namespaces(query, response => {
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
+ done();
+ });
+ });
+ });
+
+ describe('projects', () => {
+ it('fetches projects with membership when logged in', done => {
+ const query = 'dummy query';
+ const options = { unused: 'option' };
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects.json`;
+ window.gon.current_user_id = 1;
+ mock.onGet(expectedUrl).reply(200, [
+ {
+ name: 'test',
+ },
+ ]);
+
+ Api.projects(query, options, response => {
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
+ done();
+ });
+ });
+
+ it('fetches projects without membership when not logged in', done => {
+ const query = 'dummy query';
+ const options = { unused: 'option' };
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects.json`;
+ mock.onGet(expectedUrl).reply(200, [
+ {
+ name: 'test',
+ },
+ ]);
+
+ Api.projects(query, options, response => {
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
+ done();
+ });
+ });
+ });
+
+ describe('projectMergeRequests', () => {
+ const projectPath = 'abc';
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectPath}/merge_requests`;
+
+ it('fetches all merge requests for a project', done => {
+ const mockData = [{ source_branch: 'foo' }, { source_branch: 'bar' }];
+ mock.onGet(expectedUrl).reply(200, mockData);
+ Api.projectMergeRequests(projectPath)
+ .then(({ data }) => {
+ expect(data.length).toEqual(2);
+ expect(data[0].source_branch).toBe('foo');
+ expect(data[1].source_branch).toBe('bar');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('fetches merge requests filtered with passed params', done => {
+ const params = {
+ source_branch: 'bar',
+ };
+ const mockData = [{ source_branch: 'bar' }];
+ mock.onGet(expectedUrl, { params }).reply(200, mockData);
+
+ Api.projectMergeRequests(projectPath, params)
+ .then(({ data }) => {
+ expect(data.length).toEqual(1);
+ expect(data[0].source_branch).toBe('bar');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('projectMergeRequest', () => {
+ it('fetches a merge request', done => {
+ const projectPath = 'abc';
+ const mergeRequestId = '123456';
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectPath}/merge_requests/${mergeRequestId}`;
+ mock.onGet(expectedUrl).reply(200, {
+ title: 'test',
+ });
+
+ Api.projectMergeRequest(projectPath, mergeRequestId)
+ .then(({ data }) => {
+ expect(data.title).toBe('test');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('projectMergeRequestChanges', () => {
+ it('fetches the changes of a merge request', done => {
+ const projectPath = 'abc';
+ const mergeRequestId = '123456';
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectPath}/merge_requests/${mergeRequestId}/changes`;
+ mock.onGet(expectedUrl).reply(200, {
+ title: 'test',
+ });
+
+ Api.projectMergeRequestChanges(projectPath, mergeRequestId)
+ .then(({ data }) => {
+ expect(data.title).toBe('test');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('projectMergeRequestVersions', () => {
+ it('fetches the versions of a merge request', done => {
+ const projectPath = 'abc';
+ const mergeRequestId = '123456';
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectPath}/merge_requests/${mergeRequestId}/versions`;
+ mock.onGet(expectedUrl).reply(200, [
+ {
+ id: 123,
+ },
+ ]);
+
+ Api.projectMergeRequestVersions(projectPath, mergeRequestId)
+ .then(({ data }) => {
+ expect(data.length).toBe(1);
+ expect(data[0].id).toBe(123);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('projectRunners', () => {
+ it('fetches the runners of a project', done => {
+ const projectPath = 7;
+ const params = { scope: 'active' };
+ const mockData = [{ id: 4 }];
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectPath}/runners`;
+ mock.onGet(expectedUrl, { params }).reply(200, mockData);
+
+ Api.projectRunners(projectPath, { params })
+ .then(({ data }) => {
+ expect(data).toEqual(mockData);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('newLabel', () => {
+ it('creates a new label', done => {
+ const namespace = 'some namespace';
+ const project = 'some project';
+ const labelData = { some: 'data' };
+ const expectedUrl = `${dummyUrlRoot}/${namespace}/${project}/-/labels`;
+ const expectedData = {
+ label: labelData,
+ };
+ mock.onPost(expectedUrl).reply(config => {
+ expect(config.data).toBe(JSON.stringify(expectedData));
+
+ return [
+ 200,
+ {
+ name: 'test',
+ },
+ ];
+ });
+
+ Api.newLabel(namespace, project, labelData, response => {
+ expect(response.name).toBe('test');
+ done();
+ });
+ });
+
+ it('creates a group label', done => {
+ const namespace = 'group/subgroup';
+ const labelData = { some: 'data' };
+ const expectedUrl = Api.buildUrl(Api.groupLabelsPath).replace(':namespace_path', namespace);
+ const expectedData = {
+ label: labelData,
+ };
+ mock.onPost(expectedUrl).reply(config => {
+ expect(config.data).toBe(JSON.stringify(expectedData));
+
+ return [
+ 200,
+ {
+ name: 'test',
+ },
+ ];
+ });
+
+ Api.newLabel(namespace, undefined, labelData, response => {
+ expect(response.name).toBe('test');
+ done();
+ });
+ });
+ });
+
+ describe('groupProjects', () => {
+ it('fetches group projects', done => {
+ const groupId = '123456';
+ const query = 'dummy query';
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/groups/${groupId}/projects.json`;
+ mock.onGet(expectedUrl).reply(200, [
+ {
+ name: 'test',
+ },
+ ]);
+
+ Api.groupProjects(groupId, query, {}, response => {
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
+ done();
+ });
+ });
+ });
+
+ describe('issueTemplate', () => {
+ it('fetches an issue template', done => {
+ const namespace = 'some namespace';
+ const project = 'some project';
+ const templateKey = ' template #%?.key ';
+ const templateType = 'template type';
+ const expectedUrl = `${dummyUrlRoot}/${namespace}/${project}/templates/${templateType}/${encodeURIComponent(
+ templateKey,
+ )}`;
+ mock.onGet(expectedUrl).reply(200, 'test');
+
+ Api.issueTemplate(namespace, project, templateKey, templateType, (error, response) => {
+ expect(response).toBe('test');
+ done();
+ });
+ });
+ });
+
+ describe('projectTemplates', () => {
+ it('fetches a list of templates', done => {
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/gitlab-org%2Fgitlab-ce/templates/licenses`;
+
+ mock.onGet(expectedUrl).reply(200, 'test');
+
+ Api.projectTemplates('gitlab-org/gitlab-ce', 'licenses', {}, response => {
+ expect(response).toBe('test');
+ done();
+ });
+ });
+ });
+
+ describe('projectTemplate', () => {
+ it('fetches a single template', done => {
+ const data = { unused: 'option' };
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/gitlab-org%2Fgitlab-ce/templates/licenses/test%20license`;
+
+ mock.onGet(expectedUrl).reply(200, 'test');
+
+ Api.projectTemplate('gitlab-org/gitlab-ce', 'licenses', 'test license', data, response => {
+ expect(response).toBe('test');
+ done();
+ });
+ });
+ });
+
+ describe('users', () => {
+ it('fetches users', done => {
+ const query = 'dummy query';
+ const options = { unused: 'option' };
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/users.json`;
+ mock.onGet(expectedUrl).reply(200, [
+ {
+ name: 'test',
+ },
+ ]);
+
+ Api.users(query, options)
+ .then(({ data }) => {
+ expect(data.length).toBe(1);
+ expect(data[0].name).toBe('test');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('user', () => {
+ it('fetches single user', done => {
+ const userId = '123456';
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/users/${userId}`;
+ mock.onGet(expectedUrl).reply(200, {
+ name: 'testuser',
+ });
+
+ Api.user(userId)
+ .then(({ data }) => {
+ expect(data.name).toBe('testuser');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('user status', () => {
+ it('fetches single user status', done => {
+ const userId = '123456';
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/users/${userId}/status`;
+ mock.onGet(expectedUrl).reply(200, {
+ message: 'testmessage',
+ });
+
+ Api.userStatus(userId)
+ .then(({ data }) => {
+ expect(data.message).toBe('testmessage');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('commitPipelines', () => {
+ it('fetches pipelines for a given commit', done => {
+ const projectId = 'example/foobar';
+ const commitSha = 'abc123def';
+ const expectedUrl = `${dummyUrlRoot}/${projectId}/commit/${commitSha}/pipelines`;
+ mock.onGet(expectedUrl).reply(200, [
+ {
+ name: 'test',
+ },
+ ]);
+
+ Api.commitPipelines(projectId, commitSha)
+ .then(({ data }) => {
+ expect(data.length).toBe(1);
+ expect(data[0].name).toBe('test');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('createBranch', () => {
+ it('creates new branch', done => {
+ const ref = 'master';
+ const branch = 'new-branch-name';
+ const dummyProjectPath = 'gitlab-org/gitlab-ce';
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${encodeURIComponent(
+ dummyProjectPath,
+ )}/repository/branches`;
+
+ jest.spyOn(axios, 'post');
+
+ mock.onPost(expectedUrl).replyOnce(200, {
+ name: branch,
+ });
+
+ Api.createBranch(dummyProjectPath, { ref, branch })
+ .then(({ data }) => {
+ expect(data.name).toBe(branch);
+ expect(axios.post).toHaveBeenCalledWith(expectedUrl, { ref, branch });
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+});
diff --git a/spec/frontend/autosave_spec.js b/spec/frontend/autosave_spec.js
new file mode 100644
index 00000000000..4d9c8f96d62
--- /dev/null
+++ b/spec/frontend/autosave_spec.js
@@ -0,0 +1,151 @@
+import $ from 'jquery';
+import Autosave from '~/autosave';
+import AccessorUtilities from '~/lib/utils/accessor';
+import { useLocalStorageSpy } from 'helpers/local_storage_helper';
+
+describe('Autosave', () => {
+ useLocalStorageSpy();
+
+ let autosave;
+ const field = $('<textarea></textarea>');
+ const key = 'key';
+
+ describe('class constructor', () => {
+ beforeEach(() => {
+ jest.spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').mockReturnValue(true);
+ jest.spyOn(Autosave.prototype, 'restore').mockImplementation(() => {});
+ });
+
+ it('should set .isLocalStorageAvailable', () => {
+ autosave = new Autosave(field, key);
+
+ expect(AccessorUtilities.isLocalStorageAccessSafe).toHaveBeenCalled();
+ expect(autosave.isLocalStorageAvailable).toBe(true);
+ });
+ });
+
+ describe('restore', () => {
+ beforeEach(() => {
+ autosave = {
+ field,
+ key,
+ };
+ });
+
+ describe('if .isLocalStorageAvailable is `false`', () => {
+ beforeEach(() => {
+ autosave.isLocalStorageAvailable = false;
+
+ Autosave.prototype.restore.call(autosave);
+ });
+
+ it('should not call .getItem', () => {
+ expect(window.localStorage.getItem).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('if .isLocalStorageAvailable is `true`', () => {
+ beforeEach(() => {
+ autosave.isLocalStorageAvailable = true;
+ });
+
+ it('should call .getItem', () => {
+ Autosave.prototype.restore.call(autosave);
+
+ expect(window.localStorage.getItem).toHaveBeenCalledWith(key);
+ });
+
+ it('triggers jquery event', () => {
+ jest.spyOn(autosave.field, 'trigger').mockImplementation(() => {});
+
+ Autosave.prototype.restore.call(autosave);
+
+ expect(field.trigger).toHaveBeenCalled();
+ });
+
+ it('triggers native event', done => {
+ autosave.field.get(0).addEventListener('change', () => {
+ done();
+ });
+
+ Autosave.prototype.restore.call(autosave);
+ });
+ });
+
+ describe('if field gets deleted from DOM', () => {
+ beforeEach(() => {
+ autosave.field = $('.not-a-real-element');
+ });
+
+ it('does not trigger event', () => {
+ jest.spyOn(field, 'trigger');
+
+ expect(field.trigger).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('save', () => {
+ beforeEach(() => {
+ autosave = { reset: jest.fn() };
+ autosave.field = field;
+ field.val('value');
+ });
+
+ describe('if .isLocalStorageAvailable is `false`', () => {
+ beforeEach(() => {
+ autosave.isLocalStorageAvailable = false;
+
+ Autosave.prototype.save.call(autosave);
+ });
+
+ it('should not call .setItem', () => {
+ expect(window.localStorage.setItem).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('if .isLocalStorageAvailable is `true`', () => {
+ beforeEach(() => {
+ autosave.isLocalStorageAvailable = true;
+
+ Autosave.prototype.save.call(autosave);
+ });
+
+ it('should call .setItem', () => {
+ expect(window.localStorage.setItem).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('reset', () => {
+ beforeEach(() => {
+ autosave = {
+ key,
+ };
+ });
+
+ describe('if .isLocalStorageAvailable is `false`', () => {
+ beforeEach(() => {
+ autosave.isLocalStorageAvailable = false;
+
+ Autosave.prototype.reset.call(autosave);
+ });
+
+ it('should not call .removeItem', () => {
+ expect(window.localStorage.removeItem).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('if .isLocalStorageAvailable is `true`', () => {
+ beforeEach(() => {
+ autosave.isLocalStorageAvailable = true;
+
+ Autosave.prototype.reset.call(autosave);
+ });
+
+ it('should call .removeItem', () => {
+ expect(window.localStorage.removeItem).toHaveBeenCalledWith(key);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/helpers/local_storage_helper.js b/spec/frontend/helpers/local_storage_helper.js
new file mode 100644
index 00000000000..48e66b11767
--- /dev/null
+++ b/spec/frontend/helpers/local_storage_helper.js
@@ -0,0 +1,41 @@
+/**
+ * Manage the instance of a custom `window.localStorage`
+ *
+ * This only encapsulates the setup / teardown logic so that it can easily be
+ * reused with different implementations (i.e. a spy or a [fake][1])
+ *
+ * [1]: https://stackoverflow.com/a/41434763/1708147
+ *
+ * @param {() => any} fn Function that returns the object to use for localStorage
+ */
+const useLocalStorage = fn => {
+ const origLocalStorage = window.localStorage;
+ let currentLocalStorage;
+
+ Object.defineProperty(window, 'localStorage', {
+ get: () => currentLocalStorage,
+ });
+
+ beforeEach(() => {
+ currentLocalStorage = fn();
+ });
+
+ afterEach(() => {
+ currentLocalStorage = origLocalStorage;
+ });
+};
+
+/**
+ * Create an object with the localStorage interface but `jest.fn()` implementations.
+ */
+export const createLocalStorageSpy = () => ({
+ clear: jest.fn(),
+ getItem: jest.fn(),
+ setItem: jest.fn(),
+ removeItem: jest.fn(),
+});
+
+/**
+ * Before each test, overwrite `window.localStorage` with a spy implementation.
+ */
+export const useLocalStorageSpy = () => useLocalStorage(createLocalStorageSpy);