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
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-09-23 18:06:32 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2019-09-23 18:06:32 +0300
commit6f9edd1a4c4942d3d13ec54793cfae56164b1a0a (patch)
treef118f4a1dcad2db7b35ab15157e16eef56eba860 /spec
parent94e614c94c0a42e261e6af88c89461d90f3330c0 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/finders/clusters/kubernetes_namespace_finder_spec.rb6
-rw-r--r--spec/frontend/registry/components/app_spec.js121
-rw-r--r--spec/frontend/registry/components/collapsible_container_spec.js89
-rw-r--r--spec/frontend/registry/components/table_registry_spec.js211
-rw-r--r--spec/frontend/registry/mock_data.js (renamed from spec/javascripts/registry/mock_data.js)0
-rw-r--r--spec/frontend/registry/stores/actions_spec.js189
-rw-r--r--spec/frontend/registry/stores/getters_spec.js (renamed from spec/frontend/registry/getters_spec.js)0
-rw-r--r--spec/frontend/registry/stores/mutations_spec.js (renamed from spec/javascripts/registry/stores/mutations_spec.js)0
-rw-r--r--spec/javascripts/registry/components/app_spec.js129
-rw-r--r--spec/javascripts/registry/components/collapsible_container_spec.js87
-rw-r--r--spec/javascripts/registry/components/table_registry_spec.js189
-rw-r--r--spec/javascripts/registry/stores/actions_spec.js132
-rw-r--r--spec/models/clusters/cluster_spec.rb2
-rw-r--r--spec/models/clusters/kubernetes_namespace_spec.rb14
-rw-r--r--spec/models/clusters/platforms/kubernetes_spec.rb2
15 files changed, 622 insertions, 549 deletions
diff --git a/spec/finders/clusters/kubernetes_namespace_finder_spec.rb b/spec/finders/clusters/kubernetes_namespace_finder_spec.rb
index 8beba0b99a4..7d9c4daa0fe 100644
--- a/spec/finders/clusters/kubernetes_namespace_finder_spec.rb
+++ b/spec/finders/clusters/kubernetes_namespace_finder_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Clusters::KubernetesNamespaceFinder do
described_class.new(
cluster,
project: project,
- environment_slug: 'production',
+ environment_name: 'production',
allow_blank_token: allow_blank_token
)
end
@@ -22,8 +22,8 @@ RSpec.describe Clusters::KubernetesNamespaceFinder do
end
describe '#execute' do
- let(:production) { create(:environment, project: project, slug: 'production') }
- let(:staging) { create(:environment, project: project, slug: 'staging') }
+ let(:production) { create(:environment, project: project, name: 'production') }
+ let(:staging) { create(:environment, project: project, name: 'staging') }
let(:cluster) { create(:cluster, :group, :provided_by_user) }
let(:project) { create(:project) }
diff --git a/spec/frontend/registry/components/app_spec.js b/spec/frontend/registry/components/app_spec.js
new file mode 100644
index 00000000000..190af5c11cd
--- /dev/null
+++ b/spec/frontend/registry/components/app_spec.js
@@ -0,0 +1,121 @@
+import registry from '~/registry/components/app.vue';
+import { mount } from '@vue/test-utils';
+import { TEST_HOST } from '../../helpers/test_constants';
+import { reposServerResponse, parsedReposServerResponse } from '../mock_data';
+
+describe('Registry List', () => {
+ let wrapper;
+
+ const findCollapsibleContainer = w => w.findAll({ name: 'CollapsibeContainerRegisty' });
+ const findNoContainerImagesText = w => w.find('.js-no-container-images-text');
+ const findSpinner = w => w.find('.gl-spinner');
+ const findCharacterErrorText = w => w.find('.js-character-error-text');
+
+ const propsData = {
+ endpoint: `${TEST_HOST}/foo`,
+ helpPagePath: 'foo',
+ noContainersImage: 'foo',
+ containersErrorImage: 'foo',
+ repositoryUrl: 'foo',
+ };
+
+ const setMainEndpoint = jest.fn();
+ const fetchRepos = jest.fn();
+
+ const methods = {
+ setMainEndpoint,
+ fetchRepos,
+ };
+
+ beforeEach(() => {
+ wrapper = mount(registry, {
+ propsData,
+ computed: {
+ repos() {
+ return parsedReposServerResponse;
+ },
+ },
+ methods,
+ });
+ });
+
+ describe('with data', () => {
+ it('should render a list of CollapsibeContainerRegisty', () => {
+ const containers = findCollapsibleContainer(wrapper);
+ expect(wrapper.vm.repos.length).toEqual(reposServerResponse.length);
+ expect(containers.length).toEqual(reposServerResponse.length);
+ });
+ });
+
+ describe('without data', () => {
+ let localWrapper;
+ beforeEach(() => {
+ localWrapper = mount(registry, {
+ propsData,
+ computed: {
+ repos() {
+ return [];
+ },
+ },
+ methods,
+ });
+ });
+
+ 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',
+ );
+ });
+ });
+
+ describe('while loading data', () => {
+ let localWrapper;
+
+ beforeEach(() => {
+ localWrapper = mount(registry, {
+ propsData,
+ computed: {
+ repos() {
+ return [];
+ },
+ isLoading() {
+ return true;
+ },
+ },
+ methods,
+ });
+ });
+
+ it('should render a loading spinner', () => {
+ const spinner = findSpinner(localWrapper);
+ expect(spinner.exists()).toBe(true);
+ });
+ });
+
+ describe('invalid characters in path', () => {
+ let localWrapper;
+
+ beforeEach(() => {
+ localWrapper = mount(registry, {
+ propsData: {
+ ...propsData,
+ characterError: true,
+ },
+ computed: {
+ repos() {
+ return [];
+ },
+ },
+ methods,
+ });
+ });
+
+ it('should render invalid characters error message', () => {
+ const characterErrorText = findCharacterErrorText(localWrapper);
+ expect(characterErrorText.text()).toEqual(
+ 'We are having trouble connecting to Docker, which could be due to an issue with your project name or path. More Information',
+ );
+ });
+ });
+});
diff --git a/spec/frontend/registry/components/collapsible_container_spec.js b/spec/frontend/registry/components/collapsible_container_spec.js
new file mode 100644
index 00000000000..0fe4338f1ba
--- /dev/null
+++ b/spec/frontend/registry/components/collapsible_container_spec.js
@@ -0,0 +1,89 @@
+import Vue from 'vue';
+import { mount } from '@vue/test-utils';
+import collapsibleComponent from '~/registry/components/collapsible_container.vue';
+import { repoPropsData } from '../mock_data';
+import createFlash from '~/flash';
+
+jest.mock('~/flash.js');
+
+describe('collapsible registry container', () => {
+ let wrapper;
+
+ const findDeleteBtn = w => w.find('.js-remove-repo');
+ const findContainerImageTags = w => w.find('.container-image-tags');
+ const findToggleRepos = w => w.findAll('.js-toggle-repo');
+
+ 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, {
+ propsData: {
+ repo: repoPropsData,
+ },
+ });
+ });
+
+ afterEach(() => {
+ Vue.config.silent = false;
+ });
+
+ describe('toggle', () => {
+ beforeEach(() => {
+ const fetchList = jest.fn();
+ wrapper.setMethods({ fetchList });
+ });
+
+ const expectIsClosed = () => {
+ const container = findContainerImageTags(wrapper);
+ expect(container.exists()).toBe(false);
+ expect(wrapper.vm.iconName).toEqual('angle-right');
+ };
+
+ it('should be closed by default', () => {
+ expectIsClosed();
+ });
+ it('should be open when user clicks on closed repo', () => {
+ const toggleRepos = findToggleRepos(wrapper);
+ toggleRepos.at(0).trigger('click');
+ const container = findContainerImageTags(wrapper);
+ expect(container.exists()).toBe(true);
+ expect(wrapper.vm.fetchList).toHaveBeenCalled();
+ });
+ it('should be closed when the user clicks on an opened repo', done => {
+ const toggleRepos = findToggleRepos(wrapper);
+ toggleRepos.at(0).trigger('click');
+ Vue.nextTick(() => {
+ toggleRepos.at(0).trigger('click');
+ Vue.nextTick(() => {
+ expectIsClosed();
+ done();
+ });
+ });
+ });
+ });
+
+ describe('delete repo', () => {
+ it('should be possible to delete a repo', () => {
+ const deleteBtn = findDeleteBtn(wrapper);
+ expect(deleteBtn.exists()).toBe(true);
+ });
+
+ it('should call deleteItem when confirming deletion', () => {
+ const deleteItem = jest.fn().mockResolvedValue();
+ const fetchRepos = jest.fn().mockResolvedValue();
+ wrapper.setMethods({ deleteItem, fetchRepos });
+ wrapper.vm.handleDeleteRepository();
+ expect(wrapper.vm.deleteItem).toHaveBeenCalledWith(wrapper.vm.repo);
+ });
+
+ it('should show an error when there is API error', () => {
+ const deleteItem = jest.fn().mockRejectedValue('error');
+ wrapper.setMethods({ deleteItem });
+ return wrapper.vm.handleDeleteRepository().then(() => {
+ expect(createFlash).toHaveBeenCalled();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/registry/components/table_registry_spec.js b/spec/frontend/registry/components/table_registry_spec.js
new file mode 100644
index 00000000000..a2eee4aada7
--- /dev/null
+++ b/spec/frontend/registry/components/table_registry_spec.js
@@ -0,0 +1,211 @@
+import Vue from 'vue';
+import tableRegistry from '~/registry/components/table_registry.vue';
+import { mount } from '@vue/test-utils';
+import { repoPropsData } from '../mock_data';
+
+const [firstImage, secondImage] = repoPropsData.list;
+
+describe('table registry', () => {
+ let wrapper;
+
+ const findSelectAllCheckbox = w => w.find('.js-select-all-checkbox > input');
+ const findSelectCheckboxes = w => w.findAll('.js-select-checkbox > input');
+ const findDeleteButton = w => w.find('.js-delete-registry');
+ const findDeleteButtonsRow = w => w.findAll('.js-delete-registry-row');
+ const findPagination = w => w.find('.js-registry-pagination');
+ const bulkDeletePath = 'path';
+
+ 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, {
+ propsData: {
+ repo: repoPropsData,
+ },
+ });
+ });
+
+ afterEach(() => {
+ Vue.config.silent = false;
+ });
+
+ describe('rendering', () => {
+ it('should render a table with the registry list', () => {
+ expect(wrapper.findAll('.registry-image-row').length).toEqual(repoPropsData.list.length);
+ });
+
+ it('should render registry tag', () => {
+ const tds = wrapper.findAll('.registry-image-row td');
+ expect(tds.at(0).classes()).toContain('check');
+ expect(tds.at(1).html()).toContain(repoPropsData.list[0].tag);
+ expect(tds.at(2).html()).toContain(repoPropsData.list[0].shortRevision);
+ expect(tds.at(3).html()).toContain(repoPropsData.list[0].layers);
+ expect(tds.at(3).html()).toContain(repoPropsData.list[0].size);
+ expect(tds.at(4).html()).toContain(wrapper.vm.timeFormated(repoPropsData.list[0].createdAt));
+ });
+ });
+
+ describe('multi select', () => {
+ it('selecting a row should enable delete button', done => {
+ const deleteBtn = findDeleteButton(wrapper);
+ const checkboxes = findSelectCheckboxes(wrapper);
+
+ expect(deleteBtn.attributes('disabled')).toBe('disabled');
+
+ checkboxes.at(0).trigger('click');
+ Vue.nextTick(() => {
+ expect(deleteBtn.attributes('disabled')).toEqual(undefined);
+ done();
+ });
+ });
+
+ it('selecting all checkbox should select all rows and enable delete button', done => {
+ const selectAll = findSelectAllCheckbox(wrapper);
+ const checkboxes = findSelectCheckboxes(wrapper);
+ selectAll.trigger('click');
+
+ Vue.nextTick(() => {
+ const checked = checkboxes.filter(w => w.element.checked);
+ expect(checked.length).toBe(checkboxes.length);
+ done();
+ });
+ });
+
+ it('deselecting select all checkbox should deselect all rows and disable delete button', done => {
+ const checkboxes = findSelectCheckboxes(wrapper);
+ const selectAll = findSelectAllCheckbox(wrapper);
+ selectAll.trigger('click');
+ selectAll.trigger('click');
+
+ Vue.nextTick(() => {
+ const checked = checkboxes.filter(w => !w.element.checked);
+ expect(checked.length).toBe(checkboxes.length);
+ done();
+ });
+ });
+
+ it('should delete multiple items when multiple items are selected', done => {
+ const multiDeleteItems = jest.fn().mockResolvedValue();
+ wrapper.setMethods({ multiDeleteItems });
+ const selectAll = findSelectAllCheckbox(wrapper);
+ selectAll.trigger('click');
+
+ Vue.nextTick(() => {
+ const deleteBtn = findDeleteButton(wrapper);
+ expect(wrapper.vm.itemsToBeDeleted).toEqual([0, 1]);
+ expect(deleteBtn.attributes('disabled')).toEqual(undefined);
+ wrapper.vm.handleMultipleDelete();
+
+ Vue.nextTick(() => {
+ expect(wrapper.vm.itemsToBeDeleted).toEqual([]);
+ expect(wrapper.vm.multiDeleteItems).toHaveBeenCalledWith({
+ path: bulkDeletePath,
+ items: [firstImage.tag, secondImage.tag],
+ });
+ done();
+ });
+ });
+ });
+
+ it('should show an error message if bulkDeletePath is not set', () => {
+ const showError = jest.fn();
+ wrapper.setMethods({ showError });
+ wrapper.setProps({
+ repo: {
+ ...repoPropsData,
+ tagsPath: null,
+ },
+ });
+ wrapper.vm.handleMultipleDelete();
+ expect(wrapper.vm.showError).toHaveBeenCalled();
+ });
+ });
+
+ describe('delete registry', () => {
+ beforeEach(() => {
+ wrapper.setData({ itemsToBeDeleted: [0] });
+ });
+
+ it('should be possible to delete a registry', () => {
+ const deleteBtn = findDeleteButton(wrapper);
+ const deleteBtns = findDeleteButtonsRow(wrapper);
+ expect(wrapper.vm.itemsToBeDeleted).toEqual([0]);
+ expect(deleteBtn).toBeDefined();
+ expect(deleteBtn.attributes('disable')).toBe(undefined);
+ expect(deleteBtns.is('button')).toBe(true);
+ });
+
+ it('should allow deletion row by row', () => {
+ const deleteBtns = findDeleteButtonsRow(wrapper);
+ const deleteSingleItem = jest.fn();
+ const deleteItem = jest.fn().mockResolvedValue();
+ wrapper.setMethods({ deleteSingleItem, deleteItem });
+ deleteBtns.at(0).trigger('click');
+ expect(wrapper.vm.deleteSingleItem).toHaveBeenCalledWith(0);
+ wrapper.vm.handleSingleDelete(1);
+ expect(wrapper.vm.deleteItem).toHaveBeenCalledWith(1);
+ });
+ });
+
+ describe('pagination', () => {
+ let localWrapper = null;
+ const repo = {
+ repoPropsData,
+ pagination: {
+ total: 20,
+ perPage: 2,
+ nextPage: 2,
+ },
+ };
+
+ beforeEach(() => {
+ localWrapper = mount(tableRegistry, {
+ propsData: {
+ repo,
+ },
+ });
+ });
+
+ it('should exist', () => {
+ const pagination = findPagination(localWrapper);
+ expect(pagination.exists()).toBe(true);
+ });
+ it('should be visible when pagination is needed', () => {
+ const pagination = findPagination(localWrapper);
+ expect(pagination.isVisible()).toBe(true);
+ localWrapper.setProps({
+ repo: {
+ pagination: {
+ total: 0,
+ perPage: 10,
+ },
+ },
+ });
+ expect(localWrapper.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 });
+ });
+ });
+
+ describe('modal content', () => {
+ it('should show the singular title and image name when deleting a single image', () => {
+ wrapper.setData({ itemsToBeDeleted: [1] });
+ wrapper.vm.setModalDescription(0);
+ expect(wrapper.vm.modalTitle).toBe('Remove image');
+ expect(wrapper.vm.modalDescription).toContain(firstImage.tag);
+ });
+
+ it('should show the plural title and image count when deleting more than one image', () => {
+ wrapper.setData({ itemsToBeDeleted: [1, 2] });
+ wrapper.vm.setModalDescription();
+
+ expect(wrapper.vm.modalTitle).toBe('Remove images');
+ expect(wrapper.vm.modalDescription).toContain('<b>2</b> images');
+ });
+ });
+});
diff --git a/spec/javascripts/registry/mock_data.js b/spec/frontend/registry/mock_data.js
index 130ab298e89..130ab298e89 100644
--- a/spec/javascripts/registry/mock_data.js
+++ b/spec/frontend/registry/mock_data.js
diff --git a/spec/frontend/registry/stores/actions_spec.js b/spec/frontend/registry/stores/actions_spec.js
new file mode 100644
index 00000000000..bf335904d23
--- /dev/null
+++ b/spec/frontend/registry/stores/actions_spec.js
@@ -0,0 +1,189 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import * as actions from '~/registry/stores/actions';
+import * as types from '~/registry/stores/mutation_types';
+import { TEST_HOST } from '../../helpers/test_constants';
+import testAction from '../../helpers/vuex_action_helper';
+import createFlash from '~/flash';
+
+import {
+ reposServerResponse,
+ registryServerResponse,
+ parsedReposServerResponse,
+} from '../mock_data';
+
+jest.mock('~/flash.js');
+
+describe('Actions Registry Store', () => {
+ let mock;
+ let state;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ state = {
+ endpoint: `${TEST_HOST}/endpoint.json`,
+ };
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('fetchRepos', () => {
+ beforeEach(() => {
+ mock.onGet(`${TEST_HOST}/endpoint.json`).replyOnce(200, reposServerResponse, {});
+ });
+
+ it('should set receveived repos', done => {
+ testAction(
+ actions.fetchRepos,
+ null,
+ state,
+ [
+ { type: types.TOGGLE_MAIN_LOADING },
+ { type: types.TOGGLE_MAIN_LOADING },
+ { type: types.SET_REPOS_LIST, payload: reposServerResponse },
+ ],
+ [],
+ done,
+ );
+ });
+
+ it('should create flash on API error', done => {
+ testAction(
+ actions.fetchRepos,
+ null,
+ {
+ endpoint: null,
+ },
+ [{ type: types.TOGGLE_MAIN_LOADING }, { type: types.TOGGLE_MAIN_LOADING }],
+ [],
+ () => {
+ expect(createFlash).toHaveBeenCalled();
+ done();
+ },
+ );
+ });
+ });
+
+ describe('fetchList', () => {
+ let repo;
+ beforeEach(() => {
+ state.repos = parsedReposServerResponse;
+ [, repo] = state.repos;
+ mock.onGet(repo.tagsPath).replyOnce(200, registryServerResponse, {});
+ });
+
+ it('should set received list', done => {
+ testAction(
+ actions.fetchList,
+ { repo },
+ state,
+ [
+ { type: types.TOGGLE_REGISTRY_LIST_LOADING, payload: repo },
+ { type: types.TOGGLE_REGISTRY_LIST_LOADING, payload: repo },
+ {
+ type: types.SET_REGISTRY_LIST,
+ payload: {
+ repo,
+ resp: registryServerResponse,
+ headers: expect.anything(),
+ },
+ },
+ ],
+ [],
+ done,
+ );
+ });
+
+ it('should create flash on API error', done => {
+ const updatedRepo = {
+ ...repo,
+ tagsPath: null,
+ };
+ testAction(
+ actions.fetchList,
+ {
+ repo: updatedRepo,
+ },
+ state,
+ [
+ { type: types.TOGGLE_REGISTRY_LIST_LOADING, payload: updatedRepo },
+ { type: types.TOGGLE_REGISTRY_LIST_LOADING, payload: updatedRepo },
+ ],
+ [],
+ () => {
+ expect(createFlash).toHaveBeenCalled();
+ done();
+ },
+ );
+ });
+ });
+
+ describe('setMainEndpoint', () => {
+ it('should commit set main endpoint', done => {
+ testAction(
+ actions.setMainEndpoint,
+ 'endpoint',
+ state,
+ [{ type: types.SET_MAIN_ENDPOINT, payload: 'endpoint' }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('toggleLoading', () => {
+ it('should commit toggle main loading', done => {
+ testAction(
+ actions.toggleLoading,
+ null,
+ state,
+ [{ type: types.TOGGLE_MAIN_LOADING }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('deleteItem and multiDeleteItems', () => {
+ let deleted;
+ const destroyPath = `${TEST_HOST}/mygroup/myproject/container_registry/1.json`;
+
+ const expectDelete = done => {
+ expect(mock.history.delete.length).toBe(1);
+ expect(deleted).toBe(true);
+ done();
+ };
+
+ beforeEach(() => {
+ deleted = false;
+ mock.onDelete(destroyPath).replyOnce(() => {
+ deleted = true;
+ return [200];
+ });
+ });
+
+ it('deleteItem should perform DELETE request on destroyPath', done => {
+ testAction(
+ actions.deleteItem,
+ {
+ destroyPath,
+ },
+ state,
+ )
+ .then(() => {
+ expectDelete(done);
+ })
+ .catch(done.fail);
+ });
+
+ it('multiDeleteItems should perform DELETE request on path', done => {
+ testAction(actions.multiDeleteItems, { path: destroyPath, items: [1] }, state)
+ .then(() => {
+ expectDelete(done);
+ })
+ .catch(done.fail);
+ });
+ });
+});
diff --git a/spec/frontend/registry/getters_spec.js b/spec/frontend/registry/stores/getters_spec.js
index 839aa718997..839aa718997 100644
--- a/spec/frontend/registry/getters_spec.js
+++ b/spec/frontend/registry/stores/getters_spec.js
diff --git a/spec/javascripts/registry/stores/mutations_spec.js b/spec/frontend/registry/stores/mutations_spec.js
index e19fe7a27cf..e19fe7a27cf 100644
--- a/spec/javascripts/registry/stores/mutations_spec.js
+++ b/spec/frontend/registry/stores/mutations_spec.js
diff --git a/spec/javascripts/registry/components/app_spec.js b/spec/javascripts/registry/components/app_spec.js
deleted file mode 100644
index 5ea3f85a247..00000000000
--- a/spec/javascripts/registry/components/app_spec.js
+++ /dev/null
@@ -1,129 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import Vue from 'vue';
-import registry from '~/registry/components/app.vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import { TEST_HOST } from 'spec/test_constants';
-import { reposServerResponse } from '../mock_data';
-
-describe('Registry List', () => {
- const Component = Vue.extend(registry);
- const props = {
- endpoint: `${TEST_HOST}/foo`,
- helpPagePath: 'foo',
- noContainersImage: 'foo',
- containersErrorImage: 'foo',
- repositoryUrl: 'foo',
- };
- let vm;
- let mock;
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mock.restore();
- vm.$destroy();
- });
-
- describe('with data', () => {
- beforeEach(() => {
- mock.onGet(`${TEST_HOST}/foo`).replyOnce(200, reposServerResponse);
-
- vm = mountComponent(Component, { ...props });
- });
-
- it('should render a list of repos', done => {
- setTimeout(() => {
- expect(vm.$store.state.repos.length).toEqual(reposServerResponse.length);
-
- Vue.nextTick(() => {
- expect(vm.$el.querySelectorAll('.container-image').length).toEqual(
- reposServerResponse.length,
- );
- done();
- });
- }, 0);
- });
-
- describe('delete repository', () => {
- it('should be possible to delete a repo', done => {
- setTimeout(() => {
- Vue.nextTick(() => {
- expect(vm.$el.querySelector('.container-image-head .js-remove-repo')).toBeDefined();
- done();
- });
- }, 0);
- });
- });
-
- describe('toggle repository', () => {
- it('should open the container', done => {
- setTimeout(() => {
- Vue.nextTick(() => {
- vm.$el.querySelector('.js-toggle-repo').click();
- Vue.nextTick(() => {
- expect(
- vm.$el.querySelector('.js-toggle-repo use').getAttribute('xlink:href'),
- ).toContain('angle-up');
- done();
- });
- });
- }, 0);
- });
- });
- });
-
- describe('without data', () => {
- beforeEach(() => {
- mock.onGet(`${TEST_HOST}/foo`).replyOnce(200, []);
-
- vm = mountComponent(Component, { ...props });
- });
-
- it('should render empty message', done => {
- setTimeout(() => {
- expect(vm.$el.querySelector('.js-no-container-images-text').textContent).toEqual(
- 'With the Container Registry, every project can have its own space to store its Docker images. More Information',
- );
- done();
- }, 0);
- });
- });
-
- describe('while loading data', () => {
- beforeEach(() => {
- mock.onGet(`${TEST_HOST}/foo`).replyOnce(200, []);
-
- vm = mountComponent(Component, { ...props });
- });
-
- it('should render a loading spinner', done => {
- Vue.nextTick(() => {
- expect(vm.$el.querySelector('.gl-spinner')).not.toBe(null);
- done();
- });
- });
- });
-
- describe('invalid characters in path', () => {
- beforeEach(() => {
- mock.onGet(`${TEST_HOST}/foo`).replyOnce(200, []);
-
- vm = mountComponent(Component, {
- ...props,
- characterError: true,
- });
- });
-
- it('should render invalid characters error message', done => {
- setTimeout(() => {
- expect(vm.$el.querySelector('p')).not.toContain(
- 'We are having trouble connecting to Docker, which could be due to an issue with your project name or path. More information',
- );
- done();
- });
- });
- });
-});
diff --git a/spec/javascripts/registry/components/collapsible_container_spec.js b/spec/javascripts/registry/components/collapsible_container_spec.js
deleted file mode 100644
index 2a5d8dd11da..00000000000
--- a/spec/javascripts/registry/components/collapsible_container_spec.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import Vue from 'vue';
-import collapsibleComponent from '~/registry/components/collapsible_container.vue';
-import store from '~/registry/stores';
-import * as types from '~/registry/stores/mutation_types';
-
-import { repoPropsData, registryServerResponse, reposServerResponse } from '../mock_data';
-
-describe('collapsible registry container', () => {
- let vm;
- let mock;
- const Component = Vue.extend(collapsibleComponent);
-
- const findDeleteBtn = () => vm.$el.querySelector('.js-remove-repo');
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
-
- mock.onGet(repoPropsData.tagsPath).replyOnce(200, registryServerResponse, {});
-
- store.commit(types.SET_REPOS_LIST, reposServerResponse);
-
- vm = new Component({
- store,
- propsData: {
- repo: repoPropsData,
- },
- }).$mount();
- });
-
- afterEach(() => {
- mock.restore();
- vm.$destroy();
- });
-
- describe('toggle', () => {
- it('should be closed by default', () => {
- expect(vm.$el.querySelector('.container-image-tags')).toBe(null);
- expect(vm.iconName).toEqual('angle-right');
- });
-
- it('should be open when user clicks on closed repo', done => {
- vm.$el.querySelector('.js-toggle-repo').click();
-
- Vue.nextTick(() => {
- expect(vm.$el.querySelector('.container-image-tags')).not.toBeNull();
- expect(vm.iconName).toEqual('angle-up');
-
- done();
- });
- });
-
- it('should be closed when the user clicks on an opened repo', done => {
- vm.$el.querySelector('.js-toggle-repo').click();
-
- Vue.nextTick(() => {
- vm.$el.querySelector('.js-toggle-repo').click();
- setTimeout(() => {
- Vue.nextTick(() => {
- expect(vm.$el.querySelector('.container-image-tags')).toBe(null);
- expect(vm.iconName).toEqual('angle-right');
- done();
- });
- });
- });
- });
- });
-
- describe('delete repo', () => {
- it('should be possible to delete a repo', () => {
- expect(findDeleteBtn()).not.toBeNull();
- });
-
- it('should call deleteItem when confirming deletion', done => {
- findDeleteBtn().click();
- spyOn(vm, 'deleteItem').and.returnValue(Promise.resolve());
-
- Vue.nextTick(() => {
- document.querySelector(`#${vm.modalId} .btn-danger`).click();
-
- expect(vm.deleteItem).toHaveBeenCalledWith(vm.repo);
- done();
- });
- });
- });
-});
diff --git a/spec/javascripts/registry/components/table_registry_spec.js b/spec/javascripts/registry/components/table_registry_spec.js
deleted file mode 100644
index 9c7439206ef..00000000000
--- a/spec/javascripts/registry/components/table_registry_spec.js
+++ /dev/null
@@ -1,189 +0,0 @@
-import Vue from 'vue';
-import tableRegistry from '~/registry/components/table_registry.vue';
-import store from '~/registry/stores';
-import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
-import { repoPropsData } from '../mock_data';
-
-const [firstImage, secondImage] = repoPropsData.list;
-
-describe('table registry', () => {
- let vm;
- const Component = Vue.extend(tableRegistry);
- const bulkDeletePath = 'path';
-
- const findDeleteBtn = () => vm.$el.querySelector('.js-delete-registry');
- const findDeleteBtnRow = () => vm.$el.querySelector('.js-delete-registry-row');
- const findSelectAllCheckbox = () => vm.$el.querySelector('.js-select-all-checkbox > input');
- const findAllRowCheckboxes = () =>
- Array.from(vm.$el.querySelectorAll('.js-select-checkbox input'));
- const confirmationModal = (child = '') => document.querySelector(`#${vm.modalId} ${child}`);
-
- const createComponent = () => {
- vm = mountComponentWithStore(Component, {
- store,
- props: {
- repo: repoPropsData,
- },
- });
- };
-
- const selectAllCheckboxes = () => vm.selectAll();
- const deselectAllCheckboxes = () => vm.deselectAll();
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('rendering', () => {
- it('should render a table with the registry list', () => {
- expect(vm.$el.querySelectorAll('table tbody tr').length).toEqual(repoPropsData.list.length);
- });
-
- it('should render registry tag', () => {
- const textRendered = vm.$el
- .querySelector('.table tbody tr')
- .textContent.trim()
- // replace additional whitespace characters (e.g. new lines) with a single empty space
- .replace(/\s\s+/g, ' ');
-
- expect(textRendered).toContain(repoPropsData.list[0].tag);
- expect(textRendered).toContain(repoPropsData.list[0].shortRevision);
- expect(textRendered).toContain(repoPropsData.list[0].layers);
- expect(textRendered).toContain(repoPropsData.list[0].size);
- });
- });
-
- describe('multi select', () => {
- it('should support multiselect and selecting a row should enable delete button', done => {
- findSelectAllCheckbox().click();
- selectAllCheckboxes();
-
- expect(findSelectAllCheckbox().checked).toBe(true);
-
- Vue.nextTick(() => {
- expect(findDeleteBtn().disabled).toBe(false);
- done();
- });
- });
-
- it('selecting all checkbox should select all rows and enable delete button', done => {
- selectAllCheckboxes();
-
- Vue.nextTick(() => {
- const checkedValues = findAllRowCheckboxes().filter(x => x.checked);
-
- expect(checkedValues.length).toBe(repoPropsData.list.length);
- done();
- });
- });
-
- it('deselecting select all checkbox should deselect all rows and disable delete button', done => {
- selectAllCheckboxes();
- deselectAllCheckboxes();
-
- Vue.nextTick(() => {
- const checkedValues = findAllRowCheckboxes().filter(x => x.checked);
-
- expect(checkedValues.length).toBe(0);
- done();
- });
- });
-
- it('should delete multiple items when multiple items are selected', done => {
- selectAllCheckboxes();
-
- Vue.nextTick(() => {
- expect(vm.itemsToBeDeleted).toEqual([0, 1]);
- expect(findDeleteBtn().disabled).toBe(false);
-
- findDeleteBtn().click();
- spyOn(vm, 'multiDeleteItems').and.returnValue(Promise.resolve());
-
- Vue.nextTick(() => {
- const modal = confirmationModal();
- confirmationModal('.btn-danger').click();
-
- expect(modal).toExist();
-
- Vue.nextTick(() => {
- expect(vm.itemsToBeDeleted).toEqual([]);
- expect(vm.multiDeleteItems).toHaveBeenCalledWith({
- path: bulkDeletePath,
- items: [firstImage.tag, secondImage.tag],
- });
- done();
- });
- });
- });
- });
- });
-
- describe('delete registry', () => {
- beforeEach(() => {
- vm.itemsToBeDeleted = [0];
- });
-
- it('should be possible to delete a registry', done => {
- Vue.nextTick(() => {
- expect(vm.itemsToBeDeleted).toEqual([0]);
- expect(findDeleteBtn()).toBeDefined();
- expect(findDeleteBtn().disabled).toBe(false);
- expect(findDeleteBtnRow()).toBeDefined();
- done();
- });
- });
-
- it('should call deleteItems and reset itemsToBeDeleted when confirming deletion', done => {
- Vue.nextTick(() => {
- expect(vm.itemsToBeDeleted).toEqual([0]);
- expect(findDeleteBtn().disabled).toBe(false);
- findDeleteBtn().click();
- spyOn(vm, 'multiDeleteItems').and.returnValue(Promise.resolve());
-
- Vue.nextTick(() => {
- confirmationModal('.btn-danger').click();
-
- expect(vm.itemsToBeDeleted).toEqual([]);
- expect(vm.multiDeleteItems).toHaveBeenCalledWith({
- path: bulkDeletePath,
- items: [firstImage.tag],
- });
- done();
- });
- });
- });
- });
-
- describe('pagination', () => {
- it('should be possible to change the page', () => {
- expect(vm.$el.querySelector('.gl-pagination')).toBeDefined();
- });
- });
-
- describe('modal content', () => {
- it('should show the singular title and image name when deleting a single image', done => {
- findDeleteBtnRow().click();
-
- Vue.nextTick(() => {
- expect(vm.modalTitle).toBe('Remove image');
- expect(vm.modalDescription).toContain(firstImage.tag);
- done();
- });
- });
-
- it('should show the plural title and image count when deleting more than one image', done => {
- selectAllCheckboxes();
- vm.setModalDescription();
-
- Vue.nextTick(() => {
- expect(vm.modalTitle).toBe('Remove images');
- expect(vm.modalDescription).toContain('<b>2</b> images');
- done();
- });
- });
- });
-});
diff --git a/spec/javascripts/registry/stores/actions_spec.js b/spec/javascripts/registry/stores/actions_spec.js
deleted file mode 100644
index 0613ec8e0f1..00000000000
--- a/spec/javascripts/registry/stores/actions_spec.js
+++ /dev/null
@@ -1,132 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import * as actions from '~/registry/stores/actions';
-import * as types from '~/registry/stores/mutation_types';
-import state from '~/registry/stores/state';
-import { TEST_HOST } from 'spec/test_constants';
-import testAction from '../../helpers/vuex_action_helper';
-import {
- reposServerResponse,
- registryServerResponse,
- parsedReposServerResponse,
-} from '../mock_data';
-
-describe('Actions Registry Store', () => {
- let mockedState;
- let mock;
-
- beforeEach(() => {
- mockedState = state();
- mockedState.endpoint = `${TEST_HOST}/endpoint.json`;
- mock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- describe('server requests', () => {
- describe('fetchRepos', () => {
- beforeEach(() => {
- mock.onGet(`${TEST_HOST}/endpoint.json`).replyOnce(200, reposServerResponse, {});
- });
-
- it('should set receveived repos', done => {
- testAction(
- actions.fetchRepos,
- null,
- mockedState,
- [
- { type: types.TOGGLE_MAIN_LOADING },
- { type: types.TOGGLE_MAIN_LOADING },
- { type: types.SET_REPOS_LIST, payload: reposServerResponse },
- ],
- [],
- done,
- );
- });
- });
-
- describe('fetchList', () => {
- let repo;
- beforeEach(() => {
- mockedState.repos = parsedReposServerResponse;
- [, repo] = mockedState.repos;
-
- mock.onGet(repo.tagsPath).replyOnce(200, registryServerResponse, {});
- });
-
- it('should set received list', done => {
- testAction(
- actions.fetchList,
- { repo },
- mockedState,
- [
- { type: types.TOGGLE_REGISTRY_LIST_LOADING, payload: repo },
- { type: types.TOGGLE_REGISTRY_LIST_LOADING, payload: repo },
- {
- type: types.SET_REGISTRY_LIST,
- payload: {
- repo,
- resp: registryServerResponse,
- headers: jasmine.anything(),
- },
- },
- ],
- [],
- done,
- );
- });
- });
- });
-
- describe('setMainEndpoint', () => {
- it('should commit set main endpoint', done => {
- testAction(
- actions.setMainEndpoint,
- 'endpoint',
- mockedState,
- [{ type: types.SET_MAIN_ENDPOINT, payload: 'endpoint' }],
- [],
- done,
- );
- });
- });
-
- describe('toggleLoading', () => {
- it('should commit toggle main loading', done => {
- testAction(
- actions.toggleLoading,
- null,
- mockedState,
- [{ type: types.TOGGLE_MAIN_LOADING }],
- [],
- done,
- );
- });
- });
-
- describe('deleteItem', () => {
- it('should perform DELETE request on destroyPath', done => {
- const destroyPath = `${TEST_HOST}/mygroup/myproject/container_registry/1.json`;
- let deleted = false;
- mock.onDelete(destroyPath).replyOnce(() => {
- deleted = true;
- return [200];
- });
- testAction(
- actions.deleteItem,
- {
- destroyPath,
- },
- mockedState,
- )
- .then(() => {
- expect(mock.history.delete.length).toBe(1);
- expect(deleted).toBe(true);
- done();
- })
- .catch(done.fail);
- });
- });
-});
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index df6263eeed2..06f454808e3 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -546,7 +546,7 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do
before do
expect(Clusters::KubernetesNamespaceFinder).to receive(:new)
- .with(cluster, project: environment.project, environment_slug: environment.slug)
+ .with(cluster, project: environment.project, environment_name: environment.name)
.and_return(double(execute: persisted_namespace))
end
diff --git a/spec/models/clusters/kubernetes_namespace_spec.rb b/spec/models/clusters/kubernetes_namespace_spec.rb
index d4e3a0ac84d..2920bbf2b58 100644
--- a/spec/models/clusters/kubernetes_namespace_spec.rb
+++ b/spec/models/clusters/kubernetes_namespace_spec.rb
@@ -24,13 +24,13 @@ RSpec.describe Clusters::KubernetesNamespace, type: :model do
end
end
- describe '.with_environment_slug' do
+ describe '.with_environment_name' do
let(:cluster) { create(:cluster, :group) }
- let(:environment) { create(:environment, slug: slug) }
+ let(:environment) { create(:environment, name: name) }
- let(:slug) { 'production' }
+ let(:name) { 'production' }
- subject { described_class.with_environment_slug(slug) }
+ subject { described_class.with_environment_name(name) }
context 'there is no associated environment' do
let!(:namespace) { create(:cluster_kubernetes_namespace, cluster: cluster, project: environment.project) }
@@ -48,12 +48,12 @@ RSpec.describe Clusters::KubernetesNamespace, type: :model do
)
end
- context 'with a matching slug' do
+ context 'with a matching name' do
it { is_expected.to eq [namespace] }
end
- context 'without a matching slug' do
- let(:environment) { create(:environment, slug: 'staging') }
+ context 'without a matching name' do
+ let(:environment) { create(:environment, name: 'staging') }
it { is_expected.to be_empty }
end
diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb
index 0c4cf291d20..64de6a8ab9b 100644
--- a/spec/models/clusters/platforms/kubernetes_spec.rb
+++ b/spec/models/clusters/platforms/kubernetes_spec.rb
@@ -218,7 +218,7 @@ describe Clusters::Platforms::Kubernetes do
before do
allow(Clusters::KubernetesNamespaceFinder).to receive(:new)
- .with(cluster, project: project, environment_slug: environment_slug)
+ .with(cluster, project: project, environment_name: environment_name)
.and_return(double(execute: persisted_namespace))
end