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/lib')
-rw-r--r--spec/frontend/lib/apollo/instrumentation_link_spec.js54
-rw-r--r--spec/frontend/lib/dompurify_spec.js25
-rw-r--r--spec/frontend/lib/logger/__snapshots__/hello_spec.js.snap16
-rw-r--r--spec/frontend/lib/logger/hello_deferred_spec.js17
-rw-r--r--spec/frontend/lib/logger/hello_spec.js20
-rw-r--r--spec/frontend/lib/logger/index_spec.js23
-rw-r--r--spec/frontend/lib/utils/accessor_spec.js65
-rw-r--r--spec/frontend/lib/utils/datetime/date_format_utility_spec.js120
-rw-r--r--spec/frontend/lib/utils/dom_utils_spec.js15
-rw-r--r--spec/frontend/lib/utils/text_markdown_spec.js19
-rw-r--r--spec/frontend/lib/utils/url_utility_spec.js23
11 files changed, 316 insertions, 81 deletions
diff --git a/spec/frontend/lib/apollo/instrumentation_link_spec.js b/spec/frontend/lib/apollo/instrumentation_link_spec.js
new file mode 100644
index 00000000000..ef686129257
--- /dev/null
+++ b/spec/frontend/lib/apollo/instrumentation_link_spec.js
@@ -0,0 +1,54 @@
+import { testApolloLink } from 'helpers/test_apollo_link';
+import { getInstrumentationLink, FEATURE_CATEGORY_HEADER } from '~/lib/apollo/instrumentation_link';
+
+const TEST_FEATURE_CATEGORY = 'foo_feature';
+
+describe('~/lib/apollo/instrumentation_link', () => {
+ const setFeatureCategory = (val) => {
+ window.gon.feature_category = val;
+ };
+
+ afterEach(() => {
+ getInstrumentationLink.cache.clear();
+ });
+
+ describe('getInstrumentationLink', () => {
+ describe('with no gon.feature_category', () => {
+ beforeEach(() => {
+ setFeatureCategory(null);
+ });
+
+ it('returns null', () => {
+ expect(getInstrumentationLink()).toBe(null);
+ });
+ });
+
+ describe('with gon.feature_category', () => {
+ beforeEach(() => {
+ setFeatureCategory(TEST_FEATURE_CATEGORY);
+ });
+
+ it('returns memoized apollo link', () => {
+ const result = getInstrumentationLink();
+
+ // expect.any(ApolloLink) doesn't work for some reason...
+ expect(result).toHaveProp('request');
+ expect(result).toBe(getInstrumentationLink());
+ });
+
+ it('adds a feature category header from the returned apollo link', async () => {
+ const defaultHeaders = { Authorization: 'foo' };
+ const operation = await testApolloLink(getInstrumentationLink(), {
+ context: { headers: defaultHeaders },
+ });
+
+ const { headers } = operation.getContext();
+
+ expect(headers).toEqual({
+ ...defaultHeaders,
+ [FEATURE_CATEGORY_HEADER]: TEST_FEATURE_CATEGORY,
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/lib/dompurify_spec.js b/spec/frontend/lib/dompurify_spec.js
index fa8dbb12a08..324441fa2c9 100644
--- a/spec/frontend/lib/dompurify_spec.js
+++ b/spec/frontend/lib/dompurify_spec.js
@@ -44,6 +44,31 @@ describe('~/lib/dompurify', () => {
expect(sanitize('<strong></strong>', { ALLOWED_TAGS: [] })).toBe('');
});
+ describe('includes default configuration', () => {
+ it('with empty config', () => {
+ const svgIcon = '<svg width="100"><use></use></svg>';
+ expect(sanitize(svgIcon, {})).toBe(svgIcon);
+ });
+
+ it('with valid config', () => {
+ expect(sanitize('<a href="#" data-remote="true"></a>', { ALLOWED_TAGS: ['a'] })).toBe(
+ '<a href="#"></a>',
+ );
+ });
+ });
+
+ it("doesn't sanitize local references", () => {
+ const htmlHref = `<svg><use href="#some-element"></use></svg>`;
+ const htmlXlink = `<svg><use xlink:href="#some-element"></use></svg>`;
+
+ expect(sanitize(htmlHref)).toBe(htmlHref);
+ expect(sanitize(htmlXlink)).toBe(htmlXlink);
+ });
+
+ it("doesn't sanitize gl-emoji", () => {
+ expect(sanitize('<p><gl-emoji>💯</gl-emoji></p>')).toBe('<p><gl-emoji>💯</gl-emoji></p>');
+ });
+
describe.each`
type | gon
${'root'} | ${rootGon}
diff --git a/spec/frontend/lib/logger/__snapshots__/hello_spec.js.snap b/spec/frontend/lib/logger/__snapshots__/hello_spec.js.snap
new file mode 100644
index 00000000000..791ec05befd
--- /dev/null
+++ b/spec/frontend/lib/logger/__snapshots__/hello_spec.js.snap
@@ -0,0 +1,16 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`~/lib/logger/hello logHello console logs a friendly hello message 1`] = `
+Array [
+ Array [
+ "%cWelcome to GitLab!%c
+
+Does this page need fixes or improvements? Open an issue or contribute a merge request to help make GitLab more lovable. At GitLab, everyone can contribute!
+
+🤝 Contribute to GitLab: https://about.gitlab.com/community/contribute/
+🔎 Create a new GitLab issue: https://gitlab.com/gitlab-org/gitlab/-/issues/new",
+ "padding-top: 0.5em; font-size: 2em;",
+ "padding-bottom: 0.5em;",
+ ],
+]
+`;
diff --git a/spec/frontend/lib/logger/hello_deferred_spec.js b/spec/frontend/lib/logger/hello_deferred_spec.js
new file mode 100644
index 00000000000..3233cbff0dc
--- /dev/null
+++ b/spec/frontend/lib/logger/hello_deferred_spec.js
@@ -0,0 +1,17 @@
+import waitForPromises from 'helpers/wait_for_promises';
+import { logHello } from '~/lib/logger/hello';
+import { logHelloDeferred } from '~/lib/logger/hello_deferred';
+
+jest.mock('~/lib/logger/hello');
+
+describe('~/lib/logger/hello_deferred', () => {
+ it('dynamically imports and calls logHello', async () => {
+ logHelloDeferred();
+
+ expect(logHello).not.toHaveBeenCalled();
+
+ await waitForPromises();
+
+ expect(logHello).toHaveBeenCalled();
+ });
+});
diff --git a/spec/frontend/lib/logger/hello_spec.js b/spec/frontend/lib/logger/hello_spec.js
new file mode 100644
index 00000000000..39abe0e0dd0
--- /dev/null
+++ b/spec/frontend/lib/logger/hello_spec.js
@@ -0,0 +1,20 @@
+import { logHello } from '~/lib/logger/hello';
+
+describe('~/lib/logger/hello', () => {
+ let consoleLogSpy;
+
+ beforeEach(() => {
+ // We don't `mockImplementation` so we can validate there's no errors thrown
+ consoleLogSpy = jest.spyOn(console, 'log');
+ });
+
+ describe('logHello', () => {
+ it('console logs a friendly hello message', () => {
+ expect(consoleLogSpy).not.toHaveBeenCalled();
+
+ logHello();
+
+ expect(consoleLogSpy.mock.calls).toMatchSnapshot();
+ });
+ });
+});
diff --git a/spec/frontend/lib/logger/index_spec.js b/spec/frontend/lib/logger/index_spec.js
new file mode 100644
index 00000000000..9382fafe4de
--- /dev/null
+++ b/spec/frontend/lib/logger/index_spec.js
@@ -0,0 +1,23 @@
+import { logError, LOG_PREFIX } from '~/lib/logger';
+
+describe('~/lib/logger', () => {
+ let consoleErrorSpy;
+
+ beforeEach(() => {
+ consoleErrorSpy = jest.spyOn(console, 'error');
+ consoleErrorSpy.mockImplementation();
+ });
+
+ describe('logError', () => {
+ it('sends given message to console.error', () => {
+ const message = 'Lorem ipsum dolar sit amit';
+ const error = new Error('lorem ipsum');
+
+ expect(consoleErrorSpy).not.toHaveBeenCalled();
+
+ logError(message, error);
+
+ expect(consoleErrorSpy).toHaveBeenCalledWith(LOG_PREFIX, `${message}\n`, error);
+ });
+ });
+});
diff --git a/spec/frontend/lib/utils/accessor_spec.js b/spec/frontend/lib/utils/accessor_spec.js
index 752a88296e6..63497d795ce 100644
--- a/spec/frontend/lib/utils/accessor_spec.js
+++ b/spec/frontend/lib/utils/accessor_spec.js
@@ -6,60 +6,9 @@ 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', () => {
+ describe('canUseLocalStorage', () => {
it('should return `true` if access is safe', () => {
- expect(AccessorUtilities.isLocalStorageAccessSafe()).toBe(true);
+ expect(AccessorUtilities.canUseLocalStorage()).toBe(true);
});
it('should return `false` if access to .setItem isnt safe', () => {
@@ -67,19 +16,19 @@ describe('AccessorUtilities', () => {
throw testError;
});
- expect(AccessorUtilities.isLocalStorageAccessSafe()).toBe(false);
+ expect(AccessorUtilities.canUseLocalStorage()).toBe(false);
});
it('should set a test item if access is safe', () => {
- AccessorUtilities.isLocalStorageAccessSafe();
+ AccessorUtilities.canUseLocalStorage();
- expect(window.localStorage.setItem).toHaveBeenCalledWith('isLocalStorageAccessSafe', 'true');
+ expect(window.localStorage.setItem).toHaveBeenCalledWith('canUseLocalStorage', 'true');
});
it('should remove the test item if access is safe', () => {
- AccessorUtilities.isLocalStorageAccessSafe();
+ AccessorUtilities.canUseLocalStorage();
- expect(window.localStorage.removeItem).toHaveBeenCalledWith('isLocalStorageAccessSafe');
+ expect(window.localStorage.removeItem).toHaveBeenCalledWith('canUseLocalStorage');
});
});
});
diff --git a/spec/frontend/lib/utils/datetime/date_format_utility_spec.js b/spec/frontend/lib/utils/datetime/date_format_utility_spec.js
new file mode 100644
index 00000000000..942ba56196e
--- /dev/null
+++ b/spec/frontend/lib/utils/datetime/date_format_utility_spec.js
@@ -0,0 +1,120 @@
+import * as utils from '~/lib/utils/datetime/date_format_utility';
+
+describe('date_format_utility.js', () => {
+ describe('padWithZeros', () => {
+ it.each`
+ input | output
+ ${0} | ${'00'}
+ ${'1'} | ${'01'}
+ ${'10'} | ${'10'}
+ ${'100'} | ${'100'}
+ ${100} | ${'100'}
+ ${'a'} | ${'0a'}
+ ${'foo'} | ${'foo'}
+ `('properly pads $input to match $output', ({ input, output }) => {
+ expect(utils.padWithZeros(input)).toEqual([output]);
+ });
+
+ it('accepts multiple arguments', () => {
+ expect(utils.padWithZeros(1, '2', 3)).toEqual(['01', '02', '03']);
+ });
+
+ it('returns an empty array provided no argument', () => {
+ expect(utils.padWithZeros()).toEqual([]);
+ });
+ });
+
+ describe('stripTimezoneFromISODate', () => {
+ it.each`
+ input | expectedOutput
+ ${'2021-08-16T00:00:00Z'} | ${'2021-08-16T00:00:00'}
+ ${'2021-08-16T10:30:00+02:00'} | ${'2021-08-16T10:30:00'}
+ ${'2021-08-16T10:30:00-05:30'} | ${'2021-08-16T10:30:00'}
+ `('returns $expectedOutput when given $input', ({ input, expectedOutput }) => {
+ expect(utils.stripTimezoneFromISODate(input)).toBe(expectedOutput);
+ });
+
+ it('returns null if date is invalid', () => {
+ expect(utils.stripTimezoneFromISODate('Invalid date')).toBe(null);
+ });
+ });
+
+ describe('dateToYearMonthDate', () => {
+ it.each`
+ date | expectedOutput
+ ${new Date('2021-08-05')} | ${{ year: '2021', month: '08', day: '05' }}
+ ${new Date('2021-12-24')} | ${{ year: '2021', month: '12', day: '24' }}
+ `('returns $expectedOutput provided $date', ({ date, expectedOutput }) => {
+ expect(utils.dateToYearMonthDate(date)).toEqual(expectedOutput);
+ });
+
+ it('throws provided an invalid date', () => {
+ expect(() => utils.dateToYearMonthDate('Invalid date')).toThrow(
+ 'Argument should be a Date instance',
+ );
+ });
+ });
+
+ describe('timeToHoursMinutes', () => {
+ it.each`
+ time | expectedOutput
+ ${'23:12'} | ${{ hours: '23', minutes: '12' }}
+ ${'23:12'} | ${{ hours: '23', minutes: '12' }}
+ `('returns $expectedOutput provided $time', ({ time, expectedOutput }) => {
+ expect(utils.timeToHoursMinutes(time)).toEqual(expectedOutput);
+ });
+
+ it('throws provided an invalid time', () => {
+ expect(() => utils.timeToHoursMinutes('Invalid time')).toThrow('Invalid time provided');
+ });
+ });
+
+ describe('dateAndTimeToISOString', () => {
+ it('computes the date properly', () => {
+ expect(utils.dateAndTimeToISOString(new Date('2021-08-16'), '10:00')).toBe(
+ '2021-08-16T10:00:00.000Z',
+ );
+ });
+
+ it('computes the date properly with an offset', () => {
+ expect(utils.dateAndTimeToISOString(new Date('2021-08-16'), '10:00', '-04:00')).toBe(
+ '2021-08-16T10:00:00.000-04:00',
+ );
+ });
+
+ it('throws if date in invalid', () => {
+ expect(() => utils.dateAndTimeToISOString('Invalid date', '10:00')).toThrow(
+ 'Argument should be a Date instance',
+ );
+ });
+
+ it('throws if time in invalid', () => {
+ expect(() => utils.dateAndTimeToISOString(new Date('2021-08-16'), '')).toThrow(
+ 'Invalid time provided',
+ );
+ });
+
+ it('throws if offset is invalid', () => {
+ expect(() =>
+ utils.dateAndTimeToISOString(new Date('2021-08-16'), '10:00', 'not an offset'),
+ ).toThrow('Could not initialize date');
+ });
+ });
+
+ describe('dateToTimeInputValue', () => {
+ it.each`
+ input | expectedOutput
+ ${new Date('2021-08-16T10:00:00.000Z')} | ${'10:00'}
+ ${new Date('2021-08-16T22:30:00.000Z')} | ${'22:30'}
+ ${new Date('2021-08-16T22:30:00.000-03:00')} | ${'01:30'}
+ `('extracts $expectedOutput out of $input', ({ input, expectedOutput }) => {
+ expect(utils.dateToTimeInputValue(input)).toBe(expectedOutput);
+ });
+
+ it('throws if date is invalid', () => {
+ expect(() => utils.dateToTimeInputValue('Invalid date')).toThrow(
+ 'Argument should be a Date instance',
+ );
+ });
+ });
+});
diff --git a/spec/frontend/lib/utils/dom_utils_spec.js b/spec/frontend/lib/utils/dom_utils_spec.js
index 7c4c20e651f..cb8b1c7ca9a 100644
--- a/spec/frontend/lib/utils/dom_utils_spec.js
+++ b/spec/frontend/lib/utils/dom_utils_spec.js
@@ -5,6 +5,7 @@ import {
parseBooleanDataAttributes,
isElementVisible,
isElementHidden,
+ getParents,
} from '~/lib/utils/dom_utils';
const TEST_MARGIN = 5;
@@ -193,4 +194,18 @@ describe('DOM Utils', () => {
});
},
);
+
+ describe('getParents', () => {
+ it('gets all parents of an element', () => {
+ const el = document.createElement('div');
+ el.innerHTML = '<p><span><strong><mark>hello world';
+
+ expect(getParents(el.querySelector('mark'))).toEqual([
+ el.querySelector('strong'),
+ el.querySelector('span'),
+ el.querySelector('p'),
+ el,
+ ]);
+ });
+ });
});
diff --git a/spec/frontend/lib/utils/text_markdown_spec.js b/spec/frontend/lib/utils/text_markdown_spec.js
index beedb9b2eba..acbf1a975b8 100644
--- a/spec/frontend/lib/utils/text_markdown_spec.js
+++ b/spec/frontend/lib/utils/text_markdown_spec.js
@@ -88,6 +88,25 @@ describe('init markdown', () => {
expect(textArea.value).toEqual(`${initialValue}\n- `);
});
+ it('unescapes new line characters', () => {
+ const initialValue = '';
+
+ textArea.value = initialValue;
+ textArea.selectionStart = 0;
+ textArea.selectionEnd = 0;
+
+ insertMarkdownText({
+ textArea,
+ text: textArea.value,
+ tag: '```suggestion:-0+0\n{text}\n```',
+ blockTag: true,
+ selected: '# Does not parse the %br currently.',
+ wrap: false,
+ });
+
+ expect(textArea.value).toContain('# Does not parse the \\n currently.');
+ });
+
it('inserts the tag on the same line if the current line only contains spaces', () => {
const initialValue = ' ';
diff --git a/spec/frontend/lib/utils/url_utility_spec.js b/spec/frontend/lib/utils/url_utility_spec.js
index c8ac7ffc9d9..6f186ba3227 100644
--- a/spec/frontend/lib/utils/url_utility_spec.js
+++ b/spec/frontend/lib/utils/url_utility_spec.js
@@ -645,29 +645,6 @@ describe('URL utility', () => {
});
});
- describe('urlParamsToObject', () => {
- it('parses path for label with trailing +', () => {
- // eslint-disable-next-line import/no-deprecated
- expect(urlUtils.urlParamsToObject('label_name[]=label%2B', {})).toEqual({
- label_name: ['label+'],
- });
- });
-
- it('parses path for milestone with trailing +', () => {
- // eslint-disable-next-line import/no-deprecated
- expect(urlUtils.urlParamsToObject('milestone_title=A%2B', {})).toEqual({
- milestone_title: 'A+',
- });
- });
-
- it('parses path for search terms with spaces', () => {
- // eslint-disable-next-line import/no-deprecated
- expect(urlUtils.urlParamsToObject('search=two+words', {})).toEqual({
- search: 'two words',
- });
- });
- });
-
describe('queryToObject', () => {
it.each`
case | query | options | result