summaryrefslogtreecommitdiff
path: root/spec/javascripts
diff options
context:
space:
mode:
Diffstat (limited to 'spec/javascripts')
-rw-r--r--spec/javascripts/autosave_spec.js134
-rw-r--r--spec/javascripts/behaviors/gl_emoji/unicode_support_map_spec.js47
-rw-r--r--spec/javascripts/filtered_search/components/recent_searches_dropdown_content_spec.js20
-rw-r--r--spec/javascripts/filtered_search/filtered_search_manager_spec.js34
-rw-r--r--spec/javascripts/filtered_search/recent_searches_root_spec.js31
-rw-r--r--spec/javascripts/filtered_search/services/recent_searches_service_error_spec.js18
-rw-r--r--spec/javascripts/filtered_search/services/recent_searches_service_spec.js95
-rw-r--r--spec/javascripts/lib/utils/accessor_spec.js78
-rw-r--r--spec/javascripts/signin_tabs_memoizer_spec.js90
9 files changed, 544 insertions, 3 deletions
diff --git a/spec/javascripts/autosave_spec.js b/spec/javascripts/autosave_spec.js
new file mode 100644
index 00000000000..9f9acc392c2
--- /dev/null
+++ b/spec/javascripts/autosave_spec.js
@@ -0,0 +1,134 @@
+import Autosave from '~/autosave';
+import AccessorUtilities from '~/lib/utils/accessor';
+
+describe('Autosave', () => {
+ let autosave;
+
+ describe('class constructor', () => {
+ const key = 'key';
+ const field = jasmine.createSpyObj('field', ['data', 'on']);
+
+ beforeEach(() => {
+ spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').and.returnValue(true);
+ spyOn(Autosave.prototype, 'restore');
+
+ autosave = new Autosave(field, key);
+ });
+
+ it('should set .isLocalStorageAvailable', () => {
+ expect(AccessorUtilities.isLocalStorageAccessSafe).toHaveBeenCalled();
+ expect(autosave.isLocalStorageAvailable).toBe(true);
+ });
+ });
+
+ describe('restore', () => {
+ const key = 'key';
+ const field = jasmine.createSpyObj('field', ['trigger']);
+
+ beforeEach(() => {
+ autosave = {
+ field,
+ key,
+ };
+
+ spyOn(window.localStorage, 'getItem');
+ });
+
+ 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;
+
+ Autosave.prototype.restore.call(autosave);
+ });
+
+ it('should call .getItem', () => {
+ expect(window.localStorage.getItem).toHaveBeenCalledWith(key);
+ });
+ });
+ });
+
+ describe('save', () => {
+ const field = jasmine.createSpyObj('field', ['val']);
+
+ beforeEach(() => {
+ autosave = jasmine.createSpyObj('autosave', ['reset']);
+ autosave.field = field;
+
+ field.val.and.returnValue('value');
+
+ spyOn(window.localStorage, 'setItem');
+ });
+
+ 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', () => {
+ const key = 'key';
+
+ beforeEach(() => {
+ autosave = {
+ key,
+ };
+
+ spyOn(window.localStorage, 'removeItem');
+ });
+
+ 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/javascripts/behaviors/gl_emoji/unicode_support_map_spec.js b/spec/javascripts/behaviors/gl_emoji/unicode_support_map_spec.js
new file mode 100644
index 00000000000..1ed96a67478
--- /dev/null
+++ b/spec/javascripts/behaviors/gl_emoji/unicode_support_map_spec.js
@@ -0,0 +1,47 @@
+import { getUnicodeSupportMap } from '~/behaviors/gl_emoji/unicode_support_map';
+import AccessorUtilities from '~/lib/utils/accessor';
+
+describe('Unicode Support Map', () => {
+ describe('getUnicodeSupportMap', () => {
+ const stringSupportMap = 'stringSupportMap';
+
+ beforeEach(() => {
+ spyOn(AccessorUtilities, 'isLocalStorageAccessSafe');
+ spyOn(window.localStorage, 'getItem');
+ spyOn(window.localStorage, 'setItem');
+ spyOn(JSON, 'parse');
+ spyOn(JSON, 'stringify').and.returnValue(stringSupportMap);
+ });
+
+ describe('if isLocalStorageAvailable is `true`', function () {
+ beforeEach(() => {
+ AccessorUtilities.isLocalStorageAccessSafe.and.returnValue(true);
+
+ getUnicodeSupportMap();
+ });
+
+ it('should call .getItem and .setItem', () => {
+ const allArgs = window.localStorage.setItem.calls.allArgs();
+
+ expect(window.localStorage.getItem).toHaveBeenCalledWith('gl-emoji-user-agent');
+ expect(allArgs[0][0]).toBe('gl-emoji-user-agent');
+ expect(allArgs[0][1]).toBe(navigator.userAgent);
+ expect(allArgs[1][0]).toBe('gl-emoji-unicode-support-map');
+ expect(allArgs[1][1]).toBe(stringSupportMap);
+ });
+ });
+
+ describe('if isLocalStorageAvailable is `false`', function () {
+ beforeEach(() => {
+ AccessorUtilities.isLocalStorageAccessSafe.and.returnValue(false);
+
+ getUnicodeSupportMap();
+ });
+
+ it('should not call .getItem or .setItem', () => {
+ expect(window.localStorage.getItem.calls.count()).toBe(1);
+ expect(window.localStorage.setItem).not.toHaveBeenCalled();
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/filtered_search/components/recent_searches_dropdown_content_spec.js b/spec/javascripts/filtered_search/components/recent_searches_dropdown_content_spec.js
index 2722882375f..d0f09a561d5 100644
--- a/spec/javascripts/filtered_search/components/recent_searches_dropdown_content_spec.js
+++ b/spec/javascripts/filtered_search/components/recent_searches_dropdown_content_spec.js
@@ -76,6 +76,26 @@ describe('RecentSearchesDropdownContent', () => {
});
});
+ describe('if isLocalStorageAvailable is `false`', () => {
+ let el;
+
+ beforeEach(() => {
+ const props = Object.assign({ isLocalStorageAvailable: false }, propsDataWithItems);
+
+ vm = createComponent(props);
+ el = vm.$el;
+ });
+
+ it('should render an info note', () => {
+ const note = el.querySelector('.dropdown-info-note');
+ const items = el.querySelectorAll('.filtered-search-history-dropdown-item');
+
+ expect(note).toBeDefined();
+ expect(note.innerText.trim()).toBe('This feature requires local storage to be enabled');
+ expect(items.length).toEqual(propsDataWithoutItems.items.length);
+ });
+ });
+
describe('computed', () => {
describe('processedItems', () => {
it('with items', () => {
diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_manager_spec.js
index 97af681429b..2f2ead87495 100644
--- a/spec/javascripts/filtered_search/filtered_search_manager_spec.js
+++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js
@@ -1,3 +1,7 @@
+import * as recentSearchesStoreSrc from '~/filtered_search/stores/recent_searches_store';
+import RecentSearchesService from '~/filtered_search/services/recent_searches_service';
+import RecentSearchesServiceError from '~/filtered_search/services/recent_searches_service_error';
+
require('~/lib/utils/url_utility');
require('~/lib/utils/common_utils');
require('~/filtered_search/filtered_search_token_keys');
@@ -57,6 +61,36 @@ const FilteredSearchSpecHelper = require('../helpers/filtered_search_spec_helper
manager.cleanup();
});
+ describe('class constructor', () => {
+ const isLocalStorageAvailable = 'isLocalStorageAvailable';
+ let filteredSearchManager;
+
+ beforeEach(() => {
+ spyOn(RecentSearchesService, 'isAvailable').and.returnValue(isLocalStorageAvailable);
+ spyOn(recentSearchesStoreSrc, 'default');
+
+ filteredSearchManager = new gl.FilteredSearchManager();
+
+ return filteredSearchManager;
+ });
+
+ it('should instantiate RecentSearchesStore with isLocalStorageAvailable', () => {
+ expect(RecentSearchesService.isAvailable).toHaveBeenCalled();
+ expect(recentSearchesStoreSrc.default).toHaveBeenCalledWith({
+ isLocalStorageAvailable,
+ });
+ });
+
+ it('should not instantiate Flash if an RecentSearchesServiceError is caught', () => {
+ spyOn(RecentSearchesService.prototype, 'fetch').and.callFake(() => Promise.reject(new RecentSearchesServiceError()));
+ spyOn(window, 'Flash');
+
+ filteredSearchManager = new gl.FilteredSearchManager();
+
+ expect(window.Flash).not.toHaveBeenCalled();
+ });
+ });
+
describe('search', () => {
const defaultParams = '?scope=all&utf8=%E2%9C%93&state=opened';
diff --git a/spec/javascripts/filtered_search/recent_searches_root_spec.js b/spec/javascripts/filtered_search/recent_searches_root_spec.js
new file mode 100644
index 00000000000..d8ba6de5f45
--- /dev/null
+++ b/spec/javascripts/filtered_search/recent_searches_root_spec.js
@@ -0,0 +1,31 @@
+import RecentSearchesRoot from '~/filtered_search/recent_searches_root';
+import * as vueSrc from 'vue';
+
+describe('RecentSearchesRoot', () => {
+ describe('render', () => {
+ let recentSearchesRoot;
+ let data;
+ let template;
+
+ beforeEach(() => {
+ recentSearchesRoot = {
+ store: {
+ state: 'state',
+ },
+ };
+
+ spyOn(vueSrc, 'default').and.callFake((options) => {
+ data = options.data;
+ template = options.template;
+ });
+
+ RecentSearchesRoot.prototype.render.call(recentSearchesRoot);
+ });
+
+ it('should instantiate Vue', () => {
+ expect(vueSrc.default).toHaveBeenCalled();
+ expect(data()).toBe(recentSearchesRoot.store.state);
+ expect(template).toContain(':is-local-storage-available="isLocalStorageAvailable"');
+ });
+ });
+});
diff --git a/spec/javascripts/filtered_search/services/recent_searches_service_error_spec.js b/spec/javascripts/filtered_search/services/recent_searches_service_error_spec.js
new file mode 100644
index 00000000000..ea7c146fa4f
--- /dev/null
+++ b/spec/javascripts/filtered_search/services/recent_searches_service_error_spec.js
@@ -0,0 +1,18 @@
+import RecentSearchesServiceError from '~/filtered_search/services/recent_searches_service_error';
+
+describe('RecentSearchesServiceError', () => {
+ let recentSearchesServiceError;
+
+ beforeEach(() => {
+ recentSearchesServiceError = new RecentSearchesServiceError();
+ });
+
+ it('instantiates an instance of RecentSearchesServiceError and not an Error', () => {
+ expect(recentSearchesServiceError).toEqual(jasmine.any(RecentSearchesServiceError));
+ expect(recentSearchesServiceError.name).toBe('RecentSearchesServiceError');
+ });
+
+ it('should set a default message', () => {
+ expect(recentSearchesServiceError.message).toBe('Recent Searches Service is unavailable');
+ });
+});
diff --git a/spec/javascripts/filtered_search/services/recent_searches_service_spec.js b/spec/javascripts/filtered_search/services/recent_searches_service_spec.js
index 2a58fb3a7df..c64d4374680 100644
--- a/spec/javascripts/filtered_search/services/recent_searches_service_spec.js
+++ b/spec/javascripts/filtered_search/services/recent_searches_service_spec.js
@@ -1,4 +1,5 @@
import RecentSearchesService from '~/filtered_search/services/recent_searches_service';
+import AccessorUtilities from '~/lib/utils/accessor';
describe('RecentSearchesService', () => {
let service;
@@ -9,6 +10,10 @@ describe('RecentSearchesService', () => {
});
describe('fetch', () => {
+ beforeEach(() => {
+ spyOn(RecentSearchesService, 'isAvailable').and.returnValue(true);
+ });
+
it('should default to empty array', (done) => {
const fetchItemsPromise = service.fetch();
@@ -27,11 +32,21 @@ describe('RecentSearchesService', () => {
const fetchItemsPromise = service.fetch();
fetchItemsPromise
- .catch(() => {
+ .catch((error) => {
+ expect(error).toEqual(jasmine.any(SyntaxError));
done();
});
});
+ it('should reject when service is unavailable', (done) => {
+ RecentSearchesService.isAvailable.and.returnValue(false);
+
+ service.fetch().catch((error) => {
+ expect(error).toEqual(jasmine.any(Error));
+ done();
+ });
+ });
+
it('should return items from localStorage', (done) => {
window.localStorage.setItem(service.localStorageKey, '["foo", "bar"]');
const fetchItemsPromise = service.fetch();
@@ -42,15 +57,89 @@ describe('RecentSearchesService', () => {
done();
});
});
+
+ describe('if .isAvailable returns `false`', () => {
+ beforeEach(() => {
+ RecentSearchesService.isAvailable.and.returnValue(false);
+
+ spyOn(window.localStorage, 'getItem');
+
+ RecentSearchesService.prototype.fetch();
+ });
+
+ it('should not call .getItem', () => {
+ expect(window.localStorage.getItem).not.toHaveBeenCalled();
+ });
+ });
});
describe('setRecentSearches', () => {
+ beforeEach(() => {
+ spyOn(RecentSearchesService, 'isAvailable').and.returnValue(true);
+ });
+
it('should save things in localStorage', () => {
const items = ['foo', 'bar'];
service.save(items);
- const newLocalStorageValue =
- window.localStorage.getItem(service.localStorageKey);
+ const newLocalStorageValue = window.localStorage.getItem(service.localStorageKey);
expect(JSON.parse(newLocalStorageValue)).toEqual(items);
});
});
+
+ describe('save', () => {
+ beforeEach(() => {
+ spyOn(window.localStorage, 'setItem');
+ spyOn(RecentSearchesService, 'isAvailable');
+ });
+
+ describe('if .isAvailable returns `true`', () => {
+ const searchesString = 'searchesString';
+ const localStorageKey = 'localStorageKey';
+ const recentSearchesService = {
+ localStorageKey,
+ };
+
+ beforeEach(() => {
+ RecentSearchesService.isAvailable.and.returnValue(true);
+
+ spyOn(JSON, 'stringify').and.returnValue(searchesString);
+
+ RecentSearchesService.prototype.save.call(recentSearchesService);
+ });
+
+ it('should call .setItem', () => {
+ expect(window.localStorage.setItem).toHaveBeenCalledWith(localStorageKey, searchesString);
+ });
+ });
+
+ describe('if .isAvailable returns `false`', () => {
+ beforeEach(() => {
+ RecentSearchesService.isAvailable.and.returnValue(false);
+
+ RecentSearchesService.prototype.save();
+ });
+
+ it('should not call .setItem', () => {
+ expect(window.localStorage.setItem).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('isAvailable', () => {
+ let isAvailable;
+
+ beforeEach(() => {
+ spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').and.callThrough();
+
+ isAvailable = RecentSearchesService.isAvailable();
+ });
+
+ it('should call .isLocalStorageAccessSafe', () => {
+ expect(AccessorUtilities.isLocalStorageAccessSafe).toHaveBeenCalled();
+ });
+
+ it('should return a boolean', () => {
+ expect(typeof isAvailable).toBe('boolean');
+ });
+ });
});
diff --git a/spec/javascripts/lib/utils/accessor_spec.js b/spec/javascripts/lib/utils/accessor_spec.js
new file mode 100644
index 00000000000..b768d6f2a68
--- /dev/null
+++ b/spec/javascripts/lib/utils/accessor_spec.js
@@ -0,0 +1,78 @@
+import AccessorUtilities from '~/lib/utils/accessor';
+
+describe('AccessorUtilities', () => {
+ const testError = new Error('test error');
+
+ describe('isPropertyAccessSafe', () => {
+ let base;
+
+ it('should return `true` if access is safe', () => {
+ base = { testProp: 'testProp' };
+
+ expect(AccessorUtilities.isPropertyAccessSafe(base, 'testProp')).toBe(true);
+ });
+
+ it('should return `false` if access throws an error', () => {
+ base = { get testProp() { throw testError; } };
+
+ expect(AccessorUtilities.isPropertyAccessSafe(base, 'testProp')).toBe(false);
+ });
+
+ it('should return `false` if property is undefined', () => {
+ base = {};
+
+ expect(AccessorUtilities.isPropertyAccessSafe(base, 'testProp')).toBe(false);
+ });
+ });
+
+ describe('isFunctionCallSafe', () => {
+ const base = {};
+
+ it('should return `true` if calling is safe', () => {
+ base.func = () => {};
+
+ expect(AccessorUtilities.isFunctionCallSafe(base, 'func')).toBe(true);
+ });
+
+ it('should return `false` if calling throws an error', () => {
+ base.func = () => { throw new Error('test error'); };
+
+ expect(AccessorUtilities.isFunctionCallSafe(base, 'func')).toBe(false);
+ });
+
+ it('should return `false` if function is undefined', () => {
+ base.func = undefined;
+
+ expect(AccessorUtilities.isFunctionCallSafe(base, 'func')).toBe(false);
+ });
+ });
+
+ describe('isLocalStorageAccessSafe', () => {
+ beforeEach(() => {
+ spyOn(window.localStorage, 'setItem');
+ spyOn(window.localStorage, 'removeItem');
+ });
+
+ it('should return `true` if access is safe', () => {
+ expect(AccessorUtilities.isLocalStorageAccessSafe()).toBe(true);
+ });
+
+ it('should return `false` if access to .setItem isnt safe', () => {
+ window.localStorage.setItem.and.callFake(() => { throw testError; });
+
+ expect(AccessorUtilities.isLocalStorageAccessSafe()).toBe(false);
+ });
+
+ it('should set a test item if access is safe', () => {
+ AccessorUtilities.isLocalStorageAccessSafe();
+
+ expect(window.localStorage.setItem).toHaveBeenCalledWith('isLocalStorageAccessSafe', 'true');
+ });
+
+ it('should remove the test item if access is safe', () => {
+ AccessorUtilities.isLocalStorageAccessSafe();
+
+ expect(window.localStorage.removeItem).toHaveBeenCalledWith('isLocalStorageAccessSafe');
+ });
+ });
+});
diff --git a/spec/javascripts/signin_tabs_memoizer_spec.js b/spec/javascripts/signin_tabs_memoizer_spec.js
index d83d9a57b42..5b4f5933b34 100644
--- a/spec/javascripts/signin_tabs_memoizer_spec.js
+++ b/spec/javascripts/signin_tabs_memoizer_spec.js
@@ -1,3 +1,5 @@
+import AccessorUtilities from '~/lib/utils/accessor';
+
require('~/signin_tabs_memoizer');
((global) => {
@@ -19,6 +21,8 @@ require('~/signin_tabs_memoizer');
beforeEach(() => {
loadFixtures(fixtureTemplate);
+
+ spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').and.returnValue(true);
});
it('does nothing if no tab was previously selected', () => {
@@ -49,5 +53,91 @@ require('~/signin_tabs_memoizer');
expect(memo.readData()).toEqual('#standard');
});
+
+ describe('class constructor', () => {
+ beforeEach(() => {
+ memo = createMemoizer();
+ });
+
+ it('should set .isLocalStorageAvailable', () => {
+ expect(AccessorUtilities.isLocalStorageAccessSafe).toHaveBeenCalled();
+ expect(memo.isLocalStorageAvailable).toBe(true);
+ });
+ });
+
+ describe('saveData', () => {
+ beforeEach(() => {
+ memo = {
+ currentTabKey,
+ };
+
+ spyOn(localStorage, 'setItem');
+ });
+
+ describe('if .isLocalStorageAvailable is `false`', () => {
+ beforeEach(function () {
+ memo.isLocalStorageAvailable = false;
+
+ global.ActiveTabMemoizer.prototype.saveData.call(memo);
+ });
+
+ it('should not call .setItem', () => {
+ expect(localStorage.setItem).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('if .isLocalStorageAvailable is `true`', () => {
+ const value = 'value';
+
+ beforeEach(function () {
+ memo.isLocalStorageAvailable = true;
+
+ global.ActiveTabMemoizer.prototype.saveData.call(memo, value);
+ });
+
+ it('should call .setItem', () => {
+ expect(localStorage.setItem).toHaveBeenCalledWith(currentTabKey, value);
+ });
+ });
+ });
+
+ describe('readData', () => {
+ const itemValue = 'itemValue';
+ let readData;
+
+ beforeEach(() => {
+ memo = {
+ currentTabKey,
+ };
+
+ spyOn(localStorage, 'getItem').and.returnValue(itemValue);
+ });
+
+ describe('if .isLocalStorageAvailable is `false`', () => {
+ beforeEach(function () {
+ memo.isLocalStorageAvailable = false;
+
+ readData = global.ActiveTabMemoizer.prototype.readData.call(memo);
+ });
+
+ it('should not call .getItem and should return `null`', () => {
+ expect(localStorage.getItem).not.toHaveBeenCalled();
+ expect(readData).toBe(null);
+ });
+ });
+
+ describe('if .isLocalStorageAvailable is `true`', () => {
+ beforeEach(function () {
+ memo.isLocalStorageAvailable = true;
+
+ readData = global.ActiveTabMemoizer.prototype.readData.call(memo);
+ });
+
+ it('should call .getItem and return the localStorage value', () => {
+ expect(window.localStorage.getItem).toHaveBeenCalledWith(currentTabKey);
+ expect(readData).toBe(itemValue);
+ });
+ });
+ });
});
})(window);