diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-10-17 12:07:33 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-10-17 12:07:33 +0000 |
commit | 6b75320f525f841454f1ab162d141d3610f2e77b (patch) | |
tree | 4971c27759e4fbc18b85e71800c3b9c12346317e /spec/frontend/registry | |
parent | 4226aca420920c1844e8eade4798a2dff188a6fc (diff) | |
download | gitlab-ce-6b75320f525f841454f1ab162d141d3610f2e77b.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/registry')
10 files changed, 477 insertions, 30 deletions
diff --git a/spec/frontend/registry/components/__snapshots__/group_empty_state_spec.js.snap b/spec/frontend/registry/components/__snapshots__/group_empty_state_spec.js.snap new file mode 100644 index 00000000000..3f13b7d4d76 --- /dev/null +++ b/spec/frontend/registry/components/__snapshots__/group_empty_state_spec.js.snap @@ -0,0 +1,61 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Registry Group Empty state to match the default snapshot 1`] = ` +<div + class="row container-message empty-state" +> + <div + class="col-12" + > + <div + class="svg-250 svg-content" + > + <img + alt="There are no container images available in this group" + class="" + src="imageUrl" + /> + </div> + </div> + + <div + class="col-12" + > + <div + class="text-content" + > + <h4 + class="center" + style="" + > + There are no container images available in this group + </h4> + + <p + class="center" + style="" + > + <p + class="js-no-container-images-text" + > + With the Container Registry, every project can have its own space to store its Docker images. Push at least one Docker image in one of this group's projects in order to show up here. + <a + href="help" + target="_blank" + > + More Information + </a> + </p> + </p> + + <div + class="text-center" + > + <!----> + + <!----> + </div> + </div> + </div> +</div> +`; diff --git a/spec/frontend/registry/components/__snapshots__/project_empty_state_spec.js.snap b/spec/frontend/registry/components/__snapshots__/project_empty_state_spec.js.snap new file mode 100644 index 00000000000..3084462f5ae --- /dev/null +++ b/spec/frontend/registry/components/__snapshots__/project_empty_state_spec.js.snap @@ -0,0 +1,186 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Registry Project Empty state to match the default snapshot 1`] = ` +<div + class="row container-message empty-state" +> + <div + class="col-12" + > + <div + class="svg-250 svg-content" + > + <img + alt="There are no container images stored for this project" + class="" + src="imageUrl" + /> + </div> + </div> + + <div + class="col-12" + > + <div + class="text-content" + > + <h4 + class="center" + style="" + > + There are no container images stored for this project + </h4> + + <p + class="center" + style="" + > + <p + class="js-no-container-images-text" + > + With the Container Registry, every project can have its own space to store its Docker images. + <a + href="help" + target="_blank" + > + More Information + </a> + </p> + + <h5> + Quick Start + </h5> + + <p + class="js-not-logged-in-to-registry-text" + > + If you are not already logged in, you need to authenticate to the Container Registry by using your GitLab username and password. If you have + <a + href="help_link" + target="_blank" + > + Two-Factor Authentication + </a> + enabled, use a + <a + href="personal_token" + target="_blank" + > + Personal Access Token + </a> + instead of a password. + </p> + + <div + class="input-group append-bottom-10" + > + <input + class="form-control monospace" + readonly="readonly" + type="text" + /> + + <span + class="input-group-append" + > + <button + class="btn input-group-text btn-secondary btn-default" + data-clipboard-text="docker login host" + data-original-title="Copy login command" + title="" + type="button" + > + <svg + aria-hidden="true" + class="s16 ic-duplicate" + > + <use + xlink:href="#duplicate" + /> + </svg> + </button> + </span> + </div> + + <p /> + + <p> + + You can add an image to this registry with the following commands: + + </p> + + <div + class="input-group append-bottom-10" + > + <input + class="form-control monospace" + readonly="readonly" + type="text" + /> + + <span + class="input-group-append" + > + <button + class="btn input-group-text btn-secondary btn-default" + data-clipboard-text="docker build -t url ." + data-original-title="Copy build command" + title="" + type="button" + > + <svg + aria-hidden="true" + class="s16 ic-duplicate" + > + <use + xlink:href="#duplicate" + /> + </svg> + </button> + </span> + </div> + + <div + class="input-group" + > + <input + class="form-control monospace" + readonly="readonly" + type="text" + /> + + <span + class="input-group-append" + > + <button + class="btn input-group-text btn-secondary btn-default" + data-clipboard-text="docker push url" + data-original-title="Copy push command" + title="" + type="button" + > + <svg + aria-hidden="true" + class="s16 ic-duplicate" + > + <use + xlink:href="#duplicate" + /> + </svg> + </button> + </span> + </div> + </p> + + <div + class="text-center" + > + <!----> + + <!----> + </div> + </div> + </div> +</div> +`; diff --git a/spec/frontend/registry/components/app_spec.js b/spec/frontend/registry/components/app_spec.js index 5dcb61e03b5..a69c33c246d 100644 --- a/spec/frontend/registry/components/app_spec.js +++ b/spec/frontend/registry/components/app_spec.js @@ -1,3 +1,4 @@ +import Vue from 'vue'; import { mount } from '@vue/test-utils'; import registry from '~/registry/components/app.vue'; import { TEST_HOST } from '../../helpers/test_constants'; @@ -7,8 +8,8 @@ describe('Registry List', () => { let wrapper; const findCollapsibleContainer = w => w.findAll({ name: 'CollapsibeContainerRegisty' }); - const findNoContainerImagesText = w => w.find('.js-no-container-images-text'); - const findNotLoggedInToRegistryText = w => w.find('.js-not-logged-in-to-registry-text'); + const findProjectEmptyState = w => w.find({ name: 'ProjectEmptyState' }); + const findGroupEmptyState = w => w.find({ name: 'GroupEmptyState' }); const findSpinner = w => w.find('.gl-spinner'); const findCharacterErrorText = w => w.find('.js-character-error-text'); @@ -25,13 +26,18 @@ describe('Registry List', () => { const setMainEndpoint = jest.fn(); const fetchRepos = jest.fn(); + const setIsDeleteDisabled = jest.fn(); const methods = { setMainEndpoint, fetchRepos, + setIsDeleteDisabled, }; beforeEach(() => { + // This is needed due to console.error called by vue to emit a warning that stop the tests. + // See https://github.com/vuejs/vue-test-utils/issues/532. + Vue.config.silent = true; wrapper = mount(registry, { propsData, computed: { @@ -43,6 +49,12 @@ describe('Registry List', () => { }); }); + afterEach(() => { + jest.clearAllMocks(); + Vue.config.silent = false; + wrapper.destroy(); + }); + describe('with data', () => { it('should render a list of CollapsibeContainerRegisty', () => { const containers = findCollapsibleContainer(wrapper); @@ -65,18 +77,9 @@ describe('Registry List', () => { }); }); - it('should render empty message', () => { - const noContainerImagesText = findNoContainerImagesText(localWrapper); - expect(noContainerImagesText.text()).toEqual( - 'With the Container Registry, every project can have its own space to store its Docker images. More Information', - ); - }); - - it('should render login help text', () => { - const notLoggedInToRegistryText = findNotLoggedInToRegistryText(localWrapper); - expect(notLoggedInToRegistryText.text()).toEqual( - 'If you are not already logged in, you need to authenticate to the Container Registry by using your GitLab username and password. If you have Two-Factor Authentication enabled, use a Personal Access Token instead of a password.', - ); + it('should render project empty message', () => { + const projectEmptyState = findProjectEmptyState(localWrapper); + expect(projectEmptyState.exists()).toBe(true); }); }); @@ -129,4 +132,29 @@ describe('Registry List', () => { ); }); }); + + describe('with groupId set', () => { + const isGroupPage = true; + + beforeEach(() => { + wrapper = mount(registry, { + propsData: { + ...propsData, + endpoint: null, + isGroupPage, + }, + methods, + }); + }); + + it('call the right vuex setters', () => { + expect(methods.setMainEndpoint).toHaveBeenLastCalledWith(null); + expect(methods.setIsDeleteDisabled).toHaveBeenLastCalledWith(true); + }); + + it('should render groups empty message', () => { + const groupEmptyState = findGroupEmptyState(wrapper); + expect(groupEmptyState.exists()).toBe(true); + }); + }); }); diff --git a/spec/frontend/registry/components/collapsible_container_spec.js b/spec/frontend/registry/components/collapsible_container_spec.js index 0fe4338f1ba..f93ebab1a4d 100644 --- a/spec/frontend/registry/components/collapsible_container_spec.js +++ b/spec/frontend/registry/components/collapsible_container_spec.js @@ -1,24 +1,40 @@ import Vue from 'vue'; -import { mount } from '@vue/test-utils'; +import Vuex from 'vuex'; +import { mount, createLocalVue } from '@vue/test-utils'; import collapsibleComponent from '~/registry/components/collapsible_container.vue'; import { repoPropsData } from '../mock_data'; import createFlash from '~/flash'; +import * as getters from '~/registry/stores/getters'; jest.mock('~/flash.js'); +const localVue = createLocalVue(); + +localVue.use(Vuex); + describe('collapsible registry container', () => { let wrapper; + let store; const findDeleteBtn = w => w.find('.js-remove-repo'); const findContainerImageTags = w => w.find('.container-image-tags'); const findToggleRepos = w => w.findAll('.js-toggle-repo'); + const mountWithStore = config => mount(collapsibleComponent, { ...config, store, localVue }); + beforeEach(() => { createFlash.mockClear(); // This is needed due to console.error called by vue to emit a warning that stop the tests // see https://github.com/vuejs/vue-test-utils/issues/532 Vue.config.silent = true; - wrapper = mount(collapsibleComponent, { + store = new Vuex.Store({ + state: { + isDeleteDisabled: false, + }, + getters, + }); + + wrapper = mountWithStore({ propsData: { repo: repoPropsData, }, @@ -27,6 +43,7 @@ describe('collapsible registry container', () => { afterEach(() => { Vue.config.silent = false; + wrapper.destroy(); }); describe('toggle', () => { @@ -86,4 +103,25 @@ describe('collapsible registry container', () => { }); }); }); + + describe('disabled delete', () => { + beforeEach(() => { + store = new Vuex.Store({ + state: { + isDeleteDisabled: true, + }, + getters, + }); + wrapper = mountWithStore({ + propsData: { + repo: repoPropsData, + }, + }); + }); + + it('should not render delete button', () => { + const deleteBtn = findDeleteBtn(wrapper); + expect(deleteBtn.exists()).toBe(false); + }); + }); }); diff --git a/spec/frontend/registry/components/group_empty_state_spec.js b/spec/frontend/registry/components/group_empty_state_spec.js new file mode 100644 index 00000000000..f71074b5154 --- /dev/null +++ b/spec/frontend/registry/components/group_empty_state_spec.js @@ -0,0 +1,23 @@ +import { mount } from '@vue/test-utils'; +import groupEmptyState from '~/registry/components/group_empty_state.vue'; + +describe('Registry Group Empty state', () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(groupEmptyState, { + propsData: { + noContainersImage: 'imageUrl', + helpPagePath: 'help', + }, + }); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('to match the default snapshot', () => { + expect(wrapper.element).toMatchSnapshot(); + }); +}); diff --git a/spec/frontend/registry/components/project_empty_state_spec.js b/spec/frontend/registry/components/project_empty_state_spec.js new file mode 100644 index 00000000000..913524db3aa --- /dev/null +++ b/spec/frontend/registry/components/project_empty_state_spec.js @@ -0,0 +1,27 @@ +import { mount } from '@vue/test-utils'; +import projectEmptyState from '~/registry/components/project_empty_state.vue'; + +describe('Registry Project Empty state', () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(projectEmptyState, { + propsData: { + noContainersImage: 'imageUrl', + helpPagePath: 'help', + repositoryUrl: 'url', + twoFactorAuthHelpLink: 'help_link', + personalAccessTokensHelpLink: 'personal_token', + registryHostUrlWithPort: 'host', + }, + }); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('to match the default snapshot', () => { + expect(wrapper.element).toMatchSnapshot(); + }); +}); diff --git a/spec/frontend/registry/components/table_registry_spec.js b/spec/frontend/registry/components/table_registry_spec.js index 021f13feeba..600a7a6ee87 100644 --- a/spec/frontend/registry/components/table_registry_spec.js +++ b/spec/frontend/registry/components/table_registry_spec.js @@ -1,12 +1,19 @@ import Vue from 'vue'; +import Vuex from 'vuex'; import tableRegistry from '~/registry/components/table_registry.vue'; -import { mount } from '@vue/test-utils'; +import { mount, createLocalVue } from '@vue/test-utils'; import { repoPropsData } from '../mock_data'; +import * as getters from '~/registry/stores/getters'; const [firstImage, secondImage] = repoPropsData.list; +const localVue = createLocalVue(); + +localVue.use(Vuex); + describe('table registry', () => { let wrapper; + let store; const findSelectAllCheckbox = w => w.find('.js-select-all-checkbox > input'); const findSelectCheckboxes = w => w.findAll('.js-select-checkbox > input'); @@ -15,19 +22,31 @@ describe('table registry', () => { const findPagination = w => w.find('.js-registry-pagination'); const bulkDeletePath = 'path'; + const mountWithStore = config => mount(tableRegistry, { ...config, store, localVue }); + beforeEach(() => { // This is needed due to console.error called by vue to emit a warning that stop the tests // see https://github.com/vuejs/vue-test-utils/issues/532 Vue.config.silent = true; - wrapper = mount(tableRegistry, { + + store = new Vuex.Store({ + state: { + isDeleteDisabled: false, + }, + getters, + }); + + wrapper = mountWithStore({ propsData: { repo: repoPropsData, + canDeleteRepo: true, }, }); }); afterEach(() => { Vue.config.silent = false; + wrapper.destroy(); }); describe('rendering', () => { @@ -149,7 +168,6 @@ describe('table registry', () => { }); describe('pagination', () => { - let localWrapper = null; const repo = { repoPropsData, pagination: { @@ -160,7 +178,7 @@ describe('table registry', () => { }; beforeEach(() => { - localWrapper = mount(tableRegistry, { + wrapper = mount(tableRegistry, { propsData: { repo, }, @@ -168,13 +186,13 @@ describe('table registry', () => { }); it('should exist', () => { - const pagination = findPagination(localWrapper); + const pagination = findPagination(wrapper); expect(pagination.exists()).toBe(true); }); it('should be visible when pagination is needed', () => { - const pagination = findPagination(localWrapper); + const pagination = findPagination(wrapper); expect(pagination.isVisible()).toBe(true); - localWrapper.setProps({ + wrapper.setProps({ repo: { pagination: { total: 0, @@ -182,13 +200,13 @@ describe('table registry', () => { }, }, }); - expect(localWrapper.vm.shouldRenderPagination).toBe(false); + expect(wrapper.vm.shouldRenderPagination).toBe(false); }); it('should have a change function that update the list when run', () => { const fetchList = jest.fn().mockResolvedValue(); - localWrapper.setMethods({ fetchList }); - localWrapper.vm.onPageChange(1); - expect(localWrapper.vm.fetchList).toHaveBeenCalledWith({ repo, page: 1 }); + wrapper.setMethods({ fetchList }); + wrapper.vm.onPageChange(1); + expect(wrapper.vm.fetchList).toHaveBeenCalledWith({ repo, page: 1 }); }); }); @@ -208,4 +226,41 @@ describe('table registry', () => { expect(wrapper.vm.modalDescription).toContain('<b>2</b> tags'); }); }); + + describe('disabled delete', () => { + beforeEach(() => { + store = new Vuex.Store({ + state: { + isDeleteDisabled: true, + }, + getters, + }); + wrapper = mountWithStore({ + propsData: { + repo: repoPropsData, + canDeleteRepo: false, + }, + }); + }); + + it('should not render select all', () => { + const selectAll = findSelectAllCheckbox(wrapper); + expect(selectAll.exists()).toBe(false); + }); + + it('should not render any select checkbox', () => { + const selects = findSelectCheckboxes(wrapper); + expect(selects.length).toBe(0); + }); + + it('should not render delete registry button', () => { + const deleteBtn = findDeleteButton(wrapper); + expect(deleteBtn.exists()).toBe(false); + }); + + it('should not render delete row button', () => { + const deleteBtns = findDeleteButtonsRow(wrapper); + expect(deleteBtns.length).toBe(0); + }); + }); }); diff --git a/spec/frontend/registry/stores/actions_spec.js b/spec/frontend/registry/stores/actions_spec.js index bf335904d23..7937fa82e80 100644 --- a/spec/frontend/registry/stores/actions_spec.js +++ b/spec/frontend/registry/stores/actions_spec.js @@ -34,7 +34,7 @@ describe('Actions Registry Store', () => { mock.onGet(`${TEST_HOST}/endpoint.json`).replyOnce(200, reposServerResponse, {}); }); - it('should set receveived repos', done => { + it('should set received repos', done => { testAction( actions.fetchRepos, null, @@ -71,10 +71,10 @@ describe('Actions Registry Store', () => { beforeEach(() => { state.repos = parsedReposServerResponse; [, repo] = state.repos; - mock.onGet(repo.tagsPath).replyOnce(200, registryServerResponse, {}); }); it('should set received list', done => { + mock.onGet(repo.tagsPath).replyOnce(200, registryServerResponse, {}); testAction( actions.fetchList, { repo }, @@ -97,6 +97,7 @@ describe('Actions Registry Store', () => { }); it('should create flash on API error', done => { + mock.onGet(repo.tagsPath).replyOnce(400); const updatedRepo = { ...repo, tagsPath: null, @@ -133,6 +134,19 @@ describe('Actions Registry Store', () => { }); }); + describe('setIsDeleteDisabled', () => { + it('should commit set is delete disabled', done => { + testAction( + actions.setIsDeleteDisabled, + true, + state, + [{ type: types.SET_IS_DELETE_DISABLED, payload: true }], + [], + done, + ); + }); + }); + describe('toggleLoading', () => { it('should commit toggle main loading', done => { testAction( diff --git a/spec/frontend/registry/stores/getters_spec.js b/spec/frontend/registry/stores/getters_spec.js index 839aa718997..c16f520223b 100644 --- a/spec/frontend/registry/stores/getters_spec.js +++ b/spec/frontend/registry/stores/getters_spec.js @@ -7,6 +7,7 @@ describe('Getters Registry Store', () => { state = { isLoading: false, endpoint: '/root/empty-project/container_registry.json', + isDeleteDisabled: false, repos: [ { canDelete: true, @@ -43,4 +44,9 @@ describe('Getters Registry Store', () => { expect(getters.repos(state)).toEqual(state.repos); }); }); + describe('isDeleteDisabled', () => { + it('should return isDeleteDisabled', () => { + expect(getters.isDeleteDisabled(state)).toEqual(state.isDeleteDisabled); + }); + }); }); diff --git a/spec/frontend/registry/stores/mutations_spec.js b/spec/frontend/registry/stores/mutations_spec.js index e19fe7a27cf..1d583028ca6 100644 --- a/spec/frontend/registry/stores/mutations_spec.js +++ b/spec/frontend/registry/stores/mutations_spec.js @@ -19,7 +19,16 @@ describe('Mutations Registry Store', () => { const expectedState = Object.assign({}, mockState, { endpoint: 'foo' }); mutations[types.SET_MAIN_ENDPOINT](mockState, 'foo'); - expect(mockState).toEqual(expectedState); + expect(mockState.endpoint).toEqual(expectedState.endpoint); + }); + }); + + describe('SET_IS_DELETE_DISABLED', () => { + it('should set the is delete disabled', () => { + const expectedState = Object.assign({}, mockState, { isDeleteDisabled: true }); + mutations[types.SET_IS_DELETE_DISABLED](mockState, true); + + expect(mockState.isDeleteDisabled).toEqual(expectedState.isDeleteDisabled); }); }); |