diff --git a/webapp/components/features/SearchResources/SearchResources.spec.js b/webapp/components/features/SearchResources/SearchResources.spec.js
index cc4d230c2..27a75dbfc 100644
--- a/webapp/components/features/SearchResources/SearchResources.spec.js
+++ b/webapp/components/features/SearchResources/SearchResources.spec.js
@@ -1,139 +1,71 @@
-import { mount } from '@vue/test-utils'
+import { config, mount } from '@vue/test-utils'
+import Vuex from 'vuex'
import SearchResources from './SearchResources.vue'
-
+import SearchableInput from '~/components/generic/SearchableInput/SearchableInput'
+import { results as searchResults } from './SearchResources.story'
const localVue = global.localVue
localVue.filter('truncate', () => 'truncated string')
localVue.filter('dateTime', () => Date.now)
+config.stubs['nuxt-link'] = ''
describe('SearchResources.vue', () => {
- let mocks
- let propsData
-
+ let mocks, wrapper, getters
beforeEach(() => {
- propsData = {}
+ mocks = {
+ $apollo: {
+ query: jest.fn(),
+ },
+ $t: jest.fn(string => string),
+ }
+ getters = { 'auth/isModerator': () => false }
+ wrapper = Wrapper()
})
+ const Wrapper = () => {
+ const store = new Vuex.Store({
+ getters,
+ })
+ return mount(SearchResources, { mocks, localVue, store })
+ }
+
describe('mount', () => {
- const Wrapper = () => {
- mocks = {
- $t: () => {},
- }
- return mount(SearchResources, { mocks, localVue, propsData })
- }
-
- it('renders', () => {
- expect(Wrapper().is('div')).toBe(true)
- })
-
- it('has id "nav-search"', () => {
- expect(Wrapper().contains('[data-test="search-resources"]')).toBe(true)
- })
-
- it('defaults to an empty value', () => {
- expect(Wrapper().vm.value).toBe('')
- })
-
- it('defaults to id "nav-search"', () => {
- expect(Wrapper().vm.id).toBe('nav-search')
- })
-
- it('default to a 300 millisecond delay from the time the user stops typing to when the search starts', () => {
- expect(Wrapper().vm.delay).toEqual(300)
- })
-
- it('defaults to an empty array as results', () => {
- expect(Wrapper().vm.results).toEqual([])
+ it('defaults to an empty array as searchResults', () => {
+ expect(wrapper.vm.searchResults).toEqual([])
})
it('defaults to pending false, as in the search is not pending', () => {
- expect(Wrapper().vm.pending).toBe(false)
+ expect(wrapper.vm.pending).toBe(false)
})
- it('accepts values as a string', () => {
- propsData = { value: 'abc' }
- const wrapper = Wrapper()
- expect(wrapper.vm.value).toEqual('abc')
- })
-
- describe('testing custom functions', () => {
- let select
- let wrapper
-
+ describe('Emitted events', () => {
+ let searchableInputComponent
beforeEach(() => {
- wrapper = Wrapper()
- select = wrapper.find('.ds-select')
- select.trigger('focus')
- select.element.value = 'abcd'
+ searchableInputComponent = wrapper.find(SearchableInput)
})
- it('opens the select dropdown when focused on', () => {
- expect(wrapper.vm.isOpen).toBe(true)
+ describe('query event', () => {
+ it('calls an apollo query', () => {
+ searchableInputComponent.vm.$emit('query', 'abcd')
+ expect(mocks.$apollo.query).toHaveBeenCalledWith(
+ expect.objectContaining({ variables: { query: 'abcd' } }),
+ )
+ })
})
- it('opens the select dropdown and blurs after focused on', () => {
- select.trigger('blur')
- expect(wrapper.vm.isOpen).toBe(false)
- })
+ describe('clearSearch event', () => {
+ beforeEach(() => {
+ wrapper.setData({ searchResults, pending: true })
+ searchableInputComponent.vm.$emit('clearSearch')
+ })
- it('is clearable', () => {
- select.trigger('input')
- select.trigger('keyup.esc')
- expect(wrapper.emitted().clear.length).toBe(1)
- })
+ it('clears searchResults', () => {
+ expect(wrapper.vm.searchResults).toEqual([])
+ })
- it('changes the unprocessedSearchResources as the value changes', () => {
- select.trigger('input')
- expect(wrapper.vm.unprocessedSearchResources).toBe('abcd')
- })
-
- it('searches for the term when enter is pressed', async () => {
- select.trigger('input')
- select.trigger('keyup.enter')
- await expect(wrapper.emitted().search[0]).toEqual(['abcd'])
- })
-
- it('calls onDelete when the delete key is pressed', () => {
- const spy = jest.spyOn(wrapper.vm, 'onDelete')
- select.trigger('input')
- select.trigger('keyup.delete')
- expect(spy).toHaveBeenCalledTimes(1)
- })
-
- it('calls query when a user starts a search by pressing enter', () => {
- const spy = jest.spyOn(wrapper.vm, 'query')
- select.trigger('input')
- select.trigger('keyup.enter')
- expect(spy).toHaveBeenCalledWith('abcd')
- })
-
- it('calls onSelect when a user selects an item in the search dropdown menu', async () => {
- // searched for term in the browser, copied the results from Vuex in Vue dev tools
- propsData = {
- results: [
- {
- __typename: 'Post',
- author: {
- __typename: 'User',
- id: 'u5',
- name: 'Trick',
- slug: 'trick',
- },
- commentsCount: 0,
- createdAt: '2019-03-13T11:00:20.835Z',
- id: 'p10',
- label: 'Eos aut illo omnis quis eaque et iure aut.',
- shoutedCount: 0,
- slug: 'eos-aut-illo-omnis-quis-eaque-et-iure-aut',
- value: 'Eos aut illo omnis quis eaque et iure aut.',
- },
- ],
- }
- wrapper = Wrapper()
- select.trigger('input')
- const results = wrapper.find('.ds-select-option')
- results.trigger('click')
- await expect(wrapper.emitted().select[0]).toEqual(propsData.results)
+ it('set pending to false', () => {
+ expect(wrapper.vm.pending).toBe(false)
+ })
})
})
})
diff --git a/webapp/components/features/SearchResources/SearchResources.story.js b/webapp/components/features/SearchResources/SearchResources.story.js
index 328259917..c2cd8f4fa 100644
--- a/webapp/components/features/SearchResources/SearchResources.story.js
+++ b/webapp/components/features/SearchResources/SearchResources.story.js
@@ -7,7 +7,7 @@ helpers.init()
export const results = [
{
- id: 'de100841-2336-4b01-a574-f1bd2c0b262a',
+ id: 'post-by-jenny',
__typename: 'Post',
slug: 'user-post-by-jenny',
title: 'User Post by Jenny',
diff --git a/webapp/components/generic/SearchableInput/SearchableInput.spec.js b/webapp/components/generic/SearchableInput/SearchableInput.spec.js
new file mode 100644
index 000000000..98528a466
--- /dev/null
+++ b/webapp/components/generic/SearchableInput/SearchableInput.spec.js
@@ -0,0 +1,128 @@
+import { config, mount } from '@vue/test-utils'
+import Vuex from 'vuex'
+import Vue from 'vue'
+import SearchableInput from './SearchableInput'
+import { results } from '~/components/features/SearchResources/SearchResources.story'
+
+const localVue = global.localVue
+
+localVue.filter('truncate', () => 'truncated string')
+localVue.filter('dateTime', () => Date.now)
+config.stubs['nuxt-link'] = ''
+
+describe('SearchableInput.vue', () => {
+ let mocks, propsData, getters
+
+ beforeEach(() => {
+ propsData = {}
+ mocks = {
+ $router: {
+ push: jest.fn(),
+ },
+ $t: jest.fn(string => string),
+ }
+ getters = { 'auth/isModerator': () => false }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ const store = new Vuex.Store({
+ getters,
+ })
+ return mount(SearchableInput, { mocks, localVue, propsData, store })
+ }
+
+ it('defaults to an empty value', () => {
+ expect(Wrapper().vm.value).toBe('')
+ })
+
+ it('default to a 300 millisecond delay from the time the user stops typing to when the search starts', () => {
+ expect(Wrapper().vm.delay).toEqual(300)
+ })
+
+ it('defaults to an empty array as options', () => {
+ expect(Wrapper().vm.options).toEqual([])
+ })
+
+ describe('testing custom functions', () => {
+ let select, wrapper
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ select = wrapper.find('.ds-select')
+ select.trigger('focus')
+ select.element.value = 'abcd'
+ })
+
+ it('opens the select dropdown when focused on', () => {
+ expect(wrapper.vm.isOpen).toBe(true)
+ })
+
+ it('opens the select dropdown and blurs after focused on', () => {
+ select.trigger('blur')
+ expect(wrapper.vm.isOpen).toBe(false)
+ })
+
+ it('is clearable', () => {
+ select.trigger('input')
+ select.trigger('keyup.esc')
+ expect(wrapper.emitted().clearSearch.length).toBe(1)
+ })
+
+ it('changes the unprocessedSearchInput as the value changes', () => {
+ select.trigger('input')
+ expect(wrapper.vm.unprocessedSearchInput).toBe('abcd')
+ })
+
+ it('searches for the term when enter is pressed', async () => {
+ select.element.value = 'ab'
+ select.trigger('input')
+ select.trigger('keyup.enter')
+ await expect(wrapper.emitted().query[0]).toEqual(['ab'])
+ })
+
+ it('calls onDelete when the delete key is pressed', () => {
+ const spy = jest.spyOn(wrapper.vm, 'onDelete')
+ select.trigger('input')
+ select.trigger('keyup.delete')
+ expect(spy).toHaveBeenCalledTimes(1)
+ })
+
+ describe('navigating to resource', () => {
+ beforeEach(() => {
+ propsData = { options: results }
+ wrapper = Wrapper()
+ select = wrapper.find('.ds-select')
+ select.trigger('focus')
+ })
+
+ it('pushes to post page', async () => {
+ select.element.value = 'Post'
+ select.trigger('input')
+ const post = wrapper.find('.search-post')
+ post.trigger('click')
+ await Vue.nextTick().then(() => {
+ expect(mocks.$router.push).toHaveBeenCalledWith({
+ name: 'post-id-slug',
+ params: { id: 'post-by-jenny', slug: 'user-post-by-jenny' },
+ })
+ })
+ })
+
+ it("pushes to user's profile", async () => {
+ select.element.value = 'Bob'
+ select.trigger('input')
+ const users = wrapper.findAll('.userinfo')
+ const bob = users.filter(item => item.text() === '@bob-der-baumeister')
+ bob.trigger('click')
+ await Vue.nextTick().then(() => {
+ expect(mocks.$router.push).toHaveBeenCalledWith({
+ name: 'profile-id-slug',
+ params: { id: 'u2', slug: 'bob-der-baumeister' },
+ })
+ })
+ })
+ })
+ })
+ })
+})