diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-28 12:09:05 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-28 12:09:05 +0000 |
commit | 5426ca9908085087d465fa52800335f408eb965a (patch) | |
tree | 6b442cff02fda9402fc7bb9cf9986e363dd5aaa6 /spec | |
parent | 67cdfd2683b89bce260600fa8925eefdcdf9e3e5 (diff) | |
download | gitlab-ce-5426ca9908085087d465fa52800335f408eb965a.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
12 files changed, 560 insertions, 314 deletions
diff --git a/spec/fixtures/api/schemas/public_api/v4/deploy_token.json b/spec/fixtures/api/schemas/public_api/v4/deploy_token.json new file mode 100644 index 00000000000..c8a8b8d1e7d --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/deploy_token.json @@ -0,0 +1,31 @@ +{ + "type": "object", + "required": [ + "id", + "name", + "username", + "expires_at", + "scopes" + ], + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "username": { + "type": "string" + }, + "expires_at": { + "type": "date" + }, + "scopes": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false +}
\ No newline at end of file diff --git a/spec/fixtures/api/schemas/public_api/v4/deploy_tokens.json b/spec/fixtures/api/schemas/public_api/v4/deploy_tokens.json new file mode 100644 index 00000000000..71c30cb2a73 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/deploy_tokens.json @@ -0,0 +1,6 @@ +{ + "type": "array", + "items": { + "$ref": "deploy_token.json" + } +}
\ No newline at end of file diff --git a/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js b/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js index 925699f5623..ab5784b8f7a 100644 --- a/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js +++ b/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js @@ -1,9 +1,7 @@ import { shallowMount } from '@vue/test-utils'; import { trimText } from 'helpers/text_helper'; import frequentItemsListItemComponent from '~/frequent_items/components/frequent_items_list_item.vue'; -import mockData from '../mock_data'; // can also use 'mockGroup', but not useful to test here - -const mockProject = mockData(); +import { mockProject } from '../mock_data'; // can also use 'mockGroup', but not useful to test here describe('FrequentItemsListItemComponent', () => { let wrapper; diff --git a/spec/frontend/frequent_items/components/frequent_items_list_spec.js b/spec/frontend/frequent_items/components/frequent_items_list_spec.js new file mode 100644 index 00000000000..238fd508053 --- /dev/null +++ b/spec/frontend/frequent_items/components/frequent_items_list_spec.js @@ -0,0 +1,101 @@ +import { mount } from '@vue/test-utils'; +import frequentItemsListComponent from '~/frequent_items/components/frequent_items_list.vue'; +import frequentItemsListItemComponent from '~/frequent_items/components/frequent_items_list_item.vue'; +import { mockFrequentProjects } from '../mock_data'; + +describe('FrequentItemsListComponent', () => { + let wrapper; + + const createComponent = (props = {}) => { + wrapper = mount(frequentItemsListComponent, { + propsData: { + namespace: 'projects', + items: mockFrequentProjects, + isFetchFailed: false, + hasSearchQuery: false, + matcher: 'lab', + ...props, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + describe('computed', () => { + describe('isListEmpty', () => { + it('should return `true` or `false` representing whether if `items` is empty or not with projects', () => { + createComponent({ + items: [], + }); + + expect(wrapper.vm.isListEmpty).toBe(true); + + wrapper.setProps({ + items: mockFrequentProjects, + }); + + expect(wrapper.vm.isListEmpty).toBe(false); + }); + }); + + describe('fetched item messages', () => { + it('should return appropriate empty list message based on value of `localStorageFailed` prop with projects', () => { + createComponent({ + isFetchFailed: true, + }); + + expect(wrapper.vm.listEmptyMessage).toBe( + 'This feature requires browser localStorage support', + ); + + wrapper.setProps({ + isFetchFailed: false, + }); + + expect(wrapper.vm.listEmptyMessage).toBe('Projects you visit often will appear here'); + }); + }); + + describe('searched item messages', () => { + it('should return appropriate empty list message based on value of `searchFailed` prop with projects', () => { + createComponent({ + hasSearchQuery: true, + isFetchFailed: true, + }); + + expect(wrapper.vm.listEmptyMessage).toBe('Something went wrong on our end.'); + + wrapper.setProps({ + isFetchFailed: false, + }); + + expect(wrapper.vm.listEmptyMessage).toBe('Sorry, no projects matched your search'); + }); + }); + }); + + describe('template', () => { + it('should render component element with list of projects', () => { + createComponent(); + + return wrapper.vm.$nextTick(() => { + expect(wrapper.classes('frequent-items-list-container')).toBe(true); + expect(wrapper.findAll({ ref: 'frequentItemsList' })).toHaveLength(1); + expect(wrapper.findAll(frequentItemsListItemComponent)).toHaveLength(5); + }); + }); + + it('should render component element with empty message', () => { + createComponent({ + items: [], + }); + + return wrapper.vm.$nextTick(() => { + expect(wrapper.vm.$el.querySelectorAll('li.section-empty')).toHaveLength(1); + expect(wrapper.findAll(frequentItemsListItemComponent)).toHaveLength(0); + }); + }); + }); +}); diff --git a/spec/frontend/frequent_items/mock_data.js b/spec/frontend/frequent_items/mock_data.js index 81f34053543..5cd4cddd877 100644 --- a/spec/frontend/frequent_items/mock_data.js +++ b/spec/frontend/frequent_items/mock_data.js @@ -1,9 +1,57 @@ import { TEST_HOST } from 'helpers/test_constants'; -export default () => ({ +export const mockFrequentProjects = [ + { + id: 1, + name: 'GitLab Community Edition', + namespace: 'gitlab-org / gitlab-ce', + webUrl: `${TEST_HOST}/gitlab-org/gitlab-foss`, + avatarUrl: null, + frequency: 1, + lastAccessedOn: Date.now(), + }, + { + id: 2, + name: 'GitLab CI', + namespace: 'gitlab-org / gitlab-ci', + webUrl: `${TEST_HOST}/gitlab-org/gitlab-ci`, + avatarUrl: null, + frequency: 9, + lastAccessedOn: Date.now(), + }, + { + id: 3, + name: 'Typeahead.Js', + namespace: 'twitter / typeahead-js', + webUrl: `${TEST_HOST}/twitter/typeahead-js`, + avatarUrl: '/uploads/-/system/project/avatar/7/TWBS.png', + frequency: 2, + lastAccessedOn: Date.now(), + }, + { + id: 4, + name: 'Intel', + namespace: 'platform / hardware / bsp / intel', + webUrl: `${TEST_HOST}/platform/hardware/bsp/intel`, + avatarUrl: null, + frequency: 3, + lastAccessedOn: Date.now(), + }, + { + id: 5, + name: 'v4.4', + namespace: 'platform / hardware / bsp / kernel / common / v4.4', + webUrl: `${TEST_HOST}/platform/hardware/bsp/kernel/common/v4.4`, + avatarUrl: null, + frequency: 8, + lastAccessedOn: Date.now(), + }, +]; + +export const mockProject = { id: 1, name: 'GitLab Community Edition', namespace: 'gitlab-org / gitlab-ce', webUrl: `${TEST_HOST}/gitlab-org/gitlab-foss`, avatarUrl: null, -}); +}; diff --git a/spec/frontend/lib/utils/unit_format/formatter_factory_spec.js b/spec/frontend/lib/utils/unit_format/formatter_factory_spec.js index 071ecde6a6d..26b942c3567 100644 --- a/spec/frontend/lib/utils/unit_format/formatter_factory_spec.js +++ b/spec/frontend/lib/utils/unit_format/formatter_factory_spec.js @@ -2,6 +2,7 @@ import { numberFormatter, suffixFormatter, scaledSIFormatter, + scaledBinaryFormatter, } from '~/lib/utils/unit_format/formatter_factory'; describe('unit_format/formatter_factory', () => { @@ -12,28 +13,28 @@ describe('unit_format/formatter_factory', () => { }); it('formats a integer', () => { - expect(formatNumber(1)).toEqual('1'); - expect(formatNumber(100)).toEqual('100'); - expect(formatNumber(1000)).toEqual('1,000'); - expect(formatNumber(10000)).toEqual('10,000'); - expect(formatNumber(1000000)).toEqual('1,000,000'); + expect(formatNumber(1)).toBe('1'); + expect(formatNumber(100)).toBe('100'); + expect(formatNumber(1000)).toBe('1,000'); + expect(formatNumber(10000)).toBe('10,000'); + expect(formatNumber(1000000)).toBe('1,000,000'); }); it('formats a floating point number', () => { - expect(formatNumber(0.1)).toEqual('0.1'); - expect(formatNumber(0.1, 0)).toEqual('0'); - expect(formatNumber(0.1, 2)).toEqual('0.10'); - expect(formatNumber(0.1, 3)).toEqual('0.100'); + expect(formatNumber(0.1)).toBe('0.1'); + expect(formatNumber(0.1, 0)).toBe('0'); + expect(formatNumber(0.1, 2)).toBe('0.10'); + expect(formatNumber(0.1, 3)).toBe('0.100'); - expect(formatNumber(12.345)).toEqual('12.345'); - expect(formatNumber(12.345, 2)).toEqual('12.35'); - expect(formatNumber(12.345, 4)).toEqual('12.3450'); + expect(formatNumber(12.345)).toBe('12.345'); + expect(formatNumber(12.345, 2)).toBe('12.35'); + expect(formatNumber(12.345, 4)).toBe('12.3450'); }); it('formats a large integer with a length limit', () => { - expect(formatNumber(10 ** 7, undefined)).toEqual('10,000,000'); - expect(formatNumber(10 ** 7, undefined, 9)).toEqual('1.00e+7'); - expect(formatNumber(10 ** 7, undefined, 10)).toEqual('10,000,000'); + expect(formatNumber(10 ** 7, undefined)).toBe('10,000,000'); + expect(formatNumber(10 ** 7, undefined, 9)).toBe('1.00e+7'); + expect(formatNumber(10 ** 7, undefined, 10)).toBe('10,000,000'); }); }); @@ -44,112 +45,112 @@ describe('unit_format/formatter_factory', () => { }); it('formats a integer', () => { - expect(formatSuffix(1)).toEqual('1pop.'); - expect(formatSuffix(100)).toEqual('100pop.'); - expect(formatSuffix(1000)).toEqual('1,000pop.'); - expect(formatSuffix(10000)).toEqual('10,000pop.'); - expect(formatSuffix(1000000)).toEqual('1,000,000pop.'); + expect(formatSuffix(1)).toBe('1pop.'); + expect(formatSuffix(100)).toBe('100pop.'); + expect(formatSuffix(1000)).toBe('1,000pop.'); + expect(formatSuffix(10000)).toBe('10,000pop.'); + expect(formatSuffix(1000000)).toBe('1,000,000pop.'); }); it('formats a floating point number', () => { - expect(formatSuffix(0.1)).toEqual('0.1pop.'); - expect(formatSuffix(0.1, 0)).toEqual('0pop.'); - expect(formatSuffix(0.1, 2)).toEqual('0.10pop.'); - expect(formatSuffix(0.1, 3)).toEqual('0.100pop.'); + expect(formatSuffix(0.1)).toBe('0.1pop.'); + expect(formatSuffix(0.1, 0)).toBe('0pop.'); + expect(formatSuffix(0.1, 2)).toBe('0.10pop.'); + expect(formatSuffix(0.1, 3)).toBe('0.100pop.'); - expect(formatSuffix(12.345)).toEqual('12.345pop.'); - expect(formatSuffix(12.345, 2)).toEqual('12.35pop.'); - expect(formatSuffix(12.345, 4)).toEqual('12.3450pop.'); + expect(formatSuffix(12.345)).toBe('12.345pop.'); + expect(formatSuffix(12.345, 2)).toBe('12.35pop.'); + expect(formatSuffix(12.345, 4)).toBe('12.3450pop.'); }); it('formats a negative integer', () => { - expect(formatSuffix(-1)).toEqual('-1pop.'); - expect(formatSuffix(-100)).toEqual('-100pop.'); - expect(formatSuffix(-1000)).toEqual('-1,000pop.'); - expect(formatSuffix(-10000)).toEqual('-10,000pop.'); - expect(formatSuffix(-1000000)).toEqual('-1,000,000pop.'); + expect(formatSuffix(-1)).toBe('-1pop.'); + expect(formatSuffix(-100)).toBe('-100pop.'); + expect(formatSuffix(-1000)).toBe('-1,000pop.'); + expect(formatSuffix(-10000)).toBe('-10,000pop.'); + expect(formatSuffix(-1000000)).toBe('-1,000,000pop.'); }); it('formats a floating point nugative number', () => { - expect(formatSuffix(-0.1)).toEqual('-0.1pop.'); - expect(formatSuffix(-0.1, 0)).toEqual('-0pop.'); - expect(formatSuffix(-0.1, 2)).toEqual('-0.10pop.'); - expect(formatSuffix(-0.1, 3)).toEqual('-0.100pop.'); + expect(formatSuffix(-0.1)).toBe('-0.1pop.'); + expect(formatSuffix(-0.1, 0)).toBe('-0pop.'); + expect(formatSuffix(-0.1, 2)).toBe('-0.10pop.'); + expect(formatSuffix(-0.1, 3)).toBe('-0.100pop.'); - expect(formatSuffix(-12.345)).toEqual('-12.345pop.'); - expect(formatSuffix(-12.345, 2)).toEqual('-12.35pop.'); - expect(formatSuffix(-12.345, 4)).toEqual('-12.3450pop.'); + expect(formatSuffix(-12.345)).toBe('-12.345pop.'); + expect(formatSuffix(-12.345, 2)).toBe('-12.35pop.'); + expect(formatSuffix(-12.345, 4)).toBe('-12.3450pop.'); }); it('formats a large integer', () => { - expect(formatSuffix(10 ** 7)).toEqual('10,000,000pop.'); - expect(formatSuffix(10 ** 10)).toEqual('10,000,000,000pop.'); + expect(formatSuffix(10 ** 7)).toBe('10,000,000pop.'); + expect(formatSuffix(10 ** 10)).toBe('10,000,000,000pop.'); }); it('formats a large integer with a length limit', () => { - expect(formatSuffix(10 ** 7, undefined, 10)).toEqual('1.00e+7pop.'); - expect(formatSuffix(10 ** 10, undefined, 10)).toEqual('1.00e+10pop.'); + expect(formatSuffix(10 ** 7, undefined, 10)).toBe('1.00e+7pop.'); + expect(formatSuffix(10 ** 10, undefined, 10)).toBe('1.00e+10pop.'); }); }); describe('scaledSIFormatter', () => { describe('scaled format', () => { - let formatScaled; + let formatGibibytes; beforeEach(() => { - formatScaled = scaledSIFormatter('B'); + formatGibibytes = scaledSIFormatter('B'); }); it('formats bytes', () => { - expect(formatScaled(12.345)).toEqual('12.345B'); - expect(formatScaled(12.345, 0)).toEqual('12B'); - expect(formatScaled(12.345, 1)).toEqual('12.3B'); - expect(formatScaled(12.345, 2)).toEqual('12.35B'); + expect(formatGibibytes(12.345)).toBe('12.345B'); + expect(formatGibibytes(12.345, 0)).toBe('12B'); + expect(formatGibibytes(12.345, 1)).toBe('12.3B'); + expect(formatGibibytes(12.345, 2)).toBe('12.35B'); }); - it('formats bytes in a scale', () => { - expect(formatScaled(1)).toEqual('1B'); - expect(formatScaled(10)).toEqual('10B'); - expect(formatScaled(10 ** 2)).toEqual('100B'); - expect(formatScaled(10 ** 3)).toEqual('1kB'); - expect(formatScaled(10 ** 4)).toEqual('10kB'); - expect(formatScaled(10 ** 5)).toEqual('100kB'); - expect(formatScaled(10 ** 6)).toEqual('1MB'); - expect(formatScaled(10 ** 7)).toEqual('10MB'); - expect(formatScaled(10 ** 8)).toEqual('100MB'); - expect(formatScaled(10 ** 9)).toEqual('1GB'); - expect(formatScaled(10 ** 10)).toEqual('10GB'); - expect(formatScaled(10 ** 11)).toEqual('100GB'); + it('formats bytes in a decimal scale', () => { + expect(formatGibibytes(1)).toBe('1B'); + expect(formatGibibytes(10)).toBe('10B'); + expect(formatGibibytes(10 ** 2)).toBe('100B'); + expect(formatGibibytes(10 ** 3)).toBe('1kB'); + expect(formatGibibytes(10 ** 4)).toBe('10kB'); + expect(formatGibibytes(10 ** 5)).toBe('100kB'); + expect(formatGibibytes(10 ** 6)).toBe('1MB'); + expect(formatGibibytes(10 ** 7)).toBe('10MB'); + expect(formatGibibytes(10 ** 8)).toBe('100MB'); + expect(formatGibibytes(10 ** 9)).toBe('1GB'); + expect(formatGibibytes(10 ** 10)).toBe('10GB'); + expect(formatGibibytes(10 ** 11)).toBe('100GB'); }); }); describe('scaled format with offset', () => { - let formatScaled; + let formatGigaBytes; beforeEach(() => { // formats gigabytes - formatScaled = scaledSIFormatter('B', 3); + formatGigaBytes = scaledSIFormatter('B', 3); }); it('formats floating point numbers', () => { - expect(formatScaled(12.345)).toEqual('12.345GB'); - expect(formatScaled(12.345, 0)).toEqual('12GB'); - expect(formatScaled(12.345, 1)).toEqual('12.3GB'); - expect(formatScaled(12.345, 2)).toEqual('12.35GB'); + expect(formatGigaBytes(12.345)).toBe('12.345GB'); + expect(formatGigaBytes(12.345, 0)).toBe('12GB'); + expect(formatGigaBytes(12.345, 1)).toBe('12.3GB'); + expect(formatGigaBytes(12.345, 2)).toBe('12.35GB'); }); it('formats large numbers scaled', () => { - expect(formatScaled(1)).toEqual('1GB'); - expect(formatScaled(1, 1)).toEqual('1.0GB'); - expect(formatScaled(10)).toEqual('10GB'); - expect(formatScaled(10 ** 2)).toEqual('100GB'); - expect(formatScaled(10 ** 3)).toEqual('1TB'); - expect(formatScaled(10 ** 4)).toEqual('10TB'); - expect(formatScaled(10 ** 5)).toEqual('100TB'); - expect(formatScaled(10 ** 6)).toEqual('1PB'); - expect(formatScaled(10 ** 7)).toEqual('10PB'); - expect(formatScaled(10 ** 8)).toEqual('100PB'); - expect(formatScaled(10 ** 9)).toEqual('1EB'); + expect(formatGigaBytes(1)).toBe('1GB'); + expect(formatGigaBytes(1, 1)).toBe('1.0GB'); + expect(formatGigaBytes(10)).toBe('10GB'); + expect(formatGigaBytes(10 ** 2)).toBe('100GB'); + expect(formatGigaBytes(10 ** 3)).toBe('1TB'); + expect(formatGigaBytes(10 ** 4)).toBe('10TB'); + expect(formatGigaBytes(10 ** 5)).toBe('100TB'); + expect(formatGigaBytes(10 ** 6)).toBe('1PB'); + expect(formatGigaBytes(10 ** 7)).toBe('10PB'); + expect(formatGigaBytes(10 ** 8)).toBe('100PB'); + expect(formatGigaBytes(10 ** 9)).toBe('1EB'); }); it('formatting of too large numbers is not suported', () => { @@ -159,41 +160,116 @@ describe('unit_format/formatter_factory', () => { }); describe('scaled format with negative offset', () => { - let formatScaled; + let formatMilligrams; beforeEach(() => { - formatScaled = scaledSIFormatter('g', -1); + formatMilligrams = scaledSIFormatter('g', -1); }); it('formats floating point numbers', () => { - expect(formatScaled(12.345)).toEqual('12.345mg'); - expect(formatScaled(12.345, 0)).toEqual('12mg'); - expect(formatScaled(12.345, 1)).toEqual('12.3mg'); - expect(formatScaled(12.345, 2)).toEqual('12.35mg'); + expect(formatMilligrams(1.0)).toBe('1mg'); + expect(formatMilligrams(12.345)).toBe('12.345mg'); + expect(formatMilligrams(12.345, 0)).toBe('12mg'); + expect(formatMilligrams(12.345, 1)).toBe('12.3mg'); + expect(formatMilligrams(12.345, 2)).toBe('12.35mg'); }); it('formats large numbers scaled', () => { - expect(formatScaled(1)).toEqual('1mg'); - expect(formatScaled(1, 1)).toEqual('1.0mg'); - expect(formatScaled(10)).toEqual('10mg'); - expect(formatScaled(10 ** 2)).toEqual('100mg'); - expect(formatScaled(10 ** 3)).toEqual('1g'); - expect(formatScaled(10 ** 4)).toEqual('10g'); - expect(formatScaled(10 ** 5)).toEqual('100g'); - expect(formatScaled(10 ** 6)).toEqual('1kg'); - expect(formatScaled(10 ** 7)).toEqual('10kg'); - expect(formatScaled(10 ** 8)).toEqual('100kg'); + expect(formatMilligrams(10)).toBe('10mg'); + expect(formatMilligrams(10 ** 2)).toBe('100mg'); + expect(formatMilligrams(10 ** 3)).toBe('1g'); + expect(formatMilligrams(10 ** 4)).toBe('10g'); + expect(formatMilligrams(10 ** 5)).toBe('100g'); + expect(formatMilligrams(10 ** 6)).toBe('1kg'); + expect(formatMilligrams(10 ** 7)).toBe('10kg'); + expect(formatMilligrams(10 ** 8)).toBe('100kg'); }); it('formats negative numbers scaled', () => { - expect(formatScaled(-12.345)).toEqual('-12.345mg'); - expect(formatScaled(-12.345, 0)).toEqual('-12mg'); - expect(formatScaled(-12.345, 1)).toEqual('-12.3mg'); - expect(formatScaled(-12.345, 2)).toEqual('-12.35mg'); - - expect(formatScaled(-10)).toEqual('-10mg'); - expect(formatScaled(-100)).toEqual('-100mg'); - expect(formatScaled(-(10 ** 4))).toEqual('-10g'); + expect(formatMilligrams(-12.345)).toBe('-12.345mg'); + expect(formatMilligrams(-12.345, 0)).toBe('-12mg'); + expect(formatMilligrams(-12.345, 1)).toBe('-12.3mg'); + expect(formatMilligrams(-12.345, 2)).toBe('-12.35mg'); + + expect(formatMilligrams(-10)).toBe('-10mg'); + expect(formatMilligrams(-100)).toBe('-100mg'); + expect(formatMilligrams(-(10 ** 4))).toBe('-10g'); + }); + }); + }); + + describe('scaledBinaryFormatter', () => { + describe('scaled format', () => { + let formatScaledBin; + + beforeEach(() => { + formatScaledBin = scaledBinaryFormatter('B'); + }); + + it('formats bytes', () => { + expect(formatScaledBin(12.345)).toBe('12.345B'); + expect(formatScaledBin(12.345, 0)).toBe('12B'); + expect(formatScaledBin(12.345, 1)).toBe('12.3B'); + expect(formatScaledBin(12.345, 2)).toBe('12.35B'); + }); + + it('formats bytes in a binary scale', () => { + expect(formatScaledBin(1)).toBe('1B'); + expect(formatScaledBin(10)).toBe('10B'); + expect(formatScaledBin(100)).toBe('100B'); + expect(formatScaledBin(1000)).toBe('1,000B'); + expect(formatScaledBin(10000)).toBe('9.766KiB'); + + expect(formatScaledBin(1 * 1024)).toBe('1KiB'); + expect(formatScaledBin(10 * 1024)).toBe('10KiB'); + expect(formatScaledBin(100 * 1024)).toBe('100KiB'); + + expect(formatScaledBin(1 * 1024 ** 2)).toBe('1MiB'); + expect(formatScaledBin(10 * 1024 ** 2)).toBe('10MiB'); + expect(formatScaledBin(100 * 1024 ** 2)).toBe('100MiB'); + + expect(formatScaledBin(1 * 1024 ** 3)).toBe('1GiB'); + expect(formatScaledBin(10 * 1024 ** 3)).toBe('10GiB'); + expect(formatScaledBin(100 * 1024 ** 3)).toBe('100GiB'); + }); + }); + + describe('scaled format with offset', () => { + let formatGibibytes; + + beforeEach(() => { + formatGibibytes = scaledBinaryFormatter('B', 3); + }); + + it('formats floating point numbers', () => { + expect(formatGibibytes(12.888)).toBe('12.888GiB'); + expect(formatGibibytes(12.888, 0)).toBe('13GiB'); + expect(formatGibibytes(12.888, 1)).toBe('12.9GiB'); + expect(formatGibibytes(12.888, 2)).toBe('12.89GiB'); + }); + + it('formats large numbers scaled', () => { + expect(formatGibibytes(1)).toBe('1GiB'); + expect(formatGibibytes(10)).toBe('10GiB'); + expect(formatGibibytes(100)).toBe('100GiB'); + expect(formatGibibytes(1000)).toBe('1,000GiB'); + + expect(formatGibibytes(1 * 1024)).toBe('1TiB'); + expect(formatGibibytes(10 * 1024)).toBe('10TiB'); + expect(formatGibibytes(100 * 1024)).toBe('100TiB'); + + expect(formatGibibytes(1 * 1024 ** 2)).toBe('1PiB'); + expect(formatGibibytes(10 * 1024 ** 2)).toBe('10PiB'); + expect(formatGibibytes(100 * 1024 ** 2)).toBe('100PiB'); + + expect(formatGibibytes(1 * 1024 ** 3)).toBe('1EiB'); + expect(formatGibibytes(10 * 1024 ** 3)).toBe('10EiB'); + expect(formatGibibytes(100 * 1024 ** 3)).toBe('100EiB'); + }); + + it('formatting of too large numbers is not suported', () => { + // formatting YB is out of range + expect(() => scaledBinaryFormatter('B', 9)).toThrow(); }); }); }); diff --git a/spec/frontend/lib/utils/unit_format/index_spec.js b/spec/frontend/lib/utils/unit_format/index_spec.js index e0991f2909b..5b2fdf1f02b 100644 --- a/spec/frontend/lib/utils/unit_format/index_spec.js +++ b/spec/frontend/lib/utils/unit_format/index_spec.js @@ -3,109 +3,149 @@ import { getFormatter, SUPPORTED_FORMATS } from '~/lib/utils/unit_format'; describe('unit_format', () => { describe('when a supported format is provided, the returned function formats', () => { it('numbers, by default', () => { - expect(getFormatter()(1)).toEqual('1'); + expect(getFormatter()(1)).toBe('1'); }); it('numbers', () => { const formatNumber = getFormatter(SUPPORTED_FORMATS.number); - expect(formatNumber(1)).toEqual('1'); - expect(formatNumber(100)).toEqual('100'); - expect(formatNumber(1000)).toEqual('1,000'); - expect(formatNumber(10000)).toEqual('10,000'); - expect(formatNumber(1000000)).toEqual('1,000,000'); + expect(formatNumber(1)).toBe('1'); + expect(formatNumber(100)).toBe('100'); + expect(formatNumber(1000)).toBe('1,000'); + expect(formatNumber(10000)).toBe('10,000'); + expect(formatNumber(1000000)).toBe('1,000,000'); }); it('percent', () => { const formatPercent = getFormatter(SUPPORTED_FORMATS.percent); - expect(formatPercent(1)).toEqual('100%'); - expect(formatPercent(1, 2)).toEqual('100.00%'); + expect(formatPercent(1)).toBe('100%'); + expect(formatPercent(1, 2)).toBe('100.00%'); - expect(formatPercent(0.1)).toEqual('10%'); - expect(formatPercent(0.5)).toEqual('50%'); + expect(formatPercent(0.1)).toBe('10%'); + expect(formatPercent(0.5)).toBe('50%'); - expect(formatPercent(0.888888)).toEqual('89%'); - expect(formatPercent(0.888888, 2)).toEqual('88.89%'); - expect(formatPercent(0.888888, 5)).toEqual('88.88880%'); + expect(formatPercent(0.888888)).toBe('89%'); + expect(formatPercent(0.888888, 2)).toBe('88.89%'); + expect(formatPercent(0.888888, 5)).toBe('88.88880%'); - expect(formatPercent(2)).toEqual('200%'); - expect(formatPercent(10)).toEqual('1,000%'); + expect(formatPercent(2)).toBe('200%'); + expect(formatPercent(10)).toBe('1,000%'); }); it('percentunit', () => { const formatPercentHundred = getFormatter(SUPPORTED_FORMATS.percentHundred); - expect(formatPercentHundred(1)).toEqual('1%'); - expect(formatPercentHundred(1, 2)).toEqual('1.00%'); + expect(formatPercentHundred(1)).toBe('1%'); + expect(formatPercentHundred(1, 2)).toBe('1.00%'); - expect(formatPercentHundred(88.8888)).toEqual('89%'); - expect(formatPercentHundred(88.8888, 2)).toEqual('88.89%'); - expect(formatPercentHundred(88.8888, 5)).toEqual('88.88880%'); + expect(formatPercentHundred(88.8888)).toBe('89%'); + expect(formatPercentHundred(88.8888, 2)).toBe('88.89%'); + expect(formatPercentHundred(88.8888, 5)).toBe('88.88880%'); - expect(formatPercentHundred(100)).toEqual('100%'); - expect(formatPercentHundred(100, 2)).toEqual('100.00%'); + expect(formatPercentHundred(100)).toBe('100%'); + expect(formatPercentHundred(100, 2)).toBe('100.00%'); - expect(formatPercentHundred(200)).toEqual('200%'); - expect(formatPercentHundred(1000)).toEqual('1,000%'); + expect(formatPercentHundred(200)).toBe('200%'); + expect(formatPercentHundred(1000)).toBe('1,000%'); }); it('seconds', () => { - expect(getFormatter(SUPPORTED_FORMATS.seconds)(1)).toEqual('1s'); + expect(getFormatter(SUPPORTED_FORMATS.seconds)(1)).toBe('1s'); }); - it('miliseconds', () => { - const formatMiliseconds = getFormatter(SUPPORTED_FORMATS.miliseconds); + it('milliseconds', () => { + const formatMilliseconds = getFormatter(SUPPORTED_FORMATS.milliseconds); - expect(formatMiliseconds(1)).toEqual('1ms'); - expect(formatMiliseconds(100)).toEqual('100ms'); - expect(formatMiliseconds(1000)).toEqual('1,000ms'); - expect(formatMiliseconds(10000)).toEqual('10,000ms'); - expect(formatMiliseconds(1000000)).toEqual('1,000,000ms'); + expect(formatMilliseconds(1)).toBe('1ms'); + expect(formatMilliseconds(100)).toBe('100ms'); + expect(formatMilliseconds(1000)).toBe('1,000ms'); + expect(formatMilliseconds(10000)).toBe('10,000ms'); + expect(formatMilliseconds(1000000)).toBe('1,000,000ms'); }); - it('bytes', () => { - const formatBytes = getFormatter(SUPPORTED_FORMATS.bytes); - - expect(formatBytes(1)).toEqual('1B'); - expect(formatBytes(1, 1)).toEqual('1.0B'); - - expect(formatBytes(10)).toEqual('10B'); - expect(formatBytes(10 ** 2)).toEqual('100B'); - expect(formatBytes(10 ** 3)).toEqual('1kB'); - expect(formatBytes(10 ** 4)).toEqual('10kB'); - expect(formatBytes(10 ** 5)).toEqual('100kB'); - expect(formatBytes(10 ** 6)).toEqual('1MB'); - expect(formatBytes(10 ** 7)).toEqual('10MB'); - expect(formatBytes(10 ** 8)).toEqual('100MB'); - expect(formatBytes(10 ** 9)).toEqual('1GB'); - expect(formatBytes(10 ** 10)).toEqual('10GB'); - expect(formatBytes(10 ** 11)).toEqual('100GB'); + it('decimalBytes', () => { + const formatDecimalBytes = getFormatter(SUPPORTED_FORMATS.decimalBytes); + + expect(formatDecimalBytes(1)).toBe('1B'); + expect(formatDecimalBytes(1, 1)).toBe('1.0B'); + + expect(formatDecimalBytes(10)).toBe('10B'); + expect(formatDecimalBytes(10 ** 2)).toBe('100B'); + expect(formatDecimalBytes(10 ** 3)).toBe('1kB'); + expect(formatDecimalBytes(10 ** 4)).toBe('10kB'); + expect(formatDecimalBytes(10 ** 5)).toBe('100kB'); + expect(formatDecimalBytes(10 ** 6)).toBe('1MB'); + expect(formatDecimalBytes(10 ** 7)).toBe('10MB'); + expect(formatDecimalBytes(10 ** 8)).toBe('100MB'); + expect(formatDecimalBytes(10 ** 9)).toBe('1GB'); + expect(formatDecimalBytes(10 ** 10)).toBe('10GB'); + expect(formatDecimalBytes(10 ** 11)).toBe('100GB'); }); it('kilobytes', () => { - expect(getFormatter(SUPPORTED_FORMATS.kilobytes)(1)).toEqual('1kB'); - expect(getFormatter(SUPPORTED_FORMATS.kilobytes)(1, 1)).toEqual('1.0kB'); + expect(getFormatter(SUPPORTED_FORMATS.kilobytes)(1)).toBe('1kB'); + expect(getFormatter(SUPPORTED_FORMATS.kilobytes)(1, 1)).toBe('1.0kB'); }); it('megabytes', () => { - expect(getFormatter(SUPPORTED_FORMATS.megabytes)(1)).toEqual('1MB'); - expect(getFormatter(SUPPORTED_FORMATS.megabytes)(1, 1)).toEqual('1.0MB'); + expect(getFormatter(SUPPORTED_FORMATS.megabytes)(1)).toBe('1MB'); + expect(getFormatter(SUPPORTED_FORMATS.megabytes)(1, 1)).toBe('1.0MB'); }); it('gigabytes', () => { - expect(getFormatter(SUPPORTED_FORMATS.gigabytes)(1)).toEqual('1GB'); - expect(getFormatter(SUPPORTED_FORMATS.gigabytes)(1, 1)).toEqual('1.0GB'); + expect(getFormatter(SUPPORTED_FORMATS.gigabytes)(1)).toBe('1GB'); + expect(getFormatter(SUPPORTED_FORMATS.gigabytes)(1, 1)).toBe('1.0GB'); }); it('terabytes', () => { - expect(getFormatter(SUPPORTED_FORMATS.terabytes)(1)).toEqual('1TB'); - expect(getFormatter(SUPPORTED_FORMATS.terabytes)(1, 1)).toEqual('1.0TB'); + expect(getFormatter(SUPPORTED_FORMATS.terabytes)(1)).toBe('1TB'); + expect(getFormatter(SUPPORTED_FORMATS.terabytes)(1, 1)).toBe('1.0TB'); }); it('petabytes', () => { - expect(getFormatter(SUPPORTED_FORMATS.petabytes)(1)).toEqual('1PB'); - expect(getFormatter(SUPPORTED_FORMATS.petabytes)(1, 1)).toEqual('1.0PB'); + expect(getFormatter(SUPPORTED_FORMATS.petabytes)(1)).toBe('1PB'); + expect(getFormatter(SUPPORTED_FORMATS.petabytes)(1, 1)).toBe('1.0PB'); + }); + + it('bytes', () => { + const formatBytes = getFormatter(SUPPORTED_FORMATS.bytes); + + expect(formatBytes(1)).toBe('1B'); + expect(formatBytes(1, 1)).toBe('1.0B'); + + expect(formatBytes(10)).toBe('10B'); + expect(formatBytes(100)).toBe('100B'); + expect(formatBytes(1000)).toBe('1,000B'); + + expect(formatBytes(1 * 1024)).toBe('1KiB'); + expect(formatBytes(1 * 1024 ** 2)).toBe('1MiB'); + expect(formatBytes(1 * 1024 ** 3)).toBe('1GiB'); + }); + + it('kibibytes', () => { + expect(getFormatter(SUPPORTED_FORMATS.kibibytes)(1)).toBe('1KiB'); + expect(getFormatter(SUPPORTED_FORMATS.kibibytes)(1, 1)).toBe('1.0KiB'); + }); + + it('mebibytes', () => { + expect(getFormatter(SUPPORTED_FORMATS.mebibytes)(1)).toBe('1MiB'); + expect(getFormatter(SUPPORTED_FORMATS.mebibytes)(1, 1)).toBe('1.0MiB'); + }); + + it('gibibytes', () => { + expect(getFormatter(SUPPORTED_FORMATS.gibibytes)(1)).toBe('1GiB'); + expect(getFormatter(SUPPORTED_FORMATS.gibibytes)(1, 1)).toBe('1.0GiB'); + }); + + it('tebibytes', () => { + expect(getFormatter(SUPPORTED_FORMATS.tebibytes)(1)).toBe('1TiB'); + expect(getFormatter(SUPPORTED_FORMATS.tebibytes)(1, 1)).toBe('1.0TiB'); + }); + + it('pebibytes', () => { + expect(getFormatter(SUPPORTED_FORMATS.pebibytes)(1)).toBe('1PiB'); + expect(getFormatter(SUPPORTED_FORMATS.pebibytes)(1, 1)).toBe('1.0PiB'); }); }); diff --git a/spec/frontend/notes/components/note_app_spec.js b/spec/frontend/notes/components/note_app_spec.js index a51c7c57f6c..2d0cca18647 100644 --- a/spec/frontend/notes/components/note_app_spec.js +++ b/spec/frontend/notes/components/note_app_spec.js @@ -5,7 +5,6 @@ import { mount } from '@vue/test-utils'; import { setTestTimeout } from 'helpers/timeout'; import axios from '~/lib/utils/axios_utils'; import NotesApp from '~/notes/components/notes_app.vue'; -import service from '~/notes/services/notes_service'; import createStore from '~/notes/stores'; import '~/behaviors/markdown/render_gfm'; // TODO: use generated fixture (https://gitlab.com/gitlab-org/gitlab-foss/issues/62491) @@ -192,7 +191,6 @@ describe('note_app', () => { describe('individual note', () => { beforeEach(() => { axiosMock.onAny().reply(mockData.getIndividualNoteResponse); - jest.spyOn(service, 'updateNote'); wrapper = mountComponent(); return waitForDiscussionsRequest().then(() => { wrapper.find('.js-note-edit').trigger('click'); @@ -203,18 +201,18 @@ describe('note_app', () => { expect(wrapper.find('.js-vue-issue-note-form').exists()).toBe(true); }); - it('calls the service to update the note', () => { + it('calls the store action to update the note', () => { + jest.spyOn(axios, 'put').mockImplementation(() => Promise.resolve({ data: {} })); wrapper.find('.js-vue-issue-note-form').value = 'this is a note'; wrapper.find('.js-vue-issue-save').trigger('click'); - expect(service.updateNote).toHaveBeenCalled(); + expect(axios.put).toHaveBeenCalled(); }); }); describe('discussion note', () => { beforeEach(() => { axiosMock.onAny().reply(mockData.getDiscussionNoteResponse); - jest.spyOn(service, 'updateNote'); wrapper = mountComponent(); return waitForDiscussionsRequest().then(() => { wrapper.find('.js-note-edit').trigger('click'); @@ -226,10 +224,11 @@ describe('note_app', () => { }); it('updates the note and resets the edit form', () => { + jest.spyOn(axios, 'put').mockImplementation(() => Promise.resolve({ data: {} })); wrapper.find('.js-vue-issue-note-form').value = 'this is a note'; wrapper.find('.js-vue-issue-save').trigger('click'); - expect(service.updateNote).toHaveBeenCalled(); + expect(axios.put).toHaveBeenCalled(); }); }); }); diff --git a/spec/javascripts/frequent_items/components/frequent_items_list_spec.js b/spec/javascripts/frequent_items/components/frequent_items_list_spec.js deleted file mode 100644 index 3fcd79480cc..00000000000 --- a/spec/javascripts/frequent_items/components/frequent_items_list_spec.js +++ /dev/null @@ -1,90 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import frequentItemsListComponent from '~/frequent_items/components/frequent_items_list.vue'; -import { mockFrequentProjects } from '../mock_data'; - -const createComponent = (namespace = 'projects') => { - const Component = Vue.extend(frequentItemsListComponent); - - return mountComponent(Component, { - namespace, - items: mockFrequentProjects, - isFetchFailed: false, - hasSearchQuery: false, - matcher: 'lab', - }); -}; - -describe('FrequentItemsListComponent', () => { - let vm; - - beforeEach(() => { - vm = createComponent(); - }); - - afterEach(() => { - vm.$destroy(); - }); - - describe('computed', () => { - describe('isListEmpty', () => { - it('should return `true` or `false` representing whether if `items` is empty or not with projects', () => { - vm.items = []; - - expect(vm.isListEmpty).toBe(true); - - vm.items = mockFrequentProjects; - - expect(vm.isListEmpty).toBe(false); - }); - }); - - describe('fetched item messages', () => { - it('should return appropriate empty list message based on value of `localStorageFailed` prop with projects', () => { - vm.isFetchFailed = true; - - expect(vm.listEmptyMessage).toBe('This feature requires browser localStorage support'); - - vm.isFetchFailed = false; - - expect(vm.listEmptyMessage).toBe('Projects you visit often will appear here'); - }); - }); - - describe('searched item messages', () => { - it('should return appropriate empty list message based on value of `searchFailed` prop with projects', () => { - vm.hasSearchQuery = true; - vm.isFetchFailed = true; - - expect(vm.listEmptyMessage).toBe('Something went wrong on our end.'); - - vm.isFetchFailed = false; - - expect(vm.listEmptyMessage).toBe('Sorry, no projects matched your search'); - }); - }); - }); - - describe('template', () => { - it('should render component element with list of projects', done => { - vm.items = mockFrequentProjects; - - Vue.nextTick(() => { - expect(vm.$el.classList.contains('frequent-items-list-container')).toBe(true); - expect(vm.$el.querySelectorAll('ul.list-unstyled').length).toBe(1); - expect(vm.$el.querySelectorAll('li.frequent-items-list-item-container').length).toBe(5); - done(); - }); - }); - - it('should render component element with empty message', done => { - vm.items = []; - - Vue.nextTick(() => { - expect(vm.$el.querySelectorAll('li.section-empty').length).toBe(1); - expect(vm.$el.querySelectorAll('li.frequent-items-list-item-container').length).toBe(0); - done(); - }); - }); - }); -}); diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index c0501fb16c6..dd1588036b6 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -178,67 +178,63 @@ describe Issue do let(:namespace) { build(:namespace, path: 'sample-namespace') } let(:project) { build(:project, name: 'sample-project', namespace: namespace) } let(:issue) { build(:issue, iid: 1, project: project) } - let(:group) { create(:group, name: 'Group', path: 'sample-group') } context 'when nil argument' do it 'returns issue id' do expect(issue.to_reference).to eq "#1" end - end - context 'when full is true' do - it 'returns complete path to the issue' do - expect(issue.to_reference(full: true)).to eq 'sample-namespace/sample-project#1' - expect(issue.to_reference(project, full: true)).to eq 'sample-namespace/sample-project#1' - expect(issue.to_reference(group, full: true)).to eq 'sample-namespace/sample-project#1' - end - end - - context 'when same project argument' do - it 'returns issue id' do - expect(issue.to_reference(project)).to eq("#1") + it 'returns complete path to the issue with full: true' do + expect(issue.to_reference(full: true)).to eq 'sample-namespace/sample-project#1' end end - context 'when cross namespace project argument' do - let(:another_namespace_project) { create(:project, name: 'another-project') } + context 'when argument is a project' do + context 'when same project' do + it 'returns issue id' do + expect(issue.to_reference(project)).to eq("#1") + end - it 'returns complete path to the issue' do - expect(issue.to_reference(another_namespace_project)).to eq 'sample-namespace/sample-project#1' + it 'returns full reference with full: true' do + expect(issue.to_reference(project, full: true)).to eq 'sample-namespace/sample-project#1' + end end - end - it 'supports a cross-project reference' do - another_project = build(:project, name: 'another-project', namespace: project.namespace) - expect(issue.to_reference(another_project)).to eq "sample-project#1" - end - - context 'when same namespace / cross-project argument' do - let(:another_project) { create(:project, namespace: namespace) } + context 'when cross-project in same namespace' do + let(:another_project) do + build(:project, name: 'another-project', namespace: project.namespace) + end - it 'returns path to the issue with the project name' do - expect(issue.to_reference(another_project)).to eq 'sample-project#1' + it 'returns a cross-project reference' do + expect(issue.to_reference(another_project)).to eq "sample-project#1" + end end - end - context 'when different namespace / cross-project argument' do - let(:another_namespace) { create(:namespace, path: 'another-namespace') } - let(:another_project) { create(:project, path: 'another-project', namespace: another_namespace) } + context 'when cross-project in different namespace' do + let(:another_namespace) { build(:namespace, path: 'another-namespace') } + let(:another_namespace_project) { build(:project, path: 'another-project', namespace: another_namespace) } - it 'returns full path to the issue' do - expect(issue.to_reference(another_project)).to eq 'sample-namespace/sample-project#1' + it 'returns complete path to the issue' do + expect(issue.to_reference(another_namespace_project)).to eq 'sample-namespace/sample-project#1' + end end end context 'when argument is a namespace' do - context 'with same project path' do + context 'when same as issue' do it 'returns path to the issue with the project name' do expect(issue.to_reference(namespace)).to eq 'sample-project#1' end + + it 'returns full reference with full: true' do + expect(issue.to_reference(namespace, full: true)).to eq 'sample-namespace/sample-project#1' + end end - context 'with different project path' do - it 'returns full path to the issue' do + context 'when different to issue namespace' do + let(:group) { build(:group, name: 'Group', path: 'sample-group') } + + it 'returns full path to the issue with full: true' do expect(issue.to_reference(group)).to eq 'sample-namespace/sample-project#1' end end diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index e1466ad2b73..635349955b1 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -52,7 +52,7 @@ describe ProjectPolicy do admin_snippet admin_project_member admin_note admin_wiki admin_project admin_commit_status admin_build admin_container_image admin_pipeline admin_environment admin_deployment destroy_release add_cluster - daily_statistics + daily_statistics read_deploy_token ] end diff --git a/spec/requests/api/deploy_tokens_spec.rb b/spec/requests/api/deploy_tokens_spec.rb index 0e3256edcd8..9aa181db7fc 100644 --- a/spec/requests/api/deploy_tokens_spec.rb +++ b/spec/requests/api/deploy_tokens_spec.rb @@ -3,43 +3,84 @@ require 'spec_helper' describe API::DeployTokens do + let(:user) { create(:user) } let(:creator) { create(:user) } let(:project) { create(:project, creator_id: creator.id) } let!(:deploy_token) { create(:deploy_token, projects: [project]) } describe 'GET /deploy_tokens' do - subject { get api('/deploy_tokens', user) } + subject do + get api('/deploy_tokens', user) + response + end context 'when unauthenticated' do let(:user) { nil } - it 'rejects the response as unauthorized' do - subject - - expect(response).to have_gitlab_http_status(:unauthorized) - end + it { is_expected.to have_gitlab_http_status(:unauthorized) } end context 'when authenticated as non-admin user' do let(:user) { creator } - it 'rejects the response as forbidden' do - subject - - expect(response).to have_gitlab_http_status(:forbidden) - end + it { is_expected.to have_gitlab_http_status(:forbidden) } end context 'when authenticated as admin' do let(:user) { create(:admin) } + it { is_expected.to have_gitlab_http_status(:ok) } + it 'returns all deploy tokens' do subject - expect(response).to have_gitlab_http_status(:ok) expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.first['id']).to eq(deploy_token.id) + expect(response).to match_response_schema('public_api/v4/deploy_tokens') + end + end + end + + describe 'GET /projects/:id/deploy_tokens' do + subject do + get api("/projects/#{project.id}/deploy_tokens", user) + response + end + + context 'when unauthenticated' do + let(:user) { nil } + + it { is_expected.to have_gitlab_http_status(:not_found) } + end + + context 'when authenticated as non-admin user' do + before do + project.add_developer(user) + end + + it { is_expected.to have_gitlab_http_status(:forbidden) } + end + + context 'when authenticated as maintainer' do + let!(:other_deploy_token) { create(:deploy_token) } + + before do + project.add_maintainer(user) + end + + it { is_expected.to have_gitlab_http_status(:ok) } + + it 'returns all deploy tokens for the project' do + subject + + expect(response).to include_pagination_headers + expect(response).to match_response_schema('public_api/v4/deploy_tokens') + end + + it 'does not return deploy tokens for other projects' do + subject + + token_ids = json_response.map { |token| token['id'] } + expect(token_ids).not_to include(other_deploy_token.id) end end end |