Commit bd8a202d authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 59a34981
...@@ -6,7 +6,7 @@ const newClusterViews = [':clusters:new', ':clusters:create_gcp', ':clusters:cre ...@@ -6,7 +6,7 @@ const newClusterViews = [':clusters:new', ':clusters:create_gcp', ':clusters:cre
const isProjectLevelCluster = page => page.startsWith('project:clusters'); const isProjectLevelCluster = page => page.startsWith('project:clusters');
export default (document, gon) => { export default document => {
const { page } = document.body.dataset; const { page } = document.body.dataset;
const isNewClusterView = newClusterViews.some(view => page.endsWith(view)); const isNewClusterView = newClusterViews.some(view => page.endsWith(view));
...@@ -19,17 +19,15 @@ export default (document, gon) => { ...@@ -19,17 +19,15 @@ export default (document, gon) => {
initGkeDropdowns(); initGkeDropdowns();
if (gon.features.createEksClusters) { import(/* webpackChunkName: 'eks_cluster' */ '~/create_cluster/eks_cluster')
import(/* webpackChunkName: 'eks_cluster' */ '~/create_cluster/eks_cluster') .then(({ default: initCreateEKSCluster }) => {
.then(({ default: initCreateEKSCluster }) => { const el = document.querySelector('.js-create-eks-cluster-form-container');
const el = document.querySelector('.js-create-eks-cluster-form-container');
if (el) { if (el) {
initCreateEKSCluster(el); initCreateEKSCluster(el);
} }
}) })
.catch(() => {}); .catch(() => {});
}
if (isProjectLevelCluster(page)) { if (isProjectLevelCluster(page)) {
initGkeNamespace(); initGkeNamespace();
......
...@@ -12,9 +12,6 @@ class Clusters::ClustersController < Clusters::BaseController ...@@ -12,9 +12,6 @@ class Clusters::ClustersController < Clusters::BaseController
before_action :authorize_update_cluster!, only: [:update] before_action :authorize_update_cluster!, only: [:update]
before_action :authorize_admin_cluster!, only: [:destroy, :clear_cache] before_action :authorize_admin_cluster!, only: [:destroy, :clear_cache]
before_action :update_applications_status, only: [:cluster_status] before_action :update_applications_status, only: [:cluster_status]
before_action only: [:new, :create_gcp] do
push_frontend_feature_flag(:create_eks_clusters)
end
before_action only: [:show] do before_action only: [:show] do
push_frontend_feature_flag(:enable_cluster_application_elastic_stack) push_frontend_feature_flag(:enable_cluster_application_elastic_stack)
push_frontend_feature_flag(:enable_cluster_application_crossplane) push_frontend_feature_flag(:enable_cluster_application_crossplane)
...@@ -42,8 +39,6 @@ class Clusters::ClustersController < Clusters::BaseController ...@@ -42,8 +39,6 @@ class Clusters::ClustersController < Clusters::BaseController
end end
def new def new
return unless Feature.enabled?(:create_eks_clusters)
if params[:provider] == 'aws' if params[:provider] == 'aws'
@aws_role = current_user.aws_role || Aws::Role.new @aws_role = current_user.aws_role || Aws::Role.new
@aws_role.ensure_role_external_id! @aws_role.ensure_role_external_id!
...@@ -113,6 +108,7 @@ class Clusters::ClustersController < Clusters::BaseController ...@@ -113,6 +108,7 @@ class Clusters::ClustersController < Clusters::BaseController
generate_gcp_authorize_url generate_gcp_authorize_url
validate_gcp_token validate_gcp_token
user_cluster user_cluster
params[:provider] = 'gcp'
render :new, locals: { active_tab: 'create' } render :new, locals: { active_tab: 'create' }
end end
...@@ -277,8 +273,7 @@ class Clusters::ClustersController < Clusters::BaseController ...@@ -277,8 +273,7 @@ class Clusters::ClustersController < Clusters::BaseController
end end
def generate_gcp_authorize_url def generate_gcp_authorize_url
params = Feature.enabled?(:create_eks_clusters) ? { provider: :gke } : {} state = generate_session_key_redirect(clusterable.new_path(provider: :gcp).to_s)
state = generate_session_key_redirect(clusterable.new_path(params).to_s)
@authorize_url = GoogleApi::CloudPlatform::Client.new( @authorize_url = GoogleApi::CloudPlatform::Client.new(
nil, callback_google_api_auth_url, nil, callback_google_api_auth_url,
......
...@@ -26,13 +26,13 @@ module Projects ...@@ -26,13 +26,13 @@ module Projects
def delete_tags(tags_to_delete, tags_by_digest) def delete_tags(tags_to_delete, tags_by_digest)
deleted_digests = group_by_digest(tags_to_delete).select do |digest, tags| deleted_digests = group_by_digest(tags_to_delete).select do |digest, tags|
delete_tag_digest(digest, tags, tags_by_digest[digest]) delete_tag_digest(tags, tags_by_digest[digest])
end end
deleted_digests.values.flatten deleted_digests.values.flatten
end end
def delete_tag_digest(digest, tags, other_tags) def delete_tag_digest(tags, other_tags)
# Issue: https://gitlab.com/gitlab-org/gitlab-foss/issues/21405 # Issue: https://gitlab.com/gitlab-org/gitlab-foss/issues/21405
# we have to remove all tags due # we have to remove all tags due
# to Docker Distribution bug unable # to Docker Distribution bug unable
......
...@@ -24,32 +24,36 @@ module Projects ...@@ -24,32 +24,36 @@ module Projects
dummy_manifest = container_repository.client.generate_empty_manifest(container_repository.path) dummy_manifest = container_repository.client.generate_empty_manifest(container_repository.path)
return error('could not generate manifest') if dummy_manifest.nil? return error('could not generate manifest') if dummy_manifest.nil?
# update the manifests of the tags with the new dummy image deleted_tags = replace_tag_manifests(container_repository, dummy_manifest, tag_names)
deleted_tags = []
tag_digests = [] # Deletes the dummy image
# All created tag digests are the same since they all have the same dummy image.
# a single delete is sufficient to remove all tags with it
if deleted_tags.any? && container_repository.delete_tag_by_digest(deleted_tags.values.first)
success(deleted: deleted_tags.keys)
else
error('could not delete tags')
end
end
# update the manifests of the tags with the new dummy image
def replace_tag_manifests(container_repository, dummy_manifest, tag_names)
deleted_tags = {}
tag_names.each do |name| tag_names.each do |name|
digest = container_repository.client.put_tag(container_repository.path, name, dummy_manifest) digest = container_repository.client.put_tag(container_repository.path, name, dummy_manifest)
next unless digest next unless digest
deleted_tags << name deleted_tags[name] = digest
tag_digests << digest
end end
# make sure the digests are the same (it should always be) # make sure the digests are the same (it should always be)
tag_digests.uniq! digests = deleted_tags.values.uniq
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
Gitlab::Sentry.track_exception(ArgumentError.new('multiple tag digests')) if tag_digests.many? Gitlab::Sentry.track_exception(ArgumentError.new('multiple tag digests')) if digests.many?
# Deletes the dummy image deleted_tags
# All created tag digests are the same since they all have the same dummy image.
# a single delete is sufficient to remove all tags with it
if tag_digests.any? && container_repository.delete_tag_by_digest(tag_digests.first)
success(deleted: deleted_tags)
else
error('could not delete tags')
end
end end
end end
end end
......
...@@ -8,5 +8,5 @@ ...@@ -8,5 +8,5 @@
= render_if_exists 'admin/application_settings/slack' = render_if_exists 'admin/application_settings/slack'
= render 'admin/application_settings/third_party_offers' = render 'admin/application_settings/third_party_offers'
= render 'admin/application_settings/snowplow' = render 'admin/application_settings/snowplow'
= render 'admin/application_settings/eks' if Feature.enabled?(:create_eks_clusters) = render 'admin/application_settings/eks'
= render 'clusters/clusters/gcp/header' = render 'clusters/clusters/gcp/header'
- if @valid_gcp_token - if @valid_gcp_token
= render 'clusters/clusters/gcp/form' = render 'clusters/clusters/gcp/form'
- elsif @authorize_url
= render 'clusters/clusters/gcp/signin_with_google_button'
- else - else
= render 'clusters/clusters/gcp/gcp_not_configured' = render 'clusters/clusters/gcp/gcp_not_configured'
.signin-with-google
- create_account_link = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: 'https://accounts.google.com/SignUpWithoutGmail?service=cloudconsole&continue=https%3A%2F%2Fconsole.cloud.google.com%2Ffreetrial%3Futm_campaign%3D2018_cpanel%26utm_source%3Dgitlab%26utm_medium%3Dreferral' }
= link_to(image_tag('auth_buttons/signin_with_google.png', width: '191px', alt: _('Sign in with Google')), @authorize_url)
= s_('or %{link_start}create a new Google account%{link_end}').html_safe % { link_start: create_account_link, link_end: '</a>'.html_safe }
- breadcrumb_title _('Kubernetes') - breadcrumb_title _('Kubernetes')
- page_title _('Kubernetes Cluster') - page_title _('Kubernetes Cluster')
- create_eks_enabled = Feature.enabled?(:create_eks_clusters)
- active_tab = local_assigns.fetch(:active_tab, 'create') - active_tab = local_assigns.fetch(:active_tab, 'create')
= javascript_include_tag 'https://apis.google.com/js/api.js' = javascript_include_tag 'https://apis.google.com/js/api.js'
...@@ -14,21 +13,14 @@ ...@@ -14,21 +13,14 @@
%li.nav-item{ role: 'presentation' } %li.nav-item{ role: 'presentation' }
%a.nav-link{ href: '#create-cluster-pane', id: 'create-cluster-tab', class: active_when(active_tab == 'create'), data: { toggle: 'tab' }, role: 'tab' } %a.nav-link{ href: '#create-cluster-pane', id: 'create-cluster-tab', class: active_when(active_tab == 'create'), data: { toggle: 'tab' }, role: 'tab' }
%span %span
- if create_eks_enabled = create_new_cluster_label(provider: params[:provider])
= create_new_cluster_label(provider: params[:provider])
- else
= create_new_cluster_label(provider: 'gcp')
%li.nav-item{ role: 'presentation' } %li.nav-item{ role: 'presentation' }
%a.nav-link{ href: '#add-cluster-pane', id: 'add-cluster-tab', class: active_when(active_tab == 'add'), data: { toggle: 'tab' }, role: 'tab' } %a.nav-link{ href: '#add-cluster-pane', id: 'add-cluster-tab', class: active_when(active_tab == 'add'), data: { toggle: 'tab' }, role: 'tab' }
%span Add existing cluster %span Add existing cluster
.tab-content.gitlab-tab-content .tab-content.gitlab-tab-content
- if create_eks_enabled .tab-pane{ id: 'create-cluster-pane', class: active_when(active_tab == 'create'), role: 'tabpanel' }
.tab-pane{ id: 'create-cluster-pane', class: active_when(active_tab == 'create'), role: 'tabpanel' } = render new_cluster_partial(provider: params[:provider])
= render new_cluster_partial(provider: params[:provider])
- else
.tab-pane{ id: 'create-cluster-pane', class: active_when(active_tab == 'create'), role: 'tabpanel' }
= render new_cluster_partial(provider: 'gcp')
.tab-pane{ id: 'add-cluster-pane', class: active_when(active_tab == 'add'), role: 'tabpanel' } .tab-pane{ id: 'add-cluster-pane', class: active_when(active_tab == 'add'), role: 'tabpanel' }
= render 'clusters/clusters/user/header' = render 'clusters/clusters/user/header'
......
---
title: Enable creating Amazon EKS clusters from GitLab
merge_request: 20333
author:
type: added
...@@ -211,33 +211,9 @@ GitLab supports: ...@@ -211,33 +211,9 @@ GitLab supports:
Before creating your first cluster on Amazon EKS with GitLab's integration, Before creating your first cluster on Amazon EKS with GitLab's integration,
make sure the following requirements are met: make sure the following requirements are met:
- Self-managed GitLab instances have the `create_eks_clusters` feature flag enabled.
- An [Amazon Web Services](https://aws.amazon.com/) account is set up and you are able to log in. - An [Amazon Web Services](https://aws.amazon.com/) account is set up and you are able to log in.
- You have permissions to manage IAM resources. - You have permissions to manage IAM resources.
##### Enable the `create_eks_clusters` feature flag **(CORE ONLY)**
Self-managed instances must have the feature flag `create_eks_clusters` enabled to create
EKS clusters. To enable EKS cluster creation, ask a GitLab administrator with Rails console access
to run the following command:
```ruby
Feature.enable(:create_eks_clusters)
```
To have it enabled for a specific project only, ask a GitLab administrator to run the following
command using a Rails console:
```ruby
Feature.enable(:create_eks_clusters, Project.find_by_full_path('my_group/my_project'))
```
To have this feature disabled, ask a GitLab administrator to run the following command:
```ruby
Feature.disable(:create_eks_clusters)
```
##### Additional requirements for self-managed instances ##### Additional requirements for self-managed instances
If you are using a self-managed GitLab instance, GitLab must first If you are using a self-managed GitLab instance, GitLab must first
......
...@@ -15948,9 +15948,6 @@ msgstr "" ...@@ -15948,9 +15948,6 @@ msgstr ""
msgid "Sign in via 2FA code" msgid "Sign in via 2FA code"
msgstr "" msgstr ""
msgid "Sign in with Google"
msgstr ""
msgid "Sign in with Single Sign-On" msgid "Sign in with Single Sign-On"
msgstr "" msgstr ""
...@@ -21263,9 +21260,6 @@ msgstr "" ...@@ -21263,9 +21260,6 @@ msgstr ""
msgid "opened %{timeAgoString} by %{user}" msgid "opened %{timeAgoString} by %{user}"
msgstr "" msgstr ""
msgid "or %{link_start}create a new Google account%{link_end}"
msgstr ""
msgid "out of %d total test" msgid "out of %d total test"
msgid_plural "out of %d total tests" msgid_plural "out of %d total tests"
msgstr[0] "" msgstr[0] ""
......
...@@ -84,29 +84,11 @@ describe Admin::ClustersController do ...@@ -84,29 +84,11 @@ describe Admin::ClustersController do
GoogleApi::CloudPlatform::Client.session_key_for_redirect_uri(key) GoogleApi::CloudPlatform::Client.session_key_for_redirect_uri(key)
end end
before do context 'when selected provider is gke and no valid gcp token exists' do
stub_feature_flags(create_eks_clusters: false) it 'redirects to gcp authorize_url' do
allow(SecureRandom).to receive(:hex).and_return(key) get_new
end
it 'has authorize_url' do
get_new
expect(assigns(:authorize_url)).to include(key)
expect(session[session_key_for_redirect_uri]).to eq(new_admin_cluster_path)
end
context 'when create_eks_clusters feature flag is enabled' do
before do
stub_feature_flags(create_eks_clusters: true)
end
context 'when selected provider is gke and no valid gcp token exists' do
it 'redirects to gcp authorize_url' do
get_new
expect(response).to redirect_to(assigns(:authorize_url)) expect(response).to redirect_to(assigns(:authorize_url))
end
end end
end end
end end
......
...@@ -97,29 +97,15 @@ describe Groups::ClustersController do ...@@ -97,29 +97,15 @@ describe Groups::ClustersController do
end end
before do before do
stub_feature_flags(create_eks_clusters: false)
allow(SecureRandom).to receive(:hex).and_return(key) allow(SecureRandom).to receive(:hex).and_return(key)
end end
it 'has authorize_url' do it 'redirects to gcp authorize_url' do
go go
expect(assigns(:authorize_url)).to include(key) expect(assigns(:authorize_url)).to include(key)
expect(session[session_key_for_redirect_uri]).to eq(new_group_cluster_path(group)) expect(session[session_key_for_redirect_uri]).to eq(new_group_cluster_path(group, provider: :gcp))
end expect(response).to redirect_to(assigns(:authorize_url))
context 'when create_eks_clusters feature flag is enabled' do
before do
stub_feature_flags(create_eks_clusters: true)
end
context 'when selected provider is gke and no valid gcp token exists' do
it 'redirects to gcp authorize_url' do
go
expect(response).to redirect_to(assigns(:authorize_url))
end
end
end end
end end
......
...@@ -95,29 +95,15 @@ describe Projects::ClustersController do ...@@ -95,29 +95,15 @@ describe Projects::ClustersController do
end end
before do before do
stub_feature_flags(create_eks_clusters: false)
allow(SecureRandom).to receive(:hex).and_return(key) allow(SecureRandom).to receive(:hex).and_return(key)
end end
it 'has authorize_url' do it 'redirects to gcp authorize_url' do
go go
expect(assigns(:authorize_url)).to include(key) expect(assigns(:authorize_url)).to include(key)
expect(session[session_key_for_redirect_uri]).to eq(new_project_cluster_path(project)) expect(session[session_key_for_redirect_uri]).to eq(new_project_cluster_path(project, provider: :gcp))
end expect(response).to redirect_to(assigns(:authorize_url))
context 'when create_eks_clusters feature flag is enabled' do
before do
stub_feature_flags(create_eks_clusters: true)
end
context 'when selected provider is gke and no valid gcp token exists' do
it 'redirects to gcp authorize_url' do
go
expect(response).to redirect_to(assigns(:authorize_url))
end
end
end end
end end
......
...@@ -18,8 +18,6 @@ describe 'Gcp Cluster', :js do ...@@ -18,8 +18,6 @@ describe 'Gcp Cluster', :js do
let(:project_id) { 'test-project-1234' } let(:project_id) { 'test-project-1234' }
before do before do
stub_feature_flags(create_eks_clusters: false)
allow_any_instance_of(Projects::ClustersController) allow_any_instance_of(Projects::ClustersController)
.to receive(:token_in_session).and_return('token') .to receive(:token_in_session).and_return('token')
allow_any_instance_of(Projects::ClustersController) allow_any_instance_of(Projects::ClustersController)
...@@ -31,7 +29,8 @@ describe 'Gcp Cluster', :js do ...@@ -31,7 +29,8 @@ describe 'Gcp Cluster', :js do
visit project_clusters_path(project) visit project_clusters_path(project)
click_link 'Add Kubernetes cluster' click_link 'Add Kubernetes cluster'
click_link 'Create new Cluster on GKE' click_link 'Create new Cluster'
click_link 'Google GKE'
end end
context 'when user filled form with valid parameters' do context 'when user filled form with valid parameters' do
...@@ -147,21 +146,6 @@ describe 'Gcp Cluster', :js do ...@@ -147,21 +146,6 @@ describe 'Gcp Cluster', :js do
end end
end end
context 'when user has not signed with Google' do
before do
stub_feature_flags(create_eks_clusters: false)
visit project_clusters_path(project)
click_link 'Add Kubernetes cluster'
click_link 'Create new Cluster on GKE'
end
it 'user sees a login page' do
expect(page).to have_css('.signin-with-google')
expect(page).to have_link('Google account')
end
end
context 'when a user cannot edit the environment scope' do context 'when a user cannot edit the environment scope' do
before do before do
visit project_clusters_path(project) visit project_clusters_path(project)
...@@ -177,7 +161,6 @@ describe 'Gcp Cluster', :js do ...@@ -177,7 +161,6 @@ describe 'Gcp Cluster', :js do
context 'when user has not dismissed GCP signup offer' do context 'when user has not dismissed GCP signup offer' do
before do before do
stub_feature_flags(create_eks_clusters: false)
visit project_clusters_path(project) visit project_clusters_path(project)
end end
...@@ -190,18 +173,10 @@ describe 'Gcp Cluster', :js do ...@@ -190,18 +173,10 @@ describe 'Gcp Cluster', :js do
expect(page).to have_css('.gcp-signup-offer') expect(page).to have_css('.gcp-signup-offer')
end end
it 'user sees offer on cluster GCP login page' do
click_link 'Add Kubernetes cluster'
click_link 'Create new Cluster on GKE'
expect(page).to have_css('.gcp-signup-offer')
end
end end
context 'when user has dismissed GCP signup offer' do context 'when user has dismissed GCP signup offer' do
before do before do
stub_feature_flags(create_eks_clusters: false)
visit project_clusters_path(project) visit project_clusters_path(project)
end end
......
...@@ -49,41 +49,20 @@ describe 'Clusters', :js do ...@@ -49,41 +49,20 @@ describe 'Clusters', :js do
end end
end end
context 'when user has not signed in Google' do context 'user visits create cluster page' do
before do before do
stub_feature_flags(create_eks_clusters: false)
visit project_clusters_path(project) visit project_clusters_path(project)
click_link 'Add Kubernetes cluster' click_link 'Add Kubernetes cluster'
click_link 'Create new Cluster on GKE' click_link 'Create new Cluster'
end end
it 'user sees a login page' do it 'user sees a link to create a GKE cluster' do
expect(page).to have_css('.signin-with-google') expect(page).to have_link('Google GKE')
expect(page).to have_link('Google account')
end end
end
context 'when create_eks_clusters feature flag is enabled' do
before do
stub_feature_flags(create_eks_clusters: true)
end
context 'when user access create cluster page' do
before do
visit project_clusters_path(project)
click_link 'Add Kubernetes cluster' it 'user sees a link to create an EKS cluster' do
click_link 'Create new Cluster' expect(page).to have_link('Amazon EKS')
end
it 'user sees a link to create a GKE cluster' do
expect(page).to have_link('Google GKE')
end
it 'user sees a link to create an EKS cluster' do
expect(page).to have_link('Amazon EKS')
end
end end
end end
end end
...@@ -4,15 +4,14 @@ import diffModule from '~/diffs/store/modules'; ...@@ -4,15 +4,14 @@ import diffModule from '~/diffs/store/modules';
import SettingsDropdown from '~/diffs/components/settings_dropdown.vue'; import SettingsDropdown from '~/diffs/components/settings_dropdown.vue';
import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants'; import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('Diff settiings dropdown component', () => { describe('Diff settiings dropdown component', () => {
let vm; let vm;
let actions; let actions;
function createComponent(extendStore = () => {}) { function createComponent(extendStore = () => {}) {
const localVue = createLocalVue();
localVue.use(Vuex);
const store = new Vuex.Store({ const store = new Vuex.Store({
modules: { modules: {
diffs: { diffs: {
...@@ -26,9 +25,10 @@ describe('Diff settiings dropdown component', () => { ...@@ -26,9 +25,10 @@ describe('Diff settiings dropdown component', () => {
extendStore(store); extendStore(store);
vm = mount(SettingsDropdown, { vm = mount(localVue.extend(SettingsDropdown), {
localVue, localVue,
store, store,
sync: false,
}); });
} }
......
import Vue from 'vue';
import frequentItemsListItemComponent from '~/frequent_items/components/frequent_items_list_item.vue'; import frequentItemsListItemComponent from '~/frequent_items/components/frequent_items_list_item.vue';
import { shallowMount } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import { trimText } from 'spec/helpers/text_helper'; import { trimText } from 'spec/helpers/text_helper';
import { mockProject } from '../mock_data'; // can also use 'mockGroup', but not useful to test here import { mockProject } from '../mock_data'; // can also use 'mockGroup', but not useful to test here
const createComponent = () => { const localVue = createLocalVue();
const Component = Vue.extend(frequentItemsListItemComponent);
return shallowMount(Component, {
propsData: {
itemId: mockProject.id,
itemName: mockProject.name,
namespace: mockProject.namespace,
webUrl: mockProject.webUrl,
avatarUrl: mockProject.avatarUrl,
},
});
};
describe('FrequentItemsListItemComponent', () => { describe('FrequentItemsListItemComponent', () => {
let wrapper; let wrapper;
let vm;
beforeEach(() => {
wrapper = createComponent();
({ vm } = wrapper); const createComponent = (props = {}) => {
}); wrapper = shallowMount(localVue.extend(frequentItemsListItemComponent), {
propsData: {
itemId: mockProject.id,
itemName: mockProject.name,
namespace: mockProject.namespace,
webUrl: mockProject.webUrl,
avatarUrl: mockProject.avatarUrl,
...props,
},
sync: false,
localVue,
});
};
afterEach(() => { afterEach(() => {
vm.$destroy(); wrapper.destroy();
wrapper = null;
}); });
describe('computed', () => { describe('computed', () => {
describe('hasAvatar', () => { describe('hasAvatar', () => {
it('should return `true` or `false` if whether avatar is present or not', () => { it('should return `true` or `false` if whether avatar is present or not', () => {
wrapper.setProps({ avatarUrl: 'path/to/avatar.png' }); createComponent({ avatarUrl: 'path/to/avatar.png' });
expect(vm.hasAvatar).toBe(true); expect(wrapper.vm.hasAvatar).toBe(true);
});
wrapper.setProps({ avatarUrl: null }); it('should return `false` if avatar is not present', () => {
createComponent({ avatarUrl: null });
expect(vm.hasAvatar).toBe(false); expect(wrapper.vm.hasAvatar).toBe(false);
}); });
}); });
describe('highlightedItemName', () => { describe('highlightedItemName', () => {
it('should enclose part of project name in <b> & </b> which matches with `matcher` prop', () => { it('should enclose part of project name in <b> & </b> which matches with `matcher` prop', () => {
wrapper.setProps({ matcher: 'lab' }); createComponent({ matcher: 'lab' });
expect(wrapper.find('.js-frequent-items-item-title').html()).toContain( expect(wrapper.find('.js-frequent-items-item-title').html()).toContain(
'<b>L</b><b>a</b><b>b</b>', '<b>L</b><b>a</b><b>b</b>',
...@@ -55,7 +53,7 @@ describe('FrequentItemsListItemComponent', () => { ...@@ -55,7 +53,7 @@ describe('FrequentItemsListItemComponent', () => {
}); });
it('should return project name as it is if `matcher` is not available', () => { it('should return project name as it is if `matcher` is not available', () => {
wrapper.setProps({ matcher: null }); createComponent({ matcher: null });
expect(trimText(wrapper.find('.js-frequent-items-item-title').text())).toBe( expect(trimText(wrapper.find('.js-frequent-items-item-title').text())).toBe(
mockProject.name, mockProject.name,
...@@ -65,13 +63,13 @@ describe('FrequentItemsListItemComponent', () => { ...@@ -65,13 +63,13 @@ describe('FrequentItemsListItemComponent', () => {
describe('truncatedNamespace', () => { describe('truncatedNamespace', () => {
it('should truncate project name from namespace string', () => { it('should truncate project name from namespace string', () => {
wrapper.setProps({ namespace: 'platform / nokia-3310' }); createComponent({ namespace: 'platform / nokia-3310' });
expect(trimText(wrapper.find('.js-frequent-items-item-namespace').text())).toBe('platform'); expect(trimText(wrapper.find('.js-frequent-items-item-namespace').text())).toBe('platform');
}); });
it('should truncate namespace string from the middle if it includes more than two groups in path', () => { it('should truncate namespace string from the middle if it includes more than two groups in path', () => {
wrapper.setProps({ createComponent({
namespace: 'platform / hardware / broadcom / Wifi Group / Mobile Chipset / nokia-3310', namespace: 'platform / hardware / broadcom / Wifi Group / Mobile Chipset / nokia-3310',
}); });
...@@ -84,6 +82,8 @@ describe('FrequentItemsListItemComponent', () => { ...@@ -84,6 +82,8 @@ describe('FrequentItemsListItemComponent', () => {
describe('template', () => { describe('template', () => {
it('should render component element', () => { it('should render component element', () => {
createComponent();
expect(wrapper.classes()).toContain('frequent-items-list-item-container'); expect(wrapper.classes()).toContain('frequent-items-list-item-container');
expect(wrapper.findAll('a').length).toBe(1); expect(wrapper.findAll('a').length).toBe(1);
expect(wrapper.findAll('.frequent-items-item-avatar-container').length).toBe(1); expect(wrapper.findAll('.frequent-items-item-avatar-container').length).toBe(1);
......
import Vue from 'vue';
import searchComponent from '~/frequent_items/components/frequent_items_search_input.vue'; import searchComponent from '~/frequent_items/components/frequent_items_search_input.vue';
import eventHub from '~/frequent_items/event_hub'; import eventHub from '~/frequent_items/event_hub';
import { shallowMount } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
const createComponent = (namespace = 'projects') => { const localVue = createLocalVue();
const Component = Vue.extend(searchComponent);
return shallowMount(Component, { propsData: { namespace } }); const createComponent = (namespace = 'projects') =>
}; shallowMount(localVue.extend(searchComponent), {
propsData: { namespace },
localVue,
sync: false,
});
describe('FrequentItemsSearchInputComponent', () => { describe('FrequentItemsSearchInputComponent', () => {
let wrapper; let wrapper;
...@@ -40,7 +42,7 @@ describe('FrequentItemsSearchInputComponent', () => { ...@@ -40,7 +42,7 @@ describe('FrequentItemsSearchInputComponent', () => {
spyOn(eventHub, '$on'); spyOn(eventHub, '$on');
const vmX = createComponent().vm; const vmX = createComponent().vm;
Vue.nextTick(() => { localVue.nextTick(() => {
expect(eventHub.$on).toHaveBeenCalledWith( expect(eventHub.$on).toHaveBeenCalledWith(
`${vmX.namespace}-dropdownOpen`, `${vmX.namespace}-dropdownOpen`,
jasmine.any(Function), jasmine.any(Function),
...@@ -58,7 +60,7 @@ describe('FrequentItemsSearchInputComponent', () => { ...@@ -58,7 +60,7 @@ describe('FrequentItemsSearchInputComponent', () => {
vmX.$mount(); vmX.$mount();
vmX.$destroy(); vmX.$destroy();
Vue.nextTick(() => { localVue.nextTick(() => {
expect(eventHub.$off).toHaveBeenCalledWith( expect(eventHub.$off).toHaveBeenCalledWith(
`${vmX.namespace}-dropdownOpen`, `${vmX.namespace}-dropdownOpen`,
jasmine.any(Function), jasmine.any(Function),
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import { GlButton } from '@gitlab/ui'; import { GlButton } from '@gitlab/ui';
import Form from '~/jobs/components/manual_variables_form.vue'; import Form from '~/jobs/components/manual_variables_form.vue';
const localVue = createLocalVue();
describe('Manual Variables Form', () => { describe('Manual Variables Form', () => {
let wrapper; let wrapper;
const requiredProps = { const requiredProps = {
action: { action: {
path: '/play', path: '/play',
...@@ -14,8 +17,10 @@ describe('Manual Variables Form', () => { ...@@ -14,8 +17,10 @@ describe('Manual Variables Form', () => {
}; };
const factory = (props = {}) => { const factory = (props = {}) => {
wrapper = shallowMount(Form, { wrapper = shallowMount(localVue.extend(Form), {
propsData: props, propsData: props,
localVue,
sync: false,
}); });
}; };
...@@ -23,8 +28,15 @@ describe('Manual Variables Form', () => { ...@@ -23,8 +28,15 @@ describe('Manual Variables Form', () => {
factory(requiredProps); factory(requiredProps);
}); });
afterEach(() => { afterEach(done => {
wrapper.destroy(); // The component has a `nextTick` callback after some events so we need
// to wait for those to finish before destroying.
setImmediate(() => {
wrapper.destroy();
wrapper = null;
done();
});
}); });
it('renders empty form with correct placeholders', () => { it('renders empty form with correct placeholders', () => {
...@@ -71,7 +83,7 @@ describe('Manual Variables Form', () => { ...@@ -71,7 +83,7 @@ describe('Manual Variables Form', () => {
}); });
describe('when deleting a variable', () => { describe('when deleting a variable', () => {
it('removes the variable row', () => { beforeEach(done => {
wrapper.vm.variables = [ wrapper.vm.variables = [
{ {
key: 'new key', key: 'new key',
...@@ -80,6 +92,10 @@ describe('Manual Variables Form', () => { ...@@ -80,6 +92,10 @@ describe('Manual Variables Form', () => {
}, },
]; ];
wrapper.vm.$nextTick(done);
});
it('removes the variable row', () => {
wrapper.find(GlButton).vm.$emit('click'); wrapper.find(GlButton).vm.$emit('click');
expect(wrapper.vm.variables.length).toBe(0); expect(wrapper.vm.variables.length).toBe(0);
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import { GlColumnChart } from '@gitlab/ui/dist/charts'; import { GlColumnChart } from '@gitlab/ui/dist/charts';
import ColumnChart from '~/monitoring/components/charts/column.vue'; import ColumnChart from '~/monitoring/components/charts/column.vue';
const localVue = createLocalVue();
describe('Column component', () => { describe('Column component', () => {
let columnChart; let columnChart;
beforeEach(() => { beforeEach(() => {
columnChart = shallowMount(ColumnChart, { columnChart = shallowMount(localVue.extend(ColumnChart), {
propsData: { propsData: {
graphData: { graphData: {
queries: [ queries: [
...@@ -28,6 +30,8 @@ describe('Column component', () => { ...@@ -28,6 +30,8 @@ describe('Column component', () => {
}, },
containerWidth: 100, containerWidth: 100,
}, },
sync: false,
localVue,
}); });
}); });
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import EmptyChart from '~/monitoring/components/charts/empty_chart.vue'; import EmptyChart from '~/monitoring/components/charts/empty_chart.vue';
const localVue = createLocalVue();
describe('Empty Chart component', () => { describe('Empty Chart component', () => {
let emptyChart; let emptyChart;
const graphTitle = 'Memory Usage'; const graphTitle = 'Memory Usage';
beforeEach(() => { beforeEach(() => {
emptyChart = shallowMount(EmptyChart, { emptyChart = shallowMount(localVue.extend(EmptyChart), {
propsData: { propsData: {
graphTitle, graphTitle,
}, },
sync: false,
localVue,
}); });
}); });
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import SingleStatChart from '~/monitoring/components/charts/single_stat.vue'; import SingleStatChart from '~/monitoring/components/charts/single_stat.vue';
import { graphDataPrometheusQuery } from '../mock_data'; import { graphDataPrometheusQuery } from '../mock_data';
const localVue = createLocalVue();
describe('Single Stat Chart component', () => { describe('Single Stat Chart component', () => {
let singleStatChart; let singleStatChart;
beforeEach(() => { beforeEach(() => {
singleStatChart = shallowMount(SingleStatChart, { singleStatChart = shallowMount(localVue.extend(SingleStatChart), {
propsData: { propsData: {
graphData: graphDataPrometheusQuery, graphData: graphDataPrometheusQuery,
}, },
sync: false,
localVue,
}); });
}); });
......
...@@ -72,6 +72,17 @@ describe('Dashboard', () => { ...@@ -72,6 +72,17 @@ describe('Dashboard', () => {
let mock; let mock;
let store; let store;
let component; let component;
let wrapper;
const createComponentWrapper = (props = {}, options = {}) => {
wrapper = shallowMount(localVue.extend(DashboardComponent), {
localVue,
sync: false,
propsData: { ...propsData, ...props },
store,
...options,
});
};
beforeEach(() => { beforeEach(() => {
setFixtures(` setFixtures(`
...@@ -81,13 +92,16 @@ describe('Dashboard', () => { ...@@ -81,13 +92,16 @@ describe('Dashboard', () => {
store = createStore(); store = createStore();
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
DashboardComponent = Vue.extend(Dashboard); DashboardComponent = localVue.extend(Dashboard);
}); });
afterEach(() => { afterEach(() => {
if (component) { if (component) {
component.$destroy(); component.$destroy();
} }
if (wrapper) {
wrapper.destroy();
}
mock.restore(); mock.restore();
}); });
...@@ -123,15 +137,8 @@ describe('Dashboard', () => { ...@@ -123,15 +137,8 @@ describe('Dashboard', () => {
}); });
describe('cluster health', () => { describe('cluster health', () => {
let wrapper;
beforeEach(done => { beforeEach(done => {
wrapper = shallowMount(DashboardComponent, { createComponentWrapper({ hasMetrics: true });
localVue,
sync: false,
propsData: { ...propsData, hasMetrics: true },
store,
});
// all_dashboards is not defined in health dashboards // all_dashboards is not defined in health dashboards
wrapper.vm.$store.commit(`monitoringDashboard/${types.SET_ALL_DASHBOARDS}`, undefined); wrapper.vm.$store.commit(`monitoringDashboard/${types.SET_ALL_DASHBOARDS}`, undefined);
...@@ -383,7 +390,6 @@ describe('Dashboard', () => { ...@@ -383,7 +390,6 @@ describe('Dashboard', () => {
}); });
describe('drag and drop function', () => { describe('drag and drop function', () => {
let wrapper;
let expectedPanelCount; // also called metrics, naming to be improved: https://gitlab.com/gitlab-org/gitlab/issues/31565 let expectedPanelCount; // also called metrics, naming to be improved: https://gitlab.com/gitlab-org/gitlab/issues/31565
const findDraggables = () => wrapper.findAll(VueDraggable); const findDraggables = () => wrapper.findAll(VueDraggable);
...@@ -400,13 +406,7 @@ describe('Dashboard', () => { ...@@ -400,13 +406,7 @@ describe('Dashboard', () => {
}); });
beforeEach(done => { beforeEach(done => {
wrapper = shallowMount(DashboardComponent, { createComponentWrapper({ hasMetrics: true }, { attachToDocument: true });
localVue,
sync: false,
propsData: { ...propsData, hasMetrics: true },
store,
attachToDocument: true,
});
setupComponentStore(wrapper.vm); setupComponentStore(wrapper.vm);
...@@ -417,6 +417,10 @@ describe('Dashboard', () => { ...@@ -417,6 +417,10 @@ describe('Dashboard', () => {
wrapper.destroy(); wrapper.destroy();
}); });
afterEach(() => {
wrapper.destroy();
});
it('wraps vuedraggable', () => { it('wraps vuedraggable', () => {
expect(findDraggablePanels().exists()).toBe(true); expect(findDraggablePanels().exists()).toBe(true);
expect(findDraggablePanels().length).toEqual(expectedPanelCount); expect(findDraggablePanels().length).toEqual(expectedPanelCount);
...@@ -502,7 +506,6 @@ describe('Dashboard', () => { ...@@ -502,7 +506,6 @@ describe('Dashboard', () => {
// https://gitlab.com/gitlab-org/gitlab-ce/issues/66922 // https://gitlab.com/gitlab-org/gitlab-ce/issues/66922
// eslint-disable-next-line jasmine/no-disabled-tests // eslint-disable-next-line jasmine/no-disabled-tests
xdescribe('link to chart', () => { xdescribe('link to chart', () => {
let wrapper;
const currentDashboard = 'TEST_DASHBOARD'; const currentDashboard = 'TEST_DASHBOARD';
localVue.use(GlToast); localVue.use(GlToast);
const link = () => wrapper.find('.js-chart-link'); const link = () => wrapper.find('.js-chart-link');
...@@ -511,13 +514,7 @@ describe('Dashboard', () => { ...@@ -511,13 +514,7 @@ describe('Dashboard', () => {
beforeEach(done => { beforeEach(done => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse); mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
wrapper = shallowMount(DashboardComponent, { createComponentWrapper({ hasMetrics: true, currentDashboard }, { attachToDocument: true });
localVue,
sync: false,
attachToDocument: true,
propsData: { ...propsData, hasMetrics: true, currentDashboard },
store,
});
setTimeout(done); setTimeout(done);
}); });
...@@ -614,19 +611,12 @@ describe('Dashboard', () => { ...@@ -614,19 +611,12 @@ describe('Dashboard', () => {
}); });
describe('dashboard edit link', () => { describe('dashboard edit link', () => {
let wrapper;
const findEditLink = () => wrapper.find('.js-edit-link'); const findEditLink = () => wrapper.find('.js-edit-link');
beforeEach(done => { beforeEach(done => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse); mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
wrapper = shallowMount(DashboardComponent, { createComponentWrapper({ hasMetrics: true }, { attachToDocument: true });
localVue,
sync: false,
attachToDocument: true,
propsData: { ...propsData, hasMetrics: true },
store,
});
wrapper.vm.$store.commit( wrapper.vm.$store.commit(
`monitoringDashboard/${types.SET_ALL_DASHBOARDS}`, `monitoringDashboard/${types.SET_ALL_DASHBOARDS}`,
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import GraphGroup from '~/monitoring/components/graph_group.vue'; import GraphGroup from '~/monitoring/components/graph_group.vue';
const localVue = createLocalVue();
describe('Graph group component', () => { describe('Graph group component', () => {
let graphGroup; let graphGroup;
const findPrometheusGroup = () => graphGroup.find('.prometheus-graph-group'); const findPrometheusGroup = () => graphGroup.find('.prometheus-graph-group');
const findPrometheusPanel = () => graphGroup.find('.prometheus-panel'); const findPrometheusPanel = () => graphGroup.find('.prometheus-panel');
const createComponent = propsData => {
graphGroup = shallowMount(localVue.extend(GraphGroup), {
propsData,
sync: false,
localVue,
});
};
afterEach(() => { afterEach(() => {
graphGroup.destroy(); graphGroup.destroy();
}); });
describe('When groups can be collapsed', () => { describe('When groups can be collapsed', () => {
beforeEach(() => { beforeEach(() => {
graphGroup = shallowMount(GraphGroup, { createComponent({
propsData: { name: 'panel',
name: 'panel', collapseGroup: true,
collapseGroup: true,
},
}); });
}); });
...@@ -33,12 +42,10 @@ describe('Graph group component', () => { ...@@ -33,12 +42,10 @@ describe('Graph group component', () => {
describe('When groups can not be collapsed', () => { describe('When groups can not be collapsed', () => {
beforeEach(() => { beforeEach(() => {
graphGroup = shallowMount(GraphGroup, { createComponent({
propsData: { name: 'panel',
name: 'panel', collapseGroup: true,
collapseGroup: true, showPanels: false,
showPanels: false,
},
}); });
}); });
...@@ -49,12 +56,7 @@ describe('Graph group component', () => { ...@@ -49,12 +56,7 @@ describe('Graph group component', () => {
describe('When collapseGroup prop is updated', () => { describe('When collapseGroup prop is updated', () => {
beforeEach(() => { beforeEach(() => {
graphGroup = shallowMount(GraphGroup, { createComponent({ name: 'panel', collapseGroup: false });
propsData: {
name: 'panel',
collapseGroup: false,
},
});
}); });
it('previously collapsed group should respond to the prop change', done => { it('previously collapsed group should respond to the prop change', done => {
......
...@@ -2,15 +2,14 @@ import Vuex from 'vuex'; ...@@ -2,15 +2,14 @@ import Vuex from 'vuex';
import { createLocalVue, mount } from '@vue/test-utils'; import { createLocalVue, mount } from '@vue/test-utils';
import ReplyButton from '~/notes/components/note_actions/reply_button.vue'; import ReplyButton from '~/notes/components/note_actions/reply_button.vue';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('ReplyButton', () => { describe('ReplyButton', () => {
let wrapper; let wrapper;
beforeEach(() => { beforeEach(() => {
const localVue = createLocalVue(); wrapper = mount(localVue.extend(ReplyButton), {
localVue.use(Vuex);
wrapper = mount(ReplyButton, {
sync: false, sync: false,
localVue, localVue,
}); });
......
...@@ -12,7 +12,7 @@ describe('noteActions', () => { ...@@ -12,7 +12,7 @@ describe('noteActions', () => {
const shallowMountNoteActions = propsData => { const shallowMountNoteActions = propsData => {
const localVue = createLocalVue(); const localVue = createLocalVue();
return shallowMount(noteActions, { return shallowMount(localVue.extend(noteActions), {
store, store,
propsData, propsData,
localVue, localVue,
......
...@@ -14,7 +14,7 @@ describe('issue_note_form component', () => { ...@@ -14,7 +14,7 @@ describe('issue_note_form component', () => {
const createComponentWrapper = () => { const createComponentWrapper = () => {
const localVue = createLocalVue(); const localVue = createLocalVue();
return shallowMount(NoteForm, { return shallowMount(localVue.extend(NoteForm), {
store, store,
propsData: props, propsData: props,
// see https://gitlab.com/gitlab-org/gitlab-foss/issues/56317 for the following // see https://gitlab.com/gitlab-org/gitlab-foss/issues/56317 for the following
......
...@@ -10,6 +10,8 @@ import mockDiffFile from '../../diffs/mock_data/diff_file'; ...@@ -10,6 +10,8 @@ import mockDiffFile from '../../diffs/mock_data/diff_file';
const discussionWithTwoUnresolvedNotes = 'merge_requests/resolved_diff_discussion.json'; const discussionWithTwoUnresolvedNotes = 'merge_requests/resolved_diff_discussion.json';
const localVue = createLocalVue();
describe('noteable_discussion component', () => { describe('noteable_discussion component', () => {
let store; let store;
let wrapper; let wrapper;
...@@ -22,8 +24,7 @@ describe('noteable_discussion component', () => { ...@@ -22,8 +24,7 @@ describe('noteable_discussion component', () => {
store.dispatch('setNoteableData', noteableDataMock); store.dispatch('setNoteableData', noteableDataMock);
store.dispatch('setNotesData', notesDataMock); store.dispatch('setNotesData', notesDataMock);
const localVue = createLocalVue(); wrapper = mount(localVue.extend(noteableDiscussion), {
wrapper = mount(noteableDiscussion, {
store, store,
propsData: { discussion: discussionMock }, propsData: { discussion: discussionMock },
localVue, localVue,
......
...@@ -18,7 +18,7 @@ describe('issue_note', () => { ...@@ -18,7 +18,7 @@ describe('issue_note', () => {
store.dispatch('setNotesData', notesDataMock); store.dispatch('setNotesData', notesDataMock);
const localVue = createLocalVue(); const localVue = createLocalVue();
wrapper = shallowMount(issueNote, { wrapper = shallowMount(localVue.extend(issueNote), {
store, store,
propsData: { propsData: {
note, note,
......
...@@ -20,7 +20,7 @@ describe('RelatedMergeRequests', () => { ...@@ -20,7 +20,7 @@ describe('RelatedMergeRequests', () => {
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
mock.onGet(`${API_ENDPOINT}?per_page=100`).reply(200, mockData, { 'x-total': 2 }); mock.onGet(`${API_ENDPOINT}?per_page=100`).reply(200, mockData, { 'x-total': 2 });
wrapper = mount(RelatedMergeRequests, { wrapper = mount(localVue.extend(RelatedMergeRequests), {
localVue, localVue,
sync: false, sync: false,
store: createStore(), store: createStore(),
......
...@@ -4,18 +4,19 @@ import MrWidgetPipeline from '~/vue_merge_request_widget/components/mr_widget_pi ...@@ -4,18 +4,19 @@ import MrWidgetPipeline from '~/vue_merge_request_widget/components/mr_widget_pi
import ArtifactsApp from '~/vue_merge_request_widget/components/artifacts_list_app.vue'; import ArtifactsApp from '~/vue_merge_request_widget/components/artifacts_list_app.vue';
import { mockStore } from '../mock_data'; import { mockStore } from '../mock_data';
const localVue = createLocalVue();
describe('MrWidgetPipelineContainer', () => { describe('MrWidgetPipelineContainer', () => {
let wrapper; let wrapper;
const factory = (props = {}) => { const factory = (props = {}) => {
const localVue = createLocalVue();
wrapper = mount(localVue.extend(MrWidgetPipelineContainer), { wrapper = mount(localVue.extend(MrWidgetPipelineContainer), {
propsData: { propsData: {
mr: Object.assign({}, mockStore), mr: Object.assign({}, mockStore),
...props, ...props,
}, },
localVue, localVue,
sync: false,
}); });
}; };
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import GraphqlPagination from '~/vue_shared/components/pagination/graphql_pagination.vue'; import GraphqlPagination from '~/vue_shared/components/pagination/graphql_pagination.vue';
const localVue = createLocalVue();
describe('Graphql Pagination component', () => { describe('Graphql Pagination component', () => {
let wrapper; let wrapper;
function factory({ hasNextPage = true, hasPreviousPage = true }) { function factory({ hasNextPage = true, hasPreviousPage = true }) {
wrapper = shallowMount(GraphqlPagination, { wrapper = shallowMount(localVue.extend(GraphqlPagination), {
propsData: { propsData: {
hasNextPage, hasNextPage,
hasPreviousPage, hasPreviousPage,
}, },
sync: false,
localVue,
}); });
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment