Commit 52c02bd8 authored by Phil Hughes's avatar Phil Hughes

Merge branch 'mw-onboarding-welcome-page-enhancements' into 'master'

Onboarding Welcome page: leverage onboarding utils and popover components

See merge request gitlab-org/gitlab-ee!13370
parents 00b3e945 934bd415
<script>
import { __ } from '~/locale';
import { GlLink, GlPopover } from '@gitlab/ui';
import { GlLink } from '@gitlab/ui';
import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
import HelpContentPopover from './../../onboarding_helper/components/help_content_popover.vue';
import ActionPopover from './../../onboarding_helper/components/action_popover.vue';
import { redirectTo } from '~/lib/utils/url_utility';
import onboardingUtils from './../../utils';
export default {
components: {
GlLink,
GlPopover,
UserAvatarImage,
HelpContentPopover,
ActionPopover,
},
props: {
userAvatarUrl: {
......@@ -31,20 +34,23 @@ export default {
helpText: __(
"Don't worry, you can access this tour by clicking on the help icon in the top right corner and choose <strong>Learn GitLab</strong>.",
),
helpPopover: {
target: null,
content: {
text: __('White helpers give contextual information.'),
buttons: [{ text: __('OK'), btnClass: 'btn-primary', disabled: true }],
},
},
actionPopover: {
target: null,
content: __('Blue helpers indicate an action to be taken.'),
cssClasses: ['blue'],
},
};
},
mounted() {
// workaround for appending a custom class to the bs popover which cannot be done via props
// see https://github.com/bootstrap-vue/bootstrap-vue/issues/1983
this.$root.$on('bv::popover::show', bvEventObj => {
const {
target: { dataset },
} = bvEventObj;
if (dataset.class) {
bvEventObj.relatedTarget.classList.add(dataset.class);
}
});
this.helpPopover.target = this.$refs.helpPopoverTrigger;
this.actionPopover.target = this.$refs.actionPopoverTrigger;
},
methods: {
startTour() {
......@@ -81,43 +87,40 @@ export default {
</p>
<div class="text-center mt-4 mb-4">
<div
id="popover-container"
id="js-popover-container"
class="popover-container d-flex justify-content-around align-items-end mb-8"
>
<button id="help-popover-trigger" type="button" class="btn-link btn-disabled"></button>
<button ref="helpPopoverTrigger" type="button" class="btn-link btn-disabled"></button>
<button
id="action-popover-trigger"
ref="actionPopoverTrigger"
type="button"
class="btn-link btn-disabled mb-3"
data-class="blue"
></button>
<gl-popover
target="help-popover-trigger"
<help-content-popover
v-if="helpPopover.target"
:target="helpPopover.target"
:help-content="helpPopover.content"
placement="top"
container="popover-container"
container="js-popover-container"
show
>
<p class="mb-2">
{{ __('White helpers give contextual information.') }}
</p>
<button disabled type="button" :aria-label="__('OK')" class="btn btn-xs popover-btn">
{{ __('OK') }}
</button>
</gl-popover>
<gl-popover
target="action-popover-trigger"
/>
<action-popover
v-if="actionPopover.target"
:target="actionPopover.target"
:content="actionPopover.content"
:css-classes="actionPopover.cssClasses"
placement="top"
container="popover-container"
show
>
{{ __('Blue helpers indicate an action to be taken.') }}
</gl-popover>
container="js-popover-container"
show-default
/>
</div>
<gl-link class="btn btn-success" @click="startTour">
<gl-link class="qa-start-tour-btn btn btn-success" @click="startTour">
{{ __("Ok let's go") }}
</gl-link>
<p class="small mt-8">
<gl-link @click="skipTour">
<gl-link class="qa-skip-tour-btn" @click="skipTour">
{{ __('Skip this for now') }}
</gl-link>
</p>
......@@ -130,11 +133,6 @@ export default {
.popover-container {
height: 140px;
}
.popover-btn[disabled] {
background-color: #1b69b6 !important;
border-color: #1b69b6 !important;
color: white !important;
}
p.large {
font-size: 16px;
}
......
import Vue from 'vue';
import component from 'ee/onboarding/onboarding_welcome/components/welcome_page.vue';
import ActionPopover from 'ee/onboarding/onboarding_helper/components/action_popover.vue';
import HelpContentPopover from 'ee/onboarding/onboarding_helper/components/help_content_popover.vue';
import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
import { shallowMount } from '@vue/test-utils';
import onboardingUtils from 'ee/onboarding/utils';
describe('User onboarding welcome page', () => {
let wrapper;
const props = {
userAvatarUrl: 'my-user.avatar.com',
projectFullPath: 'my-dummy-project/path',
skipUrl: 'skip.url.com',
};
afterEach(() => {
wrapper.destroy();
});
beforeEach(done => {
wrapper = shallowMount(component, { propsData: props });
Vue.nextTick(done);
});
describe('methods', () => {
describe('startTour', () => {
it('resets the localStorage', done => {
spyOnDependency(component, 'redirectTo');
spyOn(onboardingUtils, 'resetOnboardingLocalStorage').and.stub();
wrapper.vm
.$nextTick()
.then(() => wrapper.vm.startTour())
.then(wrapper.vm.$nextTick)
.then(() => {
expect(onboardingUtils.resetOnboardingLocalStorage).toHaveBeenCalled();
})
.then(done)
.catch(done.fail);
});
it('sets the dismissed property to false', done => {
spyOnDependency(component, 'redirectTo');
spyOn(onboardingUtils, 'updateOnboardingDismissed').and.stub();
wrapper.vm
.$nextTick()
.then(() => wrapper.vm.startTour())
.then(wrapper.vm.$nextTick)
.then(() => {
expect(onboardingUtils.updateOnboardingDismissed).toHaveBeenCalledWith(false);
})
.then(done)
.catch(done.fail);
});
it('redirects to the project path', done => {
const redirectSpy = spyOnDependency(component, 'redirectTo');
wrapper.vm
.$nextTick()
.then(() => wrapper.vm.startTour())
.then(wrapper.vm.$nextTick)
.then(() => {
expect(redirectSpy).toHaveBeenCalledWith(props.projectFullPath);
})
.then(done)
.catch(done.fail);
});
});
describe('skipTour', () => {
it('sets the dismissed property to true', done => {
spyOnDependency(component, 'redirectTo');
spyOn(onboardingUtils, 'updateOnboardingDismissed').and.stub();
wrapper.vm
.$nextTick()
.then(() => wrapper.vm.skipTour())
.then(wrapper.vm.$nextTick)
.then(() => {
expect(onboardingUtils.updateOnboardingDismissed).toHaveBeenCalledWith(true);
})
.then(done)
.catch(done.fail);
});
it('redirects to the skip url', done => {
const redirectSpy = spyOnDependency(component, 'redirectTo');
wrapper.vm
.$nextTick()
.then(() => wrapper.vm.skipTour())
.then(wrapper.vm.$nextTick)
.then(() => {
expect(redirectSpy).toHaveBeenCalledWith(props.skipUrl);
})
.then(done)
.catch(done.fail);
});
});
});
describe('template', () => {
it('renders the user avatar', () => {
const userAvatarImage = wrapper.find(UserAvatarImage);
expect(userAvatarImage.exists()).toBe(true);
expect(userAvatarImage.props('imgSrc')).toEqual(props.userAvatarUrl);
});
it('displays the title', () => {
expect(wrapper.text()).toContain('Hello there');
});
it('displays the subtitle', () => {
expect(wrapper.text()).toContain('Welcome to the Guided GitLab Tour');
});
it('displays the welcome text', () => {
expect(wrapper.text()).toContain(
'We created a short guided tour that will help you learn the basics of GitLab and how it will help you be better at your job. It should only take a couple of minutes. You willl be guided by two types of helpers, best recognized by their color.',
);
});
it('displays the help content popover', () => {
const helpContentPopover = wrapper.find(HelpContentPopover);
expect(helpContentPopover.exists()).toBe(true);
expect(helpContentPopover.props('helpContent').text).toEqual(
'White helpers give contextual information.',
);
});
it('displays the action popover', () => {
const actionPopover = wrapper.find(ActionPopover);
expect(actionPopover.exists()).toBe(true);
expect(actionPopover.props('content')).toEqual(
'Blue helpers indicate an action to be taken.',
);
});
it('displays the "Ok let\'s got" button', () => {
const btn = wrapper.find('.qa-start-tour-btn');
expect(btn.exists()).toBe(true);
expect(btn.text()).toContain("Ok let's go");
});
it('displays the "Skip this for now" link', () => {
const btn = wrapper.find('.qa-skip-tour-btn');
expect(btn.exists()).toBe(true);
expect(btn.text()).toContain('Skip this for now');
});
it('displays a note on how users can start the tour from the help menu', () => {
expect(wrapper.text()).toContain(
"Don't worry, you can access this tour by clicking on the help icon in the top right corner and choose Learn GitLab.",
);
});
});
});
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