Commit 52f25434 authored by Illya Klymov's avatar Illya Klymov

Merge branch 'xanf-better-ux-for-create-project' into 'master'

Resolve "Better UX for Project Creation"

See merge request gitlab-org/gitlab!32606
parents 79da9f33 6332e2ca
import initProjectVisibilitySelector from '../../../project_visibility';
import initProjectNew from '../../../projects/project_new';
import { __ } from '~/locale';
import createFlash from '~/flash';
import Tracking from '~/tracking';
document.addEventListener('DOMContentLoaded', () => {
initProjectVisibilitySelector();
initProjectNew.bindEvents();
const { category, property } = gon.tracking_data ?? { category: 'projects:new' };
const hasNewCreateProjectUi = 'newCreateProjectUi' in gon?.features;
if (!hasNewCreateProjectUi) {
// Setting additional tracking for HAML template
Array.from(
document.querySelectorAll('.project-edit-container [data-experiment-track-label]'),
).forEach(node =>
node.addEventListener('click', event => {
const { experimentTrackLabel: label } = event.currentTarget.dataset;
Tracking.event(category, 'click_tab', { property, label });
}),
);
} else {
import(
/* webpackChunkName: 'experiment_new_project_creation' */ '../../../projects/experiment_new_project_creation'
)
.then(m => {
const el = document.querySelector('.js-experiment-new-project-creation');
if (!el) {
return;
}
const config = {
hasErrors: 'hasErrors' in el.dataset,
isCiCdAvailable: 'isCiCdAvailable' in el.dataset,
};
m.default(el, config);
})
.catch(() => {
createFlash(__('An error occurred while loading project creation UI'));
});
}
});
<script>
import WelcomePage from './welcome.vue';
import LegacyContainer from './legacy_container.vue';
import { GlBreadcrumb, GlIcon } from '@gitlab/ui';
import { __, s__ } from '~/locale';
import blankProjectIllustration from '../illustrations/blank-project.svg';
import createFromTemplateIllustration from '../illustrations/create-from-template.svg';
import importProjectIllustration from '../illustrations/import-project.svg';
import ciCdProjectIllustration from '../illustrations/ci-cd-project.svg';
const BLANK_PANEL = 'blank_project';
const CI_CD_PANEL = 'cicd_for_external_repo';
const PANELS = [
{
name: BLANK_PANEL,
selector: '#blank-project-pane',
title: s__('ProjectsNew|Create blank project'),
description: s__(
'ProjectsNew|Create a blank project to house your files, plan your work, and collaborate on code, among other things.',
),
illustration: blankProjectIllustration,
},
{
name: 'create_from_template',
selector: '#create-from-template-pane',
title: s__('ProjectsNew|Create from template'),
description: s__(
'Create a project pre-populated with the necessary files to get you started quickly.',
),
illustration: createFromTemplateIllustration,
},
{
name: 'import_project',
selector: '#import-project-pane',
title: s__('ProjectsNew|Import project'),
description: s__(
'Migrate your data from an external source like GitHub, Bitbucket, or another instance of GitLab.',
),
illustration: importProjectIllustration,
},
{
name: CI_CD_PANEL,
selector: '#ci-cd-project-pane',
title: s__('ProjectsNew|Run CI/CD for external repository'),
description: s__('ProjectsNew|Connect your external repository to GitLab CI/CD.'),
illustration: ciCdProjectIllustration,
},
];
export default {
components: {
GlBreadcrumb,
GlIcon,
WelcomePage,
LegacyContainer,
},
props: {
hasErrors: {
type: Boolean,
required: false,
default: false,
},
isCiCdAvailable: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
activeTab: null,
};
},
computed: {
availablePanels() {
if (this.isCiCdAvailable) {
return PANELS;
}
return PANELS.filter(p => p.name !== CI_CD_PANEL);
},
activePanel() {
return PANELS.find(p => p.name === this.activeTab);
},
breadcrumbs() {
if (!this.activeTab || !this.activePanel) {
return null;
}
return [
{ text: __('New project'), href: '#' },
{ text: this.activePanel.title, href: `#${this.activeTab}` },
];
},
},
created() {
this.handleLocationHashChange();
if (this.hasErrors) {
this.activeTab = BLANK_PANEL;
}
window.addEventListener('hashchange', () => {
this.handleLocationHashChange();
this.resetProjectErrors();
});
this.$root.$on('clicked::link', e => {
window.location = e.target.href;
});
},
methods: {
resetProjectErrors() {
const errorsContainer = document.querySelector('.project-edit-errors');
if (errorsContainer) {
errorsContainer.innerHTML = '';
}
},
handleLocationHashChange() {
this.activeTab = window.location.hash.substring(1) || null;
},
},
PANELS,
};
</script>
<template>
<welcome-page v-if="activeTab === null" :panels="availablePanels" />
<div v-else class="row">
<div class="col-lg-3">
<div class="text-center" v-html="activePanel.illustration"></div>
<h4>{{ activePanel.title }}</h4>
<p>{{ activePanel.description }}</p>
</div>
<div class="col-lg-9">
<gl-breadcrumb v-if="breadcrumbs" :items="breadcrumbs">
<template #separator>
<gl-icon name="chevron-right" :size="8" />
</template>
</gl-breadcrumb>
<template v-for="panel in $options.PANELS">
<legacy-container
v-if="activeTab === panel.name"
:key="panel.name"
class="gl-mt-3"
:selector="panel.selector"
/>
</template>
</div>
</div>
</template>
<script>
export default {
inheritAttrs: false,
props: {
selector: {
type: String,
required: true,
},
},
mounted() {
const legacyEntry = document.querySelector(this.selector);
if (legacyEntry.tagName === 'TEMPLATE') {
this.$el.innerHTML = legacyEntry.innerHTML;
} else {
this.source = legacyEntry.parentNode;
this.$el.appendChild(legacyEntry);
}
},
beforeDestroy() {
if (this.source) {
this.source.appendChild(this.$el.firstChild);
}
},
};
</script>
<template>
<div></div>
</template>
<script>
import Tracking from '~/tracking';
import { GlPopover } from '@gitlab/ui';
import LegacyContainer from './legacy_container.vue';
const trackingMixin = Tracking.mixin(gon.tracking_data);
export default {
components: {
GlPopover,
LegacyContainer,
},
mixins: [trackingMixin],
props: {
panels: {
type: Array,
required: true,
},
},
};
</script>
<template>
<div class="container">
<div class="blank-state-welcome">
<h2 class="blank-state-welcome-title gl-mt-5! gl-mb-3!">
{{ s__('ProjectsNew|Create new project') }}
</h2>
<p div class="blank-state-text">&nbsp;</p>
</div>
<div class="row blank-state-row">
<a
v-for="panel in panels"
:key="panel.name"
:href="`#${panel.name}`"
class="blank-state blank-state-link experiment-new-project-page-blank-state"
@click="track('click_tab', { label: panel.name })"
>
<div class="blank-state-icon" v-html="panel.illustration"></div>
<div class="blank-state-body gl-pl-4!">
<h3 class="blank-state-title experiment-new-project-page-blank-state-title">
{{ panel.title }}
</h3>
<p class="blank-state-text">
{{ panel.description }}
</p>
</div>
</a>
</div>
<div class="blank-state-welcome">
<p>
{{ __('You can also create a project from the command line.') }}
<a
id="cli-tip"
href="#"
click.prevent
class="push-new-project-tip"
data-title="Push to create a project"
rel="noopener noreferrer"
>
{{ __('Show command') }}
</a>
<gl-popover target="cli-tip" triggers="click blur" placement="top">
<legacy-container selector=".push-new-project-tip-template" />
</gl-popover>
</p>
</div>
</div>
</template>
<?xml version="1.0" encoding="UTF-8"?>
<svg width="215px" height="115px" viewBox="0 0 215 115" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 61.2 (89653) - https://sketch.com -->
<title>create-new-project-md</title>
<desc>Created with Sketch.</desc>
<g id="create-new-project-md" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group-3" transform="translate(71.000000, 18.000000)" fill-rule="nonzero">
<g id="New-Blank1">
<path d="M6.11141667,3.90697674 L62.6947849,3.90697674 C65.9485064,3.90697674 68.5891473,6.56494969 68.5891473,9.8400273 L68.5891473,78.0669494 C68.5891473,81.342027 65.9485064,84 62.6947849,84 L6.11141667,84 C2.85769514,84 0.217054264,81.342027 0.217054264,78.0669494 L0.217054264,9.8400273 C0.217054264,6.56494969 2.85769514,3.90697674 6.11141667,3.90697674 Z" id="Path" fill="#F9F9F9"></path>
<path d="M8.89436241,1 L65.4777306,1 C68.7314521,1 71.372093,3.65598929 71.372093,6.9286227 L71.372093,74.5132378 C71.372093,77.7858712 68.7314521,80.4418605 65.4777306,80.4418605 L8.89436241,80.4418605 C5.64064088,80.4418605 3,77.7858712 3,74.5132378 L3,6.9286227 C3.00209243,3.65598929 5.64064088,1 8.89436241,1 Z" id="Path" fill="#FFFFFF"></path>
<path d="M9.2677971,2.35980136 C6.65357171,2.35980136 4.53489427,4.47043114 4.53489427,7.07940407 L4.53489427,74.3201325 C4.53489427,76.9270116 6.65147193,79.0397352 9.2677971,79.0397352 L66.0500324,79.0397352 C68.6642577,79.0397352 70.7829352,76.9291055 70.7829352,74.3201325 L70.7829352,7.07731019 C70.7829352,4.47043114 68.6663575,2.35770748 66.0500324,2.35770748 L9.2677971,2.35980136 L9.2677971,2.35980136 Z M9.2677971,0 L66.0500324,0 C69.9724203,0 73.1472868,3.16803856 73.1472868,7.07731019 L73.1472868,74.3180386 C73.1472868,78.2294042 69.9703205,81.3953488 66.0500324,81.3953488 L9.2677971,81.3953488 C5.34540913,81.3953488 2.17054264,78.2273103 2.17054264,74.3180386 L2.17054264,7.07731019 C2.17054264,3.17222631 5.34750891,0 9.2677971,0 Z" id="Shape" fill="#EEEEEE"></path>
<path d="M21.6234891,28.6511628 L28.9501543,28.6511628 C29.6221266,28.6511628 30.1705426,29.2387129 30.1705426,29.9534884 C30.1705426,30.6682639 29.6199589,31.255814 28.9501543,31.255814 L21.6234891,31.255814 C20.9515168,31.255814 20.4031008,30.6682639 20.4031008,29.9534884 C20.4031008,29.2387129 20.9515168,28.6511628 21.6234891,28.6511628 Z" id="Path" fill="#E1DBF1"></path>
<path d="M33.9142229,35.8139535 L36.1943042,35.8139535 C36.8214783,35.8139535 37.3333333,36.4015036 37.3333333,37.1162791 C37.3333333,37.8333678 36.8194552,38.4186047 36.1943042,38.4186047 L33.9142229,38.4186047 C33.2870488,38.4186047 32.7751938,37.8310546 32.7751938,37.1162791 C32.7751938,36.4015036 33.2890719,35.8139535 33.9142229,35.8139535 Z" id="Path" fill="#FC6D26"></path>
<path d="M24.200844,42.9767442 L28.9774506,42.9767442 C29.6343929,42.9767442 30.1705426,43.5642943 30.1705426,44.2790698 C30.1705426,44.9961585 29.6322737,45.5813953 28.9774506,45.5813953 L24.200844,45.5813953 C23.5439017,45.5813953 23.0077519,44.9938453 23.0077519,44.2790698 C23.0077519,43.5642943 23.5439017,42.9767442 24.200844,42.9767442 Z" id="Path" fill="#E1DBF1"></path>
<path d="M41.0770181,35.8139535 L43.3570964,35.8139535 C43.9842697,35.8139535 44.496124,36.4015036 44.496124,37.1162791 C44.496124,37.8333678 43.9822466,38.4186047 43.3570964,38.4186047 L41.0770181,38.4186047 C40.4498448,38.4186047 39.9379845,37.8310546 39.9379845,37.1162791 C39.9359673,36.4015036 40.4498448,35.8139535 41.0770181,35.8139535 Z" id="Path" fill="#FC6D26"></path>
<path d="M33.9372473,28.6511628 L47.89221,28.6511628 C48.5320619,28.6511628 49.0542636,29.2387129 49.0542636,29.9534884 C49.0542636,30.6682639 48.5299978,31.255814 47.89221,31.255814 L33.9372473,31.255814 C33.2973955,31.255814 32.7751938,30.6682639 32.7751938,29.9534884 C32.7751938,29.2387129 33.2994595,28.6511628 33.9372473,28.6511628 Z" id="Path" fill="#C3B8E3"></path>
<path d="M33.9142229,42.9767442 L36.1943042,42.9767442 C36.8214783,42.9767442 37.3333333,43.5642943 37.3333333,44.2790698 C37.3333333,44.9961585 36.8194552,45.5813953 36.1943042,45.5813953 L33.9142229,45.5813953 C33.2870488,45.5813953 32.7751938,44.9938453 32.7751938,44.2790698 C32.7751938,43.5642943 33.2890719,42.9767442 33.9142229,42.9767442 Z" id="Path" fill="#6B4FBB"></path>
<g id="Group" transform="translate(16.000000, 19.000000)">
<circle id="Oval" fill="#FFFFFF" cx="20.8396947" cy="20.8396947" r="20.7533889"></circle>
<path d="M20.8396947,41.5930835 C9.3778626,41.5930835 0.0863058062,32.3015267 0.0863058062,20.8396947 C0.0863058062,9.3778626 9.3778626,0.0863058062 20.8396947,0.0863058062 C32.3015267,0.0863058062 41.5930835,9.3778626 41.5930835,20.8396947 C41.5930835,32.3015267 32.3015267,41.5930835 20.8396947,41.5930835 Z M20.8396947,39.2207263 C30.9922045,39.2207263 39.2207263,30.9900995 39.2207263,20.8396947 C39.2207263,10.6892898 30.9900995,2.45866297 20.8396947,2.45866297 C10.6892898,2.45866297 2.45866297,10.6892898 2.45866297,20.8396947 C2.45866297,30.9900995 10.6871848,39.2207263 20.8396947,39.2207263 Z" id="Shape" fill="#EEEEEE"></path>
<path d="M13.7647236,19.060953 L27.9967615,19.060953 C28.6493176,19.060953 29.1818876,19.595628 29.1818876,20.2460791 C29.1818876,20.8986352 28.6472126,21.4312052 27.9967615,21.4312052 L13.7647236,21.4312052 C13.1121675,21.4312052 12.5795975,20.8965302 12.5795975,20.2460791 C12.5795975,19.593523 13.1142725,19.060953 13.7647236,19.060953 Z" id="Path" fill="#6B4FBB"></path>
<path d="M22.0669211,13.1311127 L22.0669211,27.3631506 C22.0669211,28.0157067 21.5322461,28.5482767 20.881795,28.5482767 C20.231344,28.5482767 19.696669,28.0136017 19.696669,27.3631506 L19.696669,13.1311127 C19.696669,12.4785566 20.231344,11.9459866 20.881795,11.9459866 C21.5322461,11.9459866 22.0669211,12.4785566 22.0669211,13.1311127 Z" id="Path" fill="#6B4FBB"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
import Vue from 'vue';
import NewProjectCreationApp from './components/app.vue';
export default function(el, props) {
return new Vue({
el,
components: {
NewProjectCreationApp,
},
render(h) {
return h(NewProjectCreationApp, { props });
},
});
}
......@@ -116,3 +116,17 @@
}
}
}
.experiment-new-project-page-blank-state {
@include media-breakpoint-down(md) {
flex-direction: column;
justify-content: center;
text-align: center;
}
}
$experiment-new-project-indigo-700: #41419f;
.experiment-new-project-page-blank-state-title {
color: $experiment-new-project-indigo-700;
}
......@@ -34,6 +34,12 @@ class ProjectsController < Projects::ApplicationController
# Project Export Rate Limit
before_action :export_rate_limit, only: [:export, :download_export, :generate_new_export]
# Experiments
before_action only: [:new, :create] do
frontend_experimentation_tracking_data(:new_create_project_ui, 'click_tab')
push_frontend_feature_flag(:new_create_project_ui) if experiment_enabled?(:new_create_project_ui)
end
layout :determine_layout
def index
......
......@@ -7,7 +7,11 @@
.project-edit-container.prepend-top-default
.project-edit-errors
= render 'projects/errors'
.row
- if experiment_enabled?(:new_create_project_ui)
.js-experiment-new-project-creation{ data: { is_ci_cd_available: ci_cd_projects_available?, has_errors: @project.errors.any? } }
.row{ 'v-cloak': experiment_enabled?(:new_create_project_ui) }
.col-lg-3.profile-settings-sidebar
%h4.gl-mt-0
= _('New project')
......@@ -32,15 +36,15 @@
.col-lg-9.js-toggle-container
%ul.nav.nav-tabs.nav-links.gitlab-tabs{ role: 'tablist' }
%li.nav-item{ role: 'presentation' }
%a.nav-link.active{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab', track_label: 'blank_project', track_event: "click_tab", track_value: "" }, role: 'tab' }
%a.nav-link.active{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab', experiment_track_label: 'blank_project' }, role: 'tab' }
%span.d-none.d-sm-block= s_('ProjectsNew|Blank project')
%span.d-block.d-sm-none= s_('ProjectsNew|Blank')
%li.nav-item{ role: 'presentation' }
%a.nav-link{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab', track_label: 'create_from_template', track_event: "click_tab", track_value: "" }, role: 'tab' }
%a.nav-link{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab', experiment_track_label: 'create_from_template' }, role: 'tab' }
%span.d-none.d-sm-block.qa-project-create-from-template-tab= s_('ProjectsNew|Create from template')
%span.d-block.d-sm-none= s_('ProjectsNew|Template')
%li.nav-item{ role: 'presentation' }
%a.nav-link{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab', track_label: 'import_project', track_event: "click_tab", track_value: "" }, role: 'tab' }
%a.nav-link{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab', experiment_track_label: 'import_project' }, role: 'tab' }
%span.d-none.d-sm-block= s_('ProjectsNew|Import project')
%span.d-block.d-sm-none= s_('ProjectsNew|Import')
= render_if_exists 'projects/new_ci_cd_only_project_tab', active_tab: active_tab
......
- return unless ci_cd_projects_available?
%li.nav-item{ class: active_when(active_tab == 'ci_cd_only'), role: 'presentation' }
%a.nav-link{ href: '#ci-cd-project-pane', id: 'ci-cd-project-tab', data: { toggle: 'tab', track_label: 'cicd_for_external_repo', track_event: "click_tab", track_value: "" }, role: 'tab' }
%a.nav-link{ href: '#ci-cd-project-pane', id: 'ci-cd-project-tab', data: { toggle: 'tab', experiment_track_label: 'cicd_for_external_repo' }, role: 'tab' }
%span.d-none.d-sm-block
= _('CI/CD for external repo')
%span.d-block.d-sm-none
......
......@@ -50,6 +50,9 @@ module Gitlab
},
invite_members_version_a: {
tracking_category: 'Growth::Expansion::Experiment::InviteMembersVersionA'
},
new_create_project_ui: {
tracking_category: 'Manage::Import::Experiment::NewCreateProjectUi'
}
}.freeze
......
......@@ -2317,6 +2317,9 @@ msgstr ""
msgid "An error occurred while loading milestones"
msgstr ""
msgid "An error occurred while loading project creation UI"
msgstr ""
msgid "An error occurred while loading terraform report"
msgstr ""
......@@ -6444,6 +6447,9 @@ msgstr ""
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr ""
msgid "Create a project pre-populated with the necessary files to get you started quickly."
msgstr ""
msgid "Create an account using:"
msgstr ""
......@@ -14047,6 +14053,9 @@ msgstr ""
msgid "Middleman project with Static Site Editor support"
msgstr ""
msgid "Migrate your data from an external source like GitHub, Bitbucket, or another instance of GitLab."
msgstr ""
msgid "Migrated %{success_count}/%{total_count} files."
msgstr ""
......@@ -17449,15 +17458,27 @@ msgstr ""
msgid "ProjectsNew|Blank project"
msgstr ""
msgid "ProjectsNew|Connect your external repository to GitLab CI/CD."
msgstr ""
msgid "ProjectsNew|Contact an administrator to enable options for importing your project."
msgstr ""
msgid "ProjectsNew|Create"
msgstr ""
msgid "ProjectsNew|Create a blank project to house your files, plan your work, and collaborate on code, among other things."
msgstr ""
msgid "ProjectsNew|Create blank project"
msgstr ""
msgid "ProjectsNew|Create from template"
msgstr ""
msgid "ProjectsNew|Create new project"
msgstr ""
msgid "ProjectsNew|Creating project & repository."
msgstr ""
......@@ -17482,6 +17503,9 @@ msgstr ""
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr ""
msgid "ProjectsNew|Run CI/CD for external repository"
msgstr ""
msgid "ProjectsNew|Template"
msgstr ""
......
......@@ -41,6 +41,27 @@ RSpec.describe ProjectsController do
end
end
end
context 'with the new_create_project_ui experiment enabled and the user is part of the control group' do
before do
stub_experiment(new_create_project_ui: true)
stub_experiment_for_user(new_create_project_ui: false)
allow_any_instance_of(described_class).to receive(:experimentation_subject_id).and_return('uuid')
end
it 'passes the right tracking parameters to the frontend' do
get(:new)
expect(Gon.tracking_data).to eq(
{
category: 'Manage::Import::Experiment::NewCreateProjectUi',
action: 'click_tab',
label: 'uuid',
property: 'control_group'
}
)
end
end
end
end
......
import { shallowMount } from '@vue/test-utils';
import { GlBreadcrumb } from '@gitlab/ui';
import App from '~/projects/experiment_new_project_creation/components/app.vue';
import WelcomePage from '~/projects/experiment_new_project_creation/components/welcome.vue';
import LegacyContainer from '~/projects/experiment_new_project_creation/components/legacy_container.vue';
describe('Experimental new project creation app', () => {
let wrapper;
const createComponent = propsData => {
wrapper = shallowMount(App, { propsData });
};
afterEach(() => {
wrapper.destroy();
window.location.hash = '';
wrapper = null;
});
describe('with empty hash', () => {
beforeEach(() => {
createComponent();
});
it('renders welcome page', () => {
expect(wrapper.find(WelcomePage).exists()).toBe(true);
});
it('does not render breadcrumbs', () => {
expect(wrapper.find(GlBreadcrumb).exists()).toBe(false);
});
});
it('renders blank project container if there are errors', () => {
createComponent({ hasErrors: true });
expect(wrapper.find(WelcomePage).exists()).toBe(false);
expect(wrapper.find(LegacyContainer).exists()).toBe(true);
});
describe('when hash is not empty on load', () => {
beforeEach(() => {
window.location.hash = '#blank_project';
createComponent();
});
it('renders relevant container', () => {
expect(wrapper.find(WelcomePage).exists()).toBe(false);
expect(wrapper.find(LegacyContainer).exists()).toBe(true);
});
it('renders breadcrumbs', () => {
expect(wrapper.find(GlBreadcrumb).exists()).toBe(true);
});
});
it('renders relevant container when hash changes', () => {
createComponent();
expect(wrapper.find(WelcomePage).exists()).toBe(true);
window.location.hash = '#blank_project';
const ev = document.createEvent('HTMLEvents');
ev.initEvent('hashchange', false, false);
window.dispatchEvent(ev);
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.find(WelcomePage).exists()).toBe(false);
expect(wrapper.find(LegacyContainer).exists()).toBe(true);
});
});
});
import { shallowMount } from '@vue/test-utils';
import LegacyContainer from '~/projects/experiment_new_project_creation/components/legacy_container.vue';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
describe('Legacy container component', () => {
let wrapper;
let dummy;
const createComponent = propsData => {
wrapper = shallowMount(LegacyContainer, { propsData });
};
afterEach(() => {
wrapper.destroy();
resetHTMLFixture();
wrapper = null;
});
describe('when selector targets real node', () => {
beforeEach(() => {
setHTMLFixture('<div class="dummy-target"></div>');
dummy = document.querySelector('.dummy-target');
createComponent({ selector: '.dummy-target' });
});
it('moves node inside component when mounted', () => {
expect(dummy.parentNode).toBe(wrapper.element);
});
it('moves node back when unmounted', () => {
wrapper.destroy();
expect(dummy.parentNode).toBe(document.body);
});
});
describe('when selector targets template node', () => {
beforeEach(() => {
setHTMLFixture('<template class="dummy-target">content</template>');
dummy = document.querySelector('.dummy-target');
createComponent({ selector: '.dummy-target' });
});
it('copies node content when mounted', () => {
expect(dummy.innerHTML).toEqual(wrapper.element.innerHTML);
expect(dummy.parentNode).toBe(document.body);
});
});
});
import { shallowMount } from '@vue/test-utils';
import WelcomePage from '~/projects/experiment_new_project_creation/components/welcome.vue';
import { mockTracking } from 'helpers/tracking_helper';
describe('Welcome page', () => {
let wrapper;
let trackingSpy;
const createComponent = propsData => {
wrapper = shallowMount(WelcomePage, { propsData });
};
beforeEach(() => {
trackingSpy = mockTracking('_category_', document, jest.spyOn);
trackingSpy.mockImplementation(() => {});
});
afterEach(() => {
wrapper.destroy();
window.location.hash = '';
wrapper = null;
});
it('tracks link clicks', () => {
createComponent({ panels: [{ name: 'test', href: '#' }] });
wrapper.find('a').trigger('click');
return wrapper.vm.$nextTick().then(() => {
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_tab', { label: 'test' });
});
});
});
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