From bc67ade3b6ed1fcbcae2619146262e1e1cb1d325 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2020 04:19:12 +0000 Subject: [PATCH 001/108] build(deps): bump graphql-shield from 7.2.0 to 7.2.1 in /backend Bumps [graphql-shield](https://github.com/maticzav/graphql-shield) from 7.2.0 to 7.2.1. - [Release notes](https://github.com/maticzav/graphql-shield/releases) - [Commits](https://github.com/maticzav/graphql-shield/compare/v7.2.0...v7.2.1) Signed-off-by: dependabot-preview[bot] --- backend/package.json | 2 +- backend/yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/backend/package.json b/backend/package.json index 77417453f..b2fee47b9 100644 --- a/backend/package.json +++ b/backend/package.json @@ -61,7 +61,7 @@ "graphql-middleware": "~4.0.2", "graphql-middleware-sentry": "^3.2.1", "graphql-redis-subscriptions": "^2.2.1", - "graphql-shield": "~7.2.0", + "graphql-shield": "~7.2.1", "graphql-tag": "~2.10.3", "helmet": "~3.21.3", "ioredis": "^4.16.0", diff --git a/backend/yarn.lock b/backend/yarn.lock index a514a60b4..8db891303 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -1587,10 +1587,10 @@ dependencies: "@types/yargs-parser" "*" -"@types/yup@0.26.32": - version "0.26.32" - resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.26.32.tgz#bd356fb405f3d641eff963854edf7ad854a8e829" - integrity sha512-55WFAq8lNYXdRzSP1cenMFFXtPRe7PWsqn5y9ibqKHOQZ/cSLErkcnB1LE89M7W2TSXVDFtx+T7eFePkGoB+xw== +"@types/yup@0.26.33": + version "0.26.33" + resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.26.33.tgz#301faab47b952a4a5f9a06246942cc7cbd09cd95" + integrity sha512-QzgcNfDtRIph8CjfoWiu+MJiOUp25Yo7FthuOHLVbtCTyonjOo2YRsFzKo3csDWbTXlw5NedOFH0Nje7yipCrA== "@types/zen-observable@^0.8.0": version "0.8.0" @@ -4498,12 +4498,12 @@ graphql-redis-subscriptions@^2.2.1: optionalDependencies: ioredis "^4.6.3" -graphql-shield@~7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/graphql-shield/-/graphql-shield-7.2.0.tgz#81b26794370608ad78dfe3833473789fb471fbd8" - integrity sha512-eLdD+gUIKYu77XRcuHs5ewZhiBuRFeWFGxPnJa+g9AkxB7Yi5RSEjEJEx0Drg9GuNvDYpHeW7nPff4v35AT2aQ== +graphql-shield@~7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/graphql-shield/-/graphql-shield-7.2.1.tgz#baca0c31a19593ede41a4bb4d476f9edd1d0eb78" + integrity sha512-EEoVYvXuqAGXGH1i9Aot4MJIUlRABVycwKRGaBreabys7yTd+0zGwudKB9yZiW3SEMIjHkz3a0r/ILhYzq0uiw== dependencies: - "@types/yup" "0.26.32" + "@types/yup" "0.26.33" object-hash "^2.0.3" yup "^0.28.3" From e236838523a7dc991f8e301b3580734c4e611933 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 7 Feb 2020 09:36:00 +0100 Subject: [PATCH 002/108] migration added for index for fulltext tag search --- .../20200207080200-fulltext_index_for_tags.js | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 backend/src/db/migrations/20200207080200-fulltext_index_for_tags.js diff --git a/backend/src/db/migrations/20200207080200-fulltext_index_for_tags.js b/backend/src/db/migrations/20200207080200-fulltext_index_for_tags.js new file mode 100644 index 000000000..0a92c90c3 --- /dev/null +++ b/backend/src/db/migrations/20200207080200-fulltext_index_for_tags.js @@ -0,0 +1,49 @@ +import { getDriver } from '../../db/neo4j' + +export const description = + 'This migration adds a fulltext index for the tags in order to search for Hasthags.' + +export async function up(next) { + const driver = getDriver() + const session = driver.session() + const transaction = session.beginTransaction() + + try { + await transaction.run(` + CALL db.index.fulltext.createNodeIndex("tag_fulltext_search",["Tag"],["id"]) + `) + await transaction.commit() + next() + } catch (error) { + // eslint-disable-next-line no-console + console.log(error) + await transaction.rollback() + // eslint-disable-next-line no-console + console.log('rolled back') + } finally { + session.close() + } +} + +export async function down(next) { + const driver = getDriver() + const session = driver.session() + const transaction = session.beginTransaction() + + try { + // Implement your migration here. + await transaction.run(` + CALL db.index.fulltext.drop("tag_fulltext_search") + `) + await transaction.commit() + next() + } catch (error) { + // eslint-disable-next-line no-console + console.log(error) + await transaction.rollback() + // eslint-disable-next-line no-console + console.log('rolled back') + } finally { + session.close() + } +} From 16ad565ec8c3ff83d6b363861ada7ea0a29d3ce9 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 11 Feb 2020 09:27:28 +0100 Subject: [PATCH 003/108] partially working, index page does not update when route is changed --- .../generic/SearchTag/SearchTag.vue | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 webapp/components/generic/SearchTag/SearchTag.vue diff --git a/webapp/components/generic/SearchTag/SearchTag.vue b/webapp/components/generic/SearchTag/SearchTag.vue new file mode 100644 index 000000000..d8cfc0b31 --- /dev/null +++ b/webapp/components/generic/SearchTag/SearchTag.vue @@ -0,0 +1,23 @@ + + + From 014be6e7f885a84668739a7697a53de5797fd61c Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 11 Feb 2020 09:27:41 +0100 Subject: [PATCH 004/108] partially working, index page does not update when route is changed --- backend/src/schema/resolvers/searches.js | 27 +++++++++++++-- backend/src/schema/types/type/Search.gql | 2 +- webapp/components/Hashtag/Hashtag.vue | 2 +- .../generic/SearchTag/SearchTag.vue | 24 ++++++------- .../SearchableInput/SearchableInput.vue | 34 ++++++++++++++++--- webapp/graphql/Search.js | 3 ++ webapp/locales/de.json | 29 ++++++++++++++++ webapp/locales/en.json | 10 ++++++ 8 files changed, 110 insertions(+), 21 deletions(-) diff --git a/backend/src/schema/resolvers/searches.js b/backend/src/schema/resolvers/searches.js index 5c1e43952..d4a2bf02a 100644 --- a/backend/src/schema/resolvers/searches.js +++ b/backend/src/schema/resolvers/searches.js @@ -43,6 +43,16 @@ export default { ` const myQuery = queryString(query) + const tagCypher = ` + CALL db.index.fulltext.queryNodes('tag_fulltext_search', $query) + YIELD node as resource, score + MATCH (resource) + WHERE score >= 0.5 + AND NOT (resource.deleted = true OR resource.disabled = true) + RETURN resource {.*, __typename: labels(resource)[0]} + LIMIT $limit + ` + const session = context.driver.session() const searchResultPromise = session.readTransaction(async transaction => { const postTransactionResponse = transaction.run(postCypher, { @@ -55,14 +65,25 @@ export default { limit, thisUserId, }) - return Promise.all([postTransactionResponse, userTransactionResponse]) + const tagTransactionResponse = transaction.run(tagCypher, { + query: myQuery, + limit, + }) + return Promise.all([ + postTransactionResponse, + userTransactionResponse, + tagTransactionResponse, + ]) }) try { - const [postResults, userResults] = await searchResultPromise + const [postResults, userResults, tagResults] = await searchResultPromise log(postResults) log(userResults) - return [...postResults.records, ...userResults.records].map(r => r.get('resource')) + log(tagResults) + return [...postResults.records, ...userResults.records, ...tagResults.records].map(r => + r.get('resource'), + ) } finally { session.close() } diff --git a/backend/src/schema/types/type/Search.gql b/backend/src/schema/types/type/Search.gql index 2c22fa61f..1ce38001d 100644 --- a/backend/src/schema/types/type/Search.gql +++ b/backend/src/schema/types/type/Search.gql @@ -1,4 +1,4 @@ -union SearchResult = Post | User +union SearchResult = Post | User | Tag type Query { findResources(query: String!, limit: Int = 5): [SearchResult]! diff --git a/webapp/components/Hashtag/Hashtag.vue b/webapp/components/Hashtag/Hashtag.vue index 35762c81c..44e5319f0 100644 --- a/webapp/components/Hashtag/Hashtag.vue +++ b/webapp/components/Hashtag/Hashtag.vue @@ -1,5 +1,5 @@ diff --git a/webapp/components/generic/SearchTag/SearchTag.vue b/webapp/components/generic/SearchTag/SearchTag.vue index d8cfc0b31..a94431eea 100644 --- a/webapp/components/generic/SearchTag/SearchTag.vue +++ b/webapp/components/generic/SearchTag/SearchTag.vue @@ -6,18 +6,18 @@ diff --git a/webapp/components/generic/SearchableInput/SearchableInput.vue b/webapp/components/generic/SearchableInput/SearchableInput.vue index 3260ff082..654deaad4 100644 --- a/webapp/components/generic/SearchableInput/SearchableInput.vue +++ b/webapp/components/generic/SearchableInput/SearchableInput.vue @@ -35,6 +35,12 @@ >

+

+ +

@@ -45,6 +51,7 @@ import { isEmpty } from 'lodash' import SearchHeading from '~/components/generic/SearchHeading/SearchHeading.vue' import SearchPost from '~/components/generic/SearchPost/SearchPost.vue' +import HcHashtag from '~/components/Hashtag/Hashtag.vue' import UserTeaser from '~/components/UserTeaser/UserTeaser.vue' export default { @@ -52,6 +59,7 @@ export default { components: { SearchHeading, SearchPost, + HcHashtag, UserTeaser, }, props: { @@ -77,6 +85,16 @@ export default { return !isEmpty(this.previousSearchTerm) }, }, + watch: { + $route(to, from) { + console.log('to', to) + console.log('from', from) + // console.log(this.finalFilters) + if (to.query.hashtag) { + this.hashtag = to.query.hashtag + } + }, + }, methods: { isFirstOfType(option) { return ( @@ -138,12 +156,20 @@ export default { isPost(item) { return item.__typename === 'Post' }, + isTag(item) { + return item.__typename === 'Tag' + }, goToResource(item) { this.$nextTick(() => { - this.$router.push({ - name: this.isPost(item) ? 'post-id-slug' : 'profile-id-slug', - params: { id: item.id, slug: item.slug }, - }) + if (!this.isTag(item)) { + this.$router.push({ + name: this.isPost(item) ? 'post-id-slug' : 'profile-id-slug', + params: { id: item.id, slug: item.slug }, + }) + } else { + console.log('HIT¡') + this.$router.push('?hashtag=' + item.id) + } }) }, }, diff --git a/webapp/graphql/Search.js b/webapp/graphql/Search.js index 9b142b429..ab34b58b6 100644 --- a/webapp/graphql/Search.js +++ b/webapp/graphql/Search.js @@ -19,6 +19,9 @@ export const findResourcesQuery = gql` ... on User { ...user } + ... on Tag { + id + } } } ` diff --git a/webapp/locales/de.json b/webapp/locales/de.json index 524ee58fa..8f38c2352 100644 --- a/webapp/locales/de.json +++ b/webapp/locales/de.json @@ -558,6 +558,35 @@ "message": "Bist Du sicher, dass Du den Kommentar von „{name}“ melden möchtest?", "title": "Kommentar melden", "type": "Kommentar" + "content": { + "unavailable-placeholder": "… dieser Kommentar ist nicht mehr verfügbar" + }, + "menu": { + "edit": "Kommentar bearbeiten", + "delete": "Kommentar löschen" + }, + "show": { + "more": "mehr anzeigen", + "less": "weniger anzeigen" + }, + "edited": "bearbeitet" + }, + "followButton": { + "follow": "Folgen", + "following": "Folge Ich" + }, + "shoutButton": { + "shouted": "empfohlen" + }, + "search": { + "placeholder": "Suchen", + "hint": "Wonach suchst Du?", + "failed": "Nichts gefunden", + "heading": { + "Post": "Beiträge", + "User": "Benutzer", + "Tag": "Hashtags" + } }, "contribution": { "error": "Du hast den Beitrag bereits gemeldet!", diff --git a/webapp/locales/en.json b/webapp/locales/en.json index e6b8def5a..642d0c228 100644 --- a/webapp/locales/en.json +++ b/webapp/locales/en.json @@ -549,6 +549,16 @@ "message": "Do you really want to release the user \"{name}\"?", "title": "Release User", "type": "User" + "empty": "Sorry, you don't have any notifications at the moment." + }, + "search": { + "placeholder": "Search", + "hint": "What are you searching for?", + "failed": "Nothing found", + "heading": { + "Post": "Posts", + "User": "Users", + "Tag": "Hashtags" } }, "report": { From 07fbe92fa81ab3828904545d9d58cd67e02238d3 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 19 Mar 2020 13:26:08 +0100 Subject: [PATCH 005/108] fixed locales after mistakes in rebase --- webapp/locales/de.json | 30 +----------------------------- webapp/locales/en.json | 11 +---------- 2 files changed, 2 insertions(+), 39 deletions(-) diff --git a/webapp/locales/de.json b/webapp/locales/de.json index 8f38c2352..a2ab2246f 100644 --- a/webapp/locales/de.json +++ b/webapp/locales/de.json @@ -558,35 +558,6 @@ "message": "Bist Du sicher, dass Du den Kommentar von „{name}“ melden möchtest?", "title": "Kommentar melden", "type": "Kommentar" - "content": { - "unavailable-placeholder": "… dieser Kommentar ist nicht mehr verfügbar" - }, - "menu": { - "edit": "Kommentar bearbeiten", - "delete": "Kommentar löschen" - }, - "show": { - "more": "mehr anzeigen", - "less": "weniger anzeigen" - }, - "edited": "bearbeitet" - }, - "followButton": { - "follow": "Folgen", - "following": "Folge Ich" - }, - "shoutButton": { - "shouted": "empfohlen" - }, - "search": { - "placeholder": "Suchen", - "hint": "Wonach suchst Du?", - "failed": "Nichts gefunden", - "heading": { - "Post": "Beiträge", - "User": "Benutzer", - "Tag": "Hashtags" - } }, "contribution": { "error": "Du hast den Beitrag bereits gemeldet!", @@ -628,6 +599,7 @@ "failed": "Nichts gefunden", "heading": { "Post": "Beiträge", + "Tag": "Hashtags", "User": "Benutzer" }, "hint": "Wonach suchst Du?", diff --git a/webapp/locales/en.json b/webapp/locales/en.json index 642d0c228..eb19dfbe7 100644 --- a/webapp/locales/en.json +++ b/webapp/locales/en.json @@ -549,16 +549,6 @@ "message": "Do you really want to release the user \"{name}\"?", "title": "Release User", "type": "User" - "empty": "Sorry, you don't have any notifications at the moment." - }, - "search": { - "placeholder": "Search", - "hint": "What are you searching for?", - "failed": "Nothing found", - "heading": { - "Post": "Posts", - "User": "Users", - "Tag": "Hashtags" } }, "report": { @@ -609,6 +599,7 @@ "failed": "Nothing found", "heading": { "Post": "Posts", + "Tag": "Hashtags", "User": "Users" }, "hint": "What are you searching for?", From 1c43d5fe6f44c7b11168af8bd765b8d785a6641a Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 19 Mar 2020 14:19:13 +0100 Subject: [PATCH 006/108] Search for Hashtags works due watching route in pages/index.vue --- backend/src/db/migrate/template.js | 1 + .../20200207080200-fulltext_index_for_tags.js | 2 + backend/src/schema/resolvers/searches.js | 6 +- .../generic/SearchTag/SearchTag.vue | 23 -- .../SearchableInput/SearchableInput.vue | 11 - webapp/pages/index.vue | 306 +++++++++--------- 6 files changed, 162 insertions(+), 187 deletions(-) delete mode 100644 webapp/components/generic/SearchTag/SearchTag.vue diff --git a/backend/src/db/migrate/template.js b/backend/src/db/migrate/template.js index 9adb0786d..72bfc9b1b 100644 --- a/backend/src/db/migrate/template.js +++ b/backend/src/db/migrate/template.js @@ -40,6 +40,7 @@ export async function down(next) { await transaction.rollback() // eslint-disable-next-line no-console console.log('rolled back') + throw new Error(error) } finally { session.close() } diff --git a/backend/src/db/migrations/20200207080200-fulltext_index_for_tags.js b/backend/src/db/migrations/20200207080200-fulltext_index_for_tags.js index 0a92c90c3..5064a8b17 100644 --- a/backend/src/db/migrations/20200207080200-fulltext_index_for_tags.js +++ b/backend/src/db/migrations/20200207080200-fulltext_index_for_tags.js @@ -20,6 +20,7 @@ export async function up(next) { await transaction.rollback() // eslint-disable-next-line no-console console.log('rolled back') + throw new Error(error) } finally { session.close() } @@ -43,6 +44,7 @@ export async function down(next) { await transaction.rollback() // eslint-disable-next-line no-console console.log('rolled back') + throw new Error(error) } finally { session.close() } diff --git a/backend/src/schema/resolvers/searches.js b/backend/src/schema/resolvers/searches.js index d4a2bf02a..3471c783b 100644 --- a/backend/src/schema/resolvers/searches.js +++ b/backend/src/schema/resolvers/searches.js @@ -41,18 +41,18 @@ export default { RETURN resource {.*, __typename: labels(resource)[0]} LIMIT $limit ` - const myQuery = queryString(query) - const tagCypher = ` CALL db.index.fulltext.queryNodes('tag_fulltext_search', $query) YIELD node as resource, score MATCH (resource) - WHERE score >= 0.5 + WHERE score >= 0.0 AND NOT (resource.deleted = true OR resource.disabled = true) RETURN resource {.*, __typename: labels(resource)[0]} LIMIT $limit ` + const myQuery = queryString(query) + const session = context.driver.session() const searchResultPromise = session.readTransaction(async transaction => { const postTransactionResponse = transaction.run(postCypher, { diff --git a/webapp/components/generic/SearchTag/SearchTag.vue b/webapp/components/generic/SearchTag/SearchTag.vue deleted file mode 100644 index a94431eea..000000000 --- a/webapp/components/generic/SearchTag/SearchTag.vue +++ /dev/null @@ -1,23 +0,0 @@ - - - diff --git a/webapp/components/generic/SearchableInput/SearchableInput.vue b/webapp/components/generic/SearchableInput/SearchableInput.vue index 654deaad4..b0050b429 100644 --- a/webapp/components/generic/SearchableInput/SearchableInput.vue +++ b/webapp/components/generic/SearchableInput/SearchableInput.vue @@ -85,16 +85,6 @@ export default { return !isEmpty(this.previousSearchTerm) }, }, - watch: { - $route(to, from) { - console.log('to', to) - console.log('from', from) - // console.log(this.finalFilters) - if (to.query.hashtag) { - this.hashtag = to.query.hashtag - } - }, - }, methods: { isFirstOfType(option) { return ( @@ -167,7 +157,6 @@ export default { params: { id: item.id, slug: item.slug }, }) } else { - console.log('HIT¡') this.$router.push('?hashtag=' + item.id) } }) diff --git a/webapp/pages/index.vue b/webapp/pages/index.vue index 8aef52c1d..d73c993ec 100644 --- a/webapp/pages/index.vue +++ b/webapp/pages/index.vue @@ -64,158 +64,164 @@ diff --git a/webapp/components/FilterMenu/FilterMenu.spec.js b/webapp/components/FilterMenu/FilterMenu.spec.js index 283db979e..ec94e8ea5 100644 --- a/webapp/components/FilterMenu/FilterMenu.spec.js +++ b/webapp/components/FilterMenu/FilterMenu.spec.js @@ -1,42 +1,166 @@ import { mount } from '@vue/test-utils' + +import Vuex from 'vuex' import FilterMenu from './FilterMenu.vue' +import locales from '~/locales' +import orderBy from 'lodash/orderBy' const localVue = global.localVue +let mutations +let getters + +const languages = orderBy(locales, 'name') + describe('FilterMenu.vue', () => { - let wrapper let mocks let propsData + let menuToggle + let allCategoriesButton + let environmentAndNatureButton + let democracyAndPoliticsButton + let happyEmotionButton + let englishButton + let spanishButton beforeEach(() => { - mocks = { $t: () => {} } + mocks = { + $apollo: { + query: jest + .fn() + .mockResolvedValueOnce({ + data: { Post: { title: 'Post with Category', category: [{ id: 'cat4' }] } }, + }) + .mockRejectedValue({ message: 'We were unable to filter' }), + }, + $t: jest.fn(), + $i18n: { + locale: () => 'en', + }, + $toast: { + error: jest.fn(), + }, + } + propsData = { + categories: [ + { id: 'cat4', name: 'Environment & Nature', icon: 'tree' }, + { id: 'cat15', name: 'Consumption & Sustainability', icon: 'shopping-cart' }, + { id: 'cat9', name: 'Democracy & Politics', icon: 'university' }, + ], + } }) - describe('given a hashtag', () => { - beforeEach(() => { - propsData = { - hashtag: 'Frieden', - } + describe('mount', () => { + mutations = { + 'posts/TOGGLE_FILTER_BY_FOLLOWED': jest.fn(), + 'posts/RESET_CATEGORIES': jest.fn(), + 'posts/TOGGLE_CATEGORY': jest.fn(), + 'posts/TOGGLE_EMOTION': jest.fn(), + 'posts/TOGGLE_LANGUAGE': jest.fn(), + 'posts/RESET_LANGUAGES': jest.fn(), + } + getters = { + 'posts/isActive': () => false, + 'auth/isModerator': () => false, + 'auth/user': () => { + return { id: 'u34' } + }, + 'posts/filteredCategoryIds': jest.fn(() => []), + 'posts/filteredByUsersFollowed': jest.fn(), + 'posts/filteredByEmotions': jest.fn(() => []), + 'posts/filteredLanguageCodes': jest.fn(() => []), + } + const openFilterMenu = () => { + const store = new Vuex.Store({ mutations, getters }) + const wrapper = mount(FilterMenu, { mocks, localVue, propsData, store }) + menuToggle = wrapper.findAll('button').at(0) + menuToggle.trigger('click') + return wrapper + } + + it('groups the categories by pair', () => { + const wrapper = openFilterMenu() + expect(wrapper.vm.chunk).toEqual([ + [ + { id: 'cat4', name: 'Environment & Nature', icon: 'tree' }, + { id: 'cat15', name: 'Consumption & Sustainability', icon: 'shopping-cart' }, + ], + [{ id: 'cat9', name: 'Democracy & Politics', icon: 'university' }], + ]) }) - describe('mount', () => { - const Wrapper = () => { - return mount(FilterMenu, { mocks, localVue, propsData }) - } + it('starts with all categories button active', () => { + const wrapper = openFilterMenu() + allCategoriesButton = wrapper.findAll('button').at(1) + expect(allCategoriesButton.attributes().class).toContain('--filled') + }) + + it('calls TOGGLE_CATEGORY when clicked', () => { + const wrapper = openFilterMenu() + environmentAndNatureButton = wrapper.findAll('button').at(2) + environmentAndNatureButton.trigger('click') + expect(mutations['posts/TOGGLE_CATEGORY']).toHaveBeenCalledWith({}, 'cat4') + }) + + it('calls TOGGLE_LANGUAGE when clicked', () => { + const wrapper = openFilterMenu() + englishButton = wrapper + .findAll('button.language-buttons') + .at(languages.findIndex(l => l.code === 'en')) + englishButton.trigger('click') + expect(mutations['posts/TOGGLE_LANGUAGE']).toHaveBeenCalledWith({}, 'en') + }) + + it('sets category button attribute `filled` when corresponding category is filtered', () => { + getters['posts/filteredCategoryIds'] = jest.fn(() => ['cat9']) + const wrapper = openFilterMenu() + democracyAndPoliticsButton = wrapper.findAll('button').at(4) + expect(democracyAndPoliticsButton.attributes().class).toContain('--filled') + }) + + it('sets language button attribute `filled` when corresponding language is filtered', () => { + getters['posts/filteredLanguageCodes'] = jest.fn(() => ['es']) + const wrapper = openFilterMenu() + spanishButton = wrapper + .findAll('button.language-buttons') + .at(languages.findIndex(l => l.code === 'es')) + expect(spanishButton.attributes().class).toContain('--filled') + }) + + it('sets "filter-by-followed" button attribute `filled`', () => { + getters['posts/filteredByUsersFollowed'] = jest.fn(() => true) + const wrapper = openFilterMenu() + expect(wrapper.find('.base-button[data-test="filter-by-followed"]').classes('--filled')).toBe( + true, + ) + }) + + describe('click "filter-by-followed" button', () => { + let wrapper beforeEach(() => { - wrapper = Wrapper() + wrapper = openFilterMenu() + wrapper.find('.base-button[data-test="filter-by-followed"]').trigger('click') }) - it('renders a card', () => { - wrapper = Wrapper() - expect(wrapper.is('.base-card')).toBe(true) + it('calls TOGGLE_FILTER_BY_FOLLOWED', () => { + expect(mutations['posts/TOGGLE_FILTER_BY_FOLLOWED']).toHaveBeenCalledWith({}, 'u34') + }) + }) + + describe('click on an "emotions-buttons" button', () => { + it('calls TOGGLE_EMOTION when clicked', () => { + const wrapper = openFilterMenu() + happyEmotionButton = wrapper.findAll('.emotion-button .base-button').at(1) + happyEmotionButton.trigger('click') + expect(mutations['posts/TOGGLE_EMOTION']).toHaveBeenCalledWith({}, 'happy') }) - describe('click clear search button', () => { - it('emits clearSearch', () => { - wrapper.find('.base-button').trigger('click') - expect(wrapper.emitted().clearSearch).toHaveLength(1) - }) + it('sets the attribute `src` to colorized image', () => { + getters['posts/filteredByEmotions'] = jest.fn(() => ['happy']) + const wrapper = openFilterMenu() + happyEmotionButton = wrapper.findAll('.emotion-button .base-button').at(1) + const happyEmotionButtonImage = happyEmotionButton.find('img') + expect(happyEmotionButtonImage.attributes().src).toEqual('/img/svg/emoji/happy_color.svg') }) }) }) diff --git a/webapp/components/FilterMenu/FilterMenu.vue b/webapp/components/FilterMenu/FilterMenu.vue index afe6a3d7a..0cc21f04d 100644 --- a/webapp/components/FilterMenu/FilterMenu.vue +++ b/webapp/components/FilterMenu/FilterMenu.vue @@ -1,36 +1,46 @@ - - - diff --git a/webapp/components/FilterPosts/GeneralFilterMenuItems.vue b/webapp/components/FilterMenu/GeneralFilter.vue similarity index 83% rename from webapp/components/FilterPosts/GeneralFilterMenuItems.vue rename to webapp/components/FilterMenu/GeneralFilter.vue index f1cf6adae..f13e6b778 100644 --- a/webapp/components/FilterPosts/GeneralFilterMenuItems.vue +++ b/webapp/components/FilterMenu/GeneralFilter.vue @@ -1,7 +1,7 @@