Commit 7a3b67c6 authored by Martin Wortschack's avatar Martin Wortschack

Merge branch...

Merge branch '197952-convert-jest-tests-to-use-vtu-in-spec-frontend-vue_shared-components' into 'master'

Convert Jest tests to use VTU in 'spec/frontend/vue_shared'

Closes #197952

See merge request gitlab-org/gitlab!23501
parents 0768943e 6a3b4071
......@@ -59,21 +59,25 @@ export default {
</script>
<template>
<div>
<div v-if="!isLocalStorageAvailable" class="dropdown-info-note">
<div v-if="!isLocalStorageAvailable" ref="localStorageNote" class="dropdown-info-note">
{{ __('This feature requires local storage to be enabled') }}
</div>
<ul v-else-if="hasItems">
<li v-for="(item, index) in processedItems" :key="`processed-items-${index}`">
<li
v-for="(item, index) in processedItems"
ref="dropdownItem"
:key="`processed-items-${index}`"
>
<button
type="button"
class="filtered-search-history-dropdown-item"
class="filtered-search-history-dropdown-item js-dropdown-button"
@click="onItemActivated(item.text)"
>
<span>
<span
v-for="(token, tokenIndex) in item.tokens"
:key="`dropdown-token-${tokenIndex}`"
class="filtered-search-history-dropdown-token"
class="filtered-search-history-dropdown-token js-dropdown-token"
>
<span class="name">{{ token.prefix }}</span>
<span class="name">{{ token.operator }}</span>
......@@ -88,6 +92,7 @@ export default {
<li class="divider"></li>
<li>
<button
ref="clearButton"
type="button"
class="filtered-search-history-clear-button"
@click="onRequestClearRecentSearches($event)"
......@@ -96,6 +101,8 @@ export default {
</button>
</li>
</ul>
<div v-else class="dropdown-info-note">{{ __("You don't have any recent searches") }}</div>
<div v-else ref="dropdownNote" class="dropdown-info-note">
{{ __("You don't have any recent searches") }}
</div>
</div>
</template>
......@@ -29,7 +29,7 @@ export default {
</script>
<template>
<div :class="[sizeClass, identiconBackgroundClass]" class="avatar identicon">
<div ref="identicon" :class="[sizeClass, identiconBackgroundClass]" class="avatar identicon">
{{ identiconTitle }}
</div>
</template>
......@@ -65,14 +65,14 @@ export default {
<div class="issuable-note-warning">
<icon v-if="!isLockedAndConfidential" :name="warningIcon" :size="16" class="icon inline" />
<span v-if="isLockedAndConfidential">
<span v-if="isLockedAndConfidential" ref="lockedAndConfidential">
<span v-html="confidentialAndLockedDiscussionText"></span>
{{
__("People without permission will never get a notification and won't be able to comment.")
}}
</span>
<span v-else-if="isConfidential">
<span v-else-if="isConfidential" ref="confidential">
{{ __('This is a confidential issue.') }}
{{ __('People without permission will never get a notification.') }}
<gl-link :href="confidentialIssueDocsPath" target="_blank">
......@@ -80,7 +80,7 @@ export default {
</gl-link>
</span>
<span v-else-if="isLocked">
<span v-else-if="isLocked" ref="locked">
{{ __('This issue is locked.') }}
{{ __('Only project members can comment.') }}
<gl-link :href="lockedIssueDocsPath" target="_blank">
......
......@@ -47,7 +47,7 @@ export default {
:img-size="40"
/>
</div>
<div :class="{ discussion: !note.individual_note }" class="timeline-content">
<div ref="note" :class="{ discussion: !note.individual_note }" class="timeline-content">
<div class="note-header">
<div class="note-header-info">
<a :href="getUserData.path">
......
import Vue from 'vue';
import { shallowMount } from '@vue/test-utils';
import eventHub from '~/filtered_search/event_hub';
import RecentSearchesDropdownContent from '~/filtered_search/components/recent_searches_dropdown_content.vue';
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
const createComponent = propsData => {
const Component = Vue.extend(RecentSearchesDropdownContent);
describe('Recent Searches Dropdown Content', () => {
let wrapper;
return new Component({
el: document.createElement('div'),
propsData,
});
};
// Remove all the newlines and whitespace from the formatted markup
const trimMarkupWhitespace = text => text.replace(/(\n|\s)+/gm, ' ').trim();
const findLocalStorageNote = () => wrapper.find({ ref: 'localStorageNote' });
const findDropdownItems = () => wrapper.findAll({ ref: 'dropdownItem' });
const findDropdownNote = () => wrapper.find({ ref: 'dropdownNote' });
describe('RecentSearchesDropdownContent', () => {
const propsDataWithoutItems = {
items: [],
allowedKeys: IssuableFilteredSearchTokenKeys.getKeys(),
};
const propsDataWithItems = {
items: ['foo', 'author:@root label:~foo bar'],
const createComponent = props => {
wrapper = shallowMount(RecentSearchesDropdownContent, {
propsData: {
allowedKeys: IssuableFilteredSearchTokenKeys.getKeys(),
items: [],
isLocalStorageAvailable: false,
...props,
},
});
};
let vm;
afterEach(() => {
if (vm) {
vm.$destroy();
}
wrapper.destroy();
wrapper = null;
});
describe('with no items', () => {
let el;
describe('when local storage is not available', () => {
beforeEach(() => {
vm = createComponent(propsDataWithoutItems);
el = vm.$el;
createComponent();
});
it('should render empty state', () => {
expect(el.querySelector('.dropdown-info-note')).toBeDefined();
const items = el.querySelectorAll('.filtered-search-history-dropdown-item');
expect(items.length).toEqual(propsDataWithoutItems.items.length);
});
it('renders a note about enabling local storage', () => {
expect(findLocalStorageNote().exists()).toBe(true);
});
describe('with items', () => {
let el;
beforeEach(() => {
vm = createComponent(propsDataWithItems);
el = vm.$el;
it('does not render dropdown items', () => {
expect(findDropdownItems().exists()).toBe(false);
});
it('should render clear recent searches button', () => {
expect(el.querySelector('.filtered-search-history-clear-button')).toBeDefined();
});
it('should render recent search items', () => {
const items = el.querySelectorAll('.filtered-search-history-dropdown-item');
expect(items.length).toEqual(propsDataWithItems.items.length);
expect(
trimMarkupWhitespace(
items[0].querySelector('.filtered-search-history-dropdown-search-token').textContent,
),
).toEqual('foo');
const item1Tokens = items[1].querySelectorAll('.filtered-search-history-dropdown-token');
expect(item1Tokens.length).toEqual(2);
expect(item1Tokens[0].querySelector('.name').textContent).toEqual('author:');
expect(item1Tokens[0].querySelector('.value').textContent).toEqual('@root');
expect(item1Tokens[1].querySelector('.name').textContent).toEqual('label:');
expect(item1Tokens[1].querySelector('.value').textContent).toEqual('~foo');
expect(
trimMarkupWhitespace(
items[1].querySelector('.filtered-search-history-dropdown-search-token').textContent,
),
).toEqual('bar');
it('does not render dropdownNote', () => {
expect(findDropdownNote().exists()).toBe(false);
});
});
describe('if isLocalStorageAvailable is `false`', () => {
let el;
beforeEach(() => {
const props = Object.assign({ isLocalStorageAvailable: false }, propsDataWithItems);
describe('when localStorage is available and items array is not empty', () => {
let onRecentSearchesItemSelectedSpy;
let onRequestClearRecentSearchesSpy;
vm = createComponent(props);
el = vm.$el;
beforeAll(() => {
onRecentSearchesItemSelectedSpy = jest.fn();
onRequestClearRecentSearchesSpy = jest.fn();
eventHub.$on('recentSearchesItemSelected', onRecentSearchesItemSelectedSpy);
eventHub.$on('requestClearRecentSearches', onRequestClearRecentSearchesSpy);
});
it('should render an info note', () => {
const note = el.querySelector('.dropdown-info-note');
const items = el.querySelectorAll('.filtered-search-history-dropdown-item');
expect(note).toBeDefined();
expect(note.innerText.trim()).toBe('This feature requires local storage to be enabled');
expect(items.length).toEqual(propsDataWithoutItems.items.length);
beforeEach(() => {
createComponent({
items: ['foo', 'author:@root label:~foo bar'],
isLocalStorageAvailable: true,
});
});
describe('computed', () => {
describe('processedItems', () => {
it('with items', () => {
vm = createComponent(propsDataWithItems);
const { processedItems } = vm;
expect(processedItems.length).toEqual(2);
expect(processedItems[0].text).toEqual(propsDataWithItems.items[0]);
expect(processedItems[0].tokens).toEqual([]);
expect(processedItems[0].searchToken).toEqual('foo');
expect(processedItems[1].text).toEqual(propsDataWithItems.items[1]);
expect(processedItems[1].tokens.length).toEqual(2);
expect(processedItems[1].tokens[0].prefix).toEqual('author:');
expect(processedItems[1].tokens[0].suffix).toEqual('@root');
expect(processedItems[1].tokens[1].prefix).toEqual('label:');
expect(processedItems[1].tokens[1].suffix).toEqual('~foo');
expect(processedItems[1].searchToken).toEqual('bar');
afterAll(() => {
eventHub.$off('recentSearchesItemSelected', onRecentSearchesItemSelectedSpy);
eventHub.$off('requestClearRecentSearchesSpy', onRequestClearRecentSearchesSpy);
});
it('with no items', () => {
vm = createComponent(propsDataWithoutItems);
const { processedItems } = vm;
expect(processedItems.length).toEqual(0);
});
it('does not render a note about enabling local storage', () => {
expect(findLocalStorageNote().exists()).toBe(false);
});
describe('hasItems', () => {
it('with items', () => {
vm = createComponent(propsDataWithItems);
const { hasItems } = vm;
expect(hasItems).toEqual(true);
it('does not render dropdownNote', () => {
expect(findDropdownNote().exists()).toBe(false);
});
it('with no items', () => {
vm = createComponent(propsDataWithoutItems);
const { hasItems } = vm;
expect(hasItems).toEqual(false);
it('renders a correct amount of dropdown items', () => {
expect(findDropdownItems()).toHaveLength(2);
});
});
});
describe('methods', () => {
describe('onItemActivated', () => {
let onRecentSearchesItemSelectedSpy;
beforeEach(() => {
onRecentSearchesItemSelectedSpy = jest.fn();
eventHub.$on('recentSearchesItemSelected', onRecentSearchesItemSelectedSpy);
vm = createComponent(propsDataWithItems);
it('expect second dropdown to have 2 tokens', () => {
expect(
findDropdownItems()
.at(1)
.findAll('.js-dropdown-token'),
).toHaveLength(2);
});
afterEach(() => {
eventHub.$off('recentSearchesItemSelected', onRecentSearchesItemSelectedSpy);
it('emits recentSearchesItemSelected on dropdown item click', () => {
findDropdownItems()
.at(0)
.find('.js-dropdown-button')
.trigger('click');
expect(onRecentSearchesItemSelectedSpy).toHaveBeenCalledWith('foo');
});
it('emits event', () => {
expect(onRecentSearchesItemSelectedSpy).not.toHaveBeenCalled();
vm.onItemActivated('something');
it('emits requestClearRecentSearches on Clear resent searches button', () => {
wrapper.find({ ref: 'clearButton' }).trigger('click');
expect(onRecentSearchesItemSelectedSpy).toHaveBeenCalledWith('something');
expect(onRequestClearRecentSearchesSpy).toHaveBeenCalled();
});
});
describe('onRequestClearRecentSearches', () => {
let onRequestClearRecentSearchesSpy;
describe('when locale storage is available and items array is empty', () => {
beforeEach(() => {
onRequestClearRecentSearchesSpy = jest.fn();
eventHub.$on('requestClearRecentSearches', onRequestClearRecentSearchesSpy);
vm = createComponent(propsDataWithItems);
createComponent({
isLocalStorageAvailable: true,
});
afterEach(() => {
eventHub.$off('requestClearRecentSearches', onRequestClearRecentSearchesSpy);
});
it('emits event', () => {
expect(onRequestClearRecentSearchesSpy).not.toHaveBeenCalled();
vm.onRequestClearRecentSearches({ stopPropagation: () => {} });
it('does not render a note about enabling local storage', () => {
expect(findLocalStorageNote().exists()).toBe(false);
});
expect(onRequestClearRecentSearchesSpy).toHaveBeenCalled();
it('does not render dropdown items', () => {
expect(findDropdownItems().exists()).toBe(false);
});
it('renders dropdown note', () => {
expect(findDropdownNote().exists()).toBe(true);
});
});
});
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Code Block matches snapshot 1`] = `
<pre
class="code-block rounded"
>
<code
class="d-block"
>
test-code
</code>
</pre>
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Identicon matches snapshot 1`] = `
<div
class="avatar identicon s40 bg2"
>
E
</div>
`;
import Vue from 'vue';
import component from '~/vue_shared/components/code_block.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
import { shallowMount } from '@vue/test-utils';
import CodeBlock from '~/vue_shared/components/code_block.vue';
describe('Code Block', () => {
const Component = Vue.extend(component);
let vm;
let wrapper;
afterEach(() => {
vm.$destroy();
});
it('renders a code block with the provided code', () => {
const code =
"Failure/Error: is_expected.to eq(3)\n\n expected: 3\n got: -1\n\n (compared using ==)\n./spec/test_spec.rb:12:in `block (4 levels) in \u003ctop (required)\u003e'";
vm = mountComponent(Component, {
code,
const createComponent = () => {
wrapper = shallowMount(CodeBlock, {
propsData: {
code: 'test-code',
},
});
};
expect(vm.$el.querySelector('code').textContent).toEqual(code);
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('escapes XSS injections', () => {
const code = 'CCC&lt;img src=x onerror=alert(document.domain)&gt;';
vm = mountComponent(Component, {
code,
});
it('matches snapshot', () => {
createComponent();
expect(vm.$el.querySelector('code').textContent).toEqual(code);
expect(wrapper.element).toMatchSnapshot();
});
});
import Vue from 'vue';
import identiconComponent from '~/vue_shared/components/identicon.vue';
import { shallowMount } from '@vue/test-utils';
import IdenticonComponent from '~/vue_shared/components/identicon.vue';
const createComponent = sizeClass => {
const Component = Vue.extend(identiconComponent);
describe('Identicon', () => {
let wrapper;
return new Component({
const createComponent = () => {
wrapper = shallowMount(IdenticonComponent, {
propsData: {
entityId: 1,
entityName: 'entity-name',
sizeClass,
sizeClass: 's40',
},
}).$mount();
};
describe('IdenticonComponent', () => {
describe('computed', () => {
let vm;
beforeEach(() => {
vm = createComponent();
});
};
afterEach(() => {
vm.$destroy();
});
describe('identiconBackgroundClass', () => {
it('should return bg class based on entityId', () => {
vm.entityId = 4;
expect(vm.identiconBackgroundClass).toBeDefined();
expect(vm.identiconBackgroundClass).toBe('bg5');
});
wrapper.destroy();
wrapper = null;
});
describe('identiconTitle', () => {
it('should return first letter of entity title in uppercase', () => {
vm.entityName = 'dummy-group';
it('matches snapshot', () => {
createComponent();
expect(vm.identiconTitle).toBeDefined();
expect(vm.identiconTitle).toBe('D');
expect(wrapper.element).toMatchSnapshot();
});
});
});
describe('template', () => {
it('should render identicon', () => {
const vm = createComponent();
expect(vm.$el.nodeName).toBe('DIV');
expect(vm.$el.classList.contains('identicon')).toBeTruthy();
expect(vm.$el.classList.contains('s40')).toBeTruthy();
expect(vm.$el.classList.contains('bg2')).toBeTruthy();
vm.$destroy();
});
it('should render identicon with provided sizing class', () => {
const vm = createComponent('s32');
it('adds a correct class to identicon', () => {
createComponent();
expect(vm.$el.classList.contains('s32')).toBeTruthy();
vm.$destroy();
});
expect(wrapper.find({ ref: 'identicon' }).classes()).toContain('bg2');
});
});
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Issue Warning Component when issue is confidential but not locked renders information about confidential issue 1`] = `
<span>
This is a confidential issue.
People without permission will never get a notification.
<gl-link-stub
href="confidential-path"
target="_blank"
>
Learn more
</gl-link-stub>
</span>
`;
exports[`Issue Warning Component when issue is locked and confidential renders information about locked and confidential issue 1`] = `
<span>
<span>
This issue is
<a
href=""
rel="noopener noreferrer"
target="_blank"
>
confidential
</a>
and
<a
href=""
rel="noopener noreferrer"
target="_blank"
>
locked
</a>
.
</span>
People without permission will never get a notification and won't be able to comment.
</span>
`;
exports[`Issue Warning Component when issue is locked but not confidential renders information about locked issue 1`] = `
<span>
This issue is locked.
Only project members can comment.
<gl-link-stub
href="locked-path"
target="_blank"
>
Learn more
</gl-link-stub>
</span>
`;
import Vue from 'vue';
import mountComponent from 'helpers/vue_mount_component_helper';
import issueWarning from '~/vue_shared/components/issue/issue_warning.vue';
import { shallowMount } from '@vue/test-utils';
import IssueWarning from '~/vue_shared/components/issue/issue_warning.vue';
import Icon from '~/vue_shared/components/icon.vue';
const IssueWarning = Vue.extend(issueWarning);
describe('Issue Warning Component', () => {
let wrapper;
function formatWarning(string) {
// Replace newlines with a space then replace multiple spaces with one space
return string
.trim()
.replace(/\n/g, ' ')
.replace(/\s\s+/g, ' ');
}
const findIcon = () => wrapper.find(Icon);
const findLockedBlock = () => wrapper.find({ ref: 'locked' });
const findConfidentialBlock = () => wrapper.find({ ref: 'confidential' });
const findLockedAndConfidentialBlock = () => wrapper.find({ ref: 'lockedAndConfidential' });
describe('Issue Warning Component', () => {
describe('isLocked', () => {
it('should render locked issue warning information', () => {
const props = {
isLocked: true,
lockedIssueDocsPath: 'docs/issues/locked',
const createComponent = props => {
wrapper = shallowMount(IssueWarning, {
propsData: {
...props,
},
});
};
const vm = mountComponent(IssueWarning, props);
expect(
vm.$el.querySelector('.icon use').getAttributeNS('http://www.w3.org/1999/xlink', 'href'),
).toMatch(/lock$/);
expect(formatWarning(vm.$el.querySelector('span').textContent)).toEqual(
'This issue is locked. Only project members can comment. Learn more',
);
expect(vm.$el.querySelector('a').href).toContain(props.lockedIssueDocsPath);
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe('when issue is locked but not confidential', () => {
beforeEach(() => {
createComponent({
isLocked: true,
lockedIssueDocsPath: 'locked-path',
isConfidential: false,
});
});
it('renders information about locked issue', () => {
expect(findLockedBlock().exists()).toBe(true);
expect(findLockedBlock().element).toMatchSnapshot();
});
it('renders warning icon', () => {
expect(findIcon().exists()).toBe(true);
});
it('does not render information about locked and confidential issue', () => {
expect(findLockedAndConfidentialBlock().exists()).toBe(false);
});
it('does not render information about confidential issue', () => {
expect(findConfidentialBlock().exists()).toBe(false);
});
});
describe('isConfidential', () => {
it('should render confidential issue warning information', () => {
const props = {
describe('when issue is confidential but not locked', () => {
beforeEach(() => {
createComponent({
isLocked: false,
isConfidential: true,
confidentialIssueDocsPath: '/docs/issues/confidential',
};
const vm = mountComponent(IssueWarning, props);
confidentialIssueDocsPath: 'confidential-path',
});
});
it('renders information about confidential issue', () => {
expect(findConfidentialBlock().exists()).toBe(true);
expect(findConfidentialBlock().element).toMatchSnapshot();
});
it('renders warning icon', () => {
expect(wrapper.find(Icon).exists()).toBe(true);
});
it('does not render information about locked issue', () => {
expect(findLockedBlock().exists()).toBe(false);
});
expect(
vm.$el.querySelector('.icon use').getAttributeNS('http://www.w3.org/1999/xlink', 'href'),
).toMatch(/eye-slash$/);
expect(formatWarning(vm.$el.querySelector('span').textContent)).toEqual(
'This is a confidential issue. People without permission will never get a notification. Learn more',
);
expect(vm.$el.querySelector('a').href).toContain(props.confidentialIssueDocsPath);
it('does not render information about locked and confidential issue', () => {
expect(findLockedAndConfidentialBlock().exists()).toBe(false);
});
});
describe('isLocked and isConfidential', () => {
it('should render locked and confidential issue warning information', () => {
const vm = mountComponent(IssueWarning, {
describe('when issue is locked and confidential', () => {
beforeEach(() => {
createComponent({
isLocked: true,
isConfidential: true,
});
});
it('renders information about locked and confidential issue', () => {
expect(findLockedAndConfidentialBlock().exists()).toBe(true);
expect(findLockedAndConfidentialBlock().element).toMatchSnapshot();
});
it('does not render warning icon', () => {
expect(wrapper.find(Icon).exists()).toBe(false);
});
it('does not render information about locked issue', () => {
expect(findLockedBlock().exists()).toBe(false);
});
expect(vm.$el.querySelector('.icon')).toBeFalsy();
expect(formatWarning(vm.$el.querySelector('span').textContent)).toEqual(
"This issue is confidential and locked. People without permission will never get a notification and won't be able to comment.",
);
it('does not render information about confidential issue', () => {
expect(findConfidentialBlock().exists()).toBe(false);
});
});
});
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Suggestion Diff component matches snapshot 1`] = `
<div
class="md-suggestion"
>
<suggestion-diff-header-stub
class="qa-suggestion-diff-header js-suggestion-diff-header"
helppagepath="path_to_docs"
/>
<table
class="mb-3 md-suggestion-diff js-syntax-highlight code"
>
<tbody>
<suggestion-diff-row-stub
line="[object Object]"
/>
<suggestion-diff-row-stub
line="[object Object]"
/>
<suggestion-diff-row-stub
line="[object Object]"
/>
</tbody>
</table>
</div>
`;
import Vue from 'vue';
import { shallowMount } from '@vue/test-utils';
import SuggestionDiffComponent from '~/vue_shared/components/markdown/suggestion_diff.vue';
import { selectDiffLines } from '~/vue_shared/components/lib/utils/diff_utils';
import SuggestionDiffHeader from '~/vue_shared/components/markdown/suggestion_diff_header.vue';
import SuggestionDiffRow from '~/vue_shared/components/markdown/suggestion_diff_row.vue';
const MOCK_DATA = {
canApply: true,
suggestion: {
id: 1,
diff_lines: [
......@@ -42,60 +42,45 @@ const MOCK_DATA = {
helpPagePath: 'path_to_docs',
};
const lines = selectDiffLines(MOCK_DATA.suggestion.diff_lines);
const newLines = lines.filter(line => line.type === 'new');
describe('Suggestion Diff component', () => {
let vm;
beforeEach(done => {
const Component = Vue.extend(SuggestionDiffComponent);
let wrapper;
vm = new Component({
propsData: MOCK_DATA,
}).$mount();
Vue.nextTick(done);
const createComponent = () => {
wrapper = shallowMount(SuggestionDiffComponent, {
propsData: {
...MOCK_DATA,
},
});
};
describe('init', () => {
it('renders a suggestion header', () => {
expect(vm.$el.querySelector('.js-suggestion-diff-header')).not.toBeNull();
beforeEach(() => {
createComponent();
});
it('renders a diff table with syntax highlighting', () => {
expect(vm.$el.querySelector('.md-suggestion-diff.js-syntax-highlight.code')).not.toBeNull();
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('renders the oldLineNumber', () => {
const fromLine = vm.$el.querySelector('.old_line').innerHTML;
expect(parseInt(fromLine, 10)).toBe(lines[0].old_line);
it('matches snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
it('renders the oldLineContent', () => {
const fromContent = vm.$el.querySelector('.line_content.old').innerHTML;
expect(fromContent.includes(lines[0].text)).toBe(true);
it('renders a correct amount of suggestion diff rows', () => {
expect(wrapper.findAll(SuggestionDiffRow)).toHaveLength(3);
});
it('renders new lines', () => {
const newLinesElements = vm.$el.querySelectorAll('.line_holder.new');
it('emits apply event on sugestion diff header apply', () => {
wrapper.find(SuggestionDiffHeader).vm.$emit('apply', 'test-event');
newLinesElements.forEach((line, i) => {
expect(newLinesElements[i].innerHTML.includes(newLines[i].new_line)).toBe(true);
expect(newLinesElements[i].innerHTML.includes(newLines[i].text)).toBe(true);
});
});
});
describe('applySuggestion', () => {
it('emits apply event when applySuggestion is called', () => {
const callback = () => {};
jest.spyOn(vm, '$emit').mockImplementation(() => {});
vm.applySuggestion(callback);
expect(vm.$emit).toHaveBeenCalledWith('apply', { suggestionId: vm.suggestion.id, callback });
});
expect(wrapper.emitted('apply')).toBeDefined();
expect(wrapper.emitted('apply')).toEqual([
[
{
callback: 'test-event',
suggestionId: 1,
},
],
]);
});
});
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Issue placeholder note component matches snapshot 1`] = `
<timeline-entry-item-stub
class="note note-wrapper being-posted fade-in-half"
>
<div
class="timeline-icon"
>
<user-avatar-link-stub
imgalt=""
imgcssclasses=""
imgsize="40"
imgsrc="mock_path"
linkhref="/root"
tooltipplacement="top"
tooltiptext=""
username=""
/>
</div>
<div
class="timeline-content discussion"
>
<div
class="note-header"
>
<div
class="note-header-info"
>
<a
href="/root"
>
<span
class="d-none d-sm-inline-block bold"
>
Root
</span>
<span
class="note-headline-light"
>
@root
</span>
</a>
</div>
</div>
<div
class="note-body"
>
<div
class="note-text md"
>
<p>
Foo
</p>
</div>
</div>
</div>
</timeline-entry-item-stub>
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Placeholder system note component matches snapshot 1`] = `
<timeline-entry-item-stub
class="note system-note being-posted fade-in-half"
>
<div
class="timeline-content"
>
<em>
This is a placeholder
</em>
</div>
</timeline-entry-item-stub>
`;
import Vue from 'vue';
import issuePlaceholderNote from '~/vue_shared/components/notes/placeholder_note.vue';
import createStore from '~/notes/stores';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import IssuePlaceholderNote from '~/vue_shared/components/notes/placeholder_note.vue';
import { userDataMock } from '../../../notes/mock_data';
describe('issue placeholder system note component', () => {
let store;
let vm;
beforeEach(() => {
const Component = Vue.extend(issuePlaceholderNote);
store = createStore();
store.dispatch('setUserData', userDataMock);
vm = new Component({
store,
propsData: { note: { body: 'Foo' } },
}).$mount();
const localVue = createLocalVue();
localVue.use(Vuex);
const getters = {
getUserData: () => userDataMock,
};
describe('Issue placeholder note component', () => {
let wrapper;
const findNote = () => wrapper.find({ ref: 'note' });
const createComponent = (isIndividual = false) => {
wrapper = shallowMount(IssuePlaceholderNote, {
localVue,
store: new Vuex.Store({
getters,
}),
propsData: {
note: {
body: 'Foo',
individual_note: isIndividual,
},
},
});
};
afterEach(() => {
vm.$destroy();
wrapper.destroy();
wrapper = null;
});
describe('user information', () => {
it('should render user avatar with link', () => {
expect(vm.$el.querySelector('.user-avatar-link').getAttribute('href')).toEqual(
userDataMock.path,
);
it('matches snapshot', () => {
createComponent();
expect(vm.$el.querySelector('.user-avatar-link img').getAttribute('src')).toEqual(
`${userDataMock.avatar_url}?width=40`,
);
});
expect(wrapper.element).toMatchSnapshot();
});
describe('note content', () => {
it('should render note header information', () => {
expect(vm.$el.querySelector('.note-header-info a').getAttribute('href')).toEqual(
userDataMock.path,
);
it('does not add "discussion" class to individual notes', () => {
createComponent(true);
expect(
vm.$el.querySelector('.note-header-info .note-headline-light').textContent.trim(),
).toEqual(`@${userDataMock.username}`);
expect(findNote().classes()).not.toContain('discussion');
});
it('should render note body', () => {
expect(vm.$el.querySelector('.note-text p').textContent.trim()).toEqual('Foo');
});
it('adds "discussion" class to non-individual notes', () => {
createComponent();
expect(findNote().classes()).toContain('discussion');
});
});
import Vue from 'vue';
import mountComponent from 'helpers/vue_mount_component_helper';
import placeholderSystemNote from '~/vue_shared/components/notes/placeholder_system_note.vue';
import { shallowMount } from '@vue/test-utils';
import PlaceholderSystemNote from '~/vue_shared/components/notes/placeholder_system_note.vue';
describe('placeholder system note component', () => {
let PlaceholderSystemNote;
let vm;
describe('Placeholder system note component', () => {
let wrapper;
beforeEach(() => {
PlaceholderSystemNote = Vue.extend(placeholderSystemNote);
const createComponent = () => {
wrapper = shallowMount(PlaceholderSystemNote, {
propsData: {
note: { body: 'This is a placeholder' },
},
});
};
afterEach(() => {
vm.$destroy();
wrapper.destroy();
wrapper = null;
});
it('should render system note placeholder with plain text', () => {
vm = mountComponent(PlaceholderSystemNote, {
note: { body: 'This is a placeholder' },
});
it('matches snapshot', () => {
createComponent();
expect(vm.$el.tagName).toEqual('LI');
expect(vm.$el.querySelector('.timeline-content em').textContent.trim()).toEqual(
'This is a placeholder',
);
expect(wrapper.element).toMatchSnapshot();
});
});
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