diff --git a/cypress/integration/common/search.js b/cypress/integration/common/search.js
index 1c1981581..5a3819a9d 100644
--- a/cypress/integration/common/search.js
+++ b/cypress/integration/common/search.js
@@ -1,73 +1,70 @@
-import { When, Then } from 'cypress-cucumber-preprocessor/steps'
-When('I search for {string}', value => {
- cy.get('#nav-search')
+import { When, Then } from "cypress-cucumber-preprocessor/steps";
+When("I search for {string}", value => {
+ cy.get("#nav-search")
.focus()
- .type(value)
-})
+ .type(value);
+});
-Then('I should have one post in the select dropdown', () => {
- cy.get('.ds-select-dropdown').should($li => {
- expect($li).to.have.length(1)
- })
-})
+Then("I should have one post in the select dropdown", () => {
+ cy.get(".input .ds-select-dropdown").should($li => {
+ expect($li).to.have.length(1);
+ });
+});
-Then('I should see the following posts in the select dropdown:', table => {
+Then("I should see the following posts in the select dropdown:", table => {
table.hashes().forEach(({ title }) => {
- cy.get('.ds-select-dropdown').should('contain', title)
- })
-})
+ cy.get(".ds-select-dropdown").should("contain", title);
+ });
+});
-When('I type {string} and press Enter', value => {
- cy.get('#nav-search')
+When("I type {string} and press Enter", value => {
+ cy.get("#nav-search")
.focus()
.type(value)
- .type('{enter}', { force: true })
-})
+ .type("{enter}", { force: true });
+});
-When('I type {string} and press escape', value => {
- cy.get('#nav-search')
+When("I type {string} and press escape", value => {
+ cy.get("#nav-search")
.focus()
.type(value)
- .type('{esc}')
-})
+ .type("{esc}");
+});
-Then('the search field should clear', () => {
- cy.get('#nav-search').should('have.text', '')
-})
+Then("the search field should clear", () => {
+ cy.get("#nav-search").should("have.text", "");
+});
-When('I select an entry', () => {
- cy.get('.ds-select-dropdown ul li')
+When("I select an entry", () => {
+ cy.get(".input .ds-select-dropdown ul li")
.first()
- .trigger('click')
-})
+ .trigger("click");
+});
Then("I should be on the post's page", () => {
- cy.location('pathname').should(
- 'contain',
- '/post/'
- )
- cy.location('pathname').should(
- 'eq',
- '/post/p1/101-essays-that-will-change-the-way-you-think'
- )
-})
+ cy.location("pathname").should("contain", "/post/");
+ cy.location("pathname").should(
+ "eq",
+ "/post/p1/101-essays-that-will-change-the-way-you-think"
+ );
+});
Then(
- 'I should see posts with the searched-for term in the select dropdown',
+ "I should see posts with the searched-for term in the select dropdown",
() => {
- cy.get('.ds-select-dropdown').should(
- 'contain',
- '101 Essays that will change the way you think'
- )
+ cy.get(".ds-select-dropdown").should(
+ "contain",
+ "101 Essays that will change the way you think"
+ );
}
-)
+);
Then(
- 'I should not see posts without the searched-for term in the select dropdown',
+ "I should not see posts without the searched-for term in the select dropdown",
() => {
- cy.get('.ds-select-dropdown').should(
- 'not.contain',
- 'No searched for content'
- )
+ cy.get(".ds-select-dropdown").should(
+ "not.contain",
+ "No searched for content"
+ );
}
-)
+);
diff --git a/webapp/graphql/PostQuery.js b/webapp/graphql/PostQuery.js
index d2bba23ef..eec2b25d8 100644
--- a/webapp/graphql/PostQuery.js
+++ b/webapp/graphql/PostQuery.js
@@ -79,8 +79,8 @@ export default i18n => {
export const filterPosts = i18n => {
const lang = i18n.locale().toUpperCase()
return gql`
- query Post($filter: _PostFilter, $first: Int, $offset: Int) {
- Post(filter: $filter, first: $first, offset: $offset) {
+ query Post($filter: _PostFilter, $first: Int, $offset: Int, $orderBy: [_PostOrdering]) {
+ Post(filter: $filter, first: $first, offset: $offset, orderBy: $orderBy) {
id
title
contentExcerpt
diff --git a/webapp/locales/de.json b/webapp/locales/de.json
index 58dfa187f..1f2544567 100644
--- a/webapp/locales/de.json
+++ b/webapp/locales/de.json
@@ -23,6 +23,12 @@
"bank": "Bankverbindung",
"germany": "Deutschland"
},
+ "sorting": {
+ "newest": "Neuste",
+ "oldest": "Älteste",
+ "popular": "Beliebt",
+ "commented": "meist Kommentiert"
+ },
"login": {
"copy": "Wenn Du bereits ein Konto bei Human Connection hast, melde Dich bitte hier an.",
"login": "Einloggen",
diff --git a/webapp/locales/en.json b/webapp/locales/en.json
index 3c76f6010..c94b57605 100644
--- a/webapp/locales/en.json
+++ b/webapp/locales/en.json
@@ -23,6 +23,12 @@
"bank": "bank account",
"germany": "Germany"
},
+ "sorting": {
+ "newest": "Newest",
+ "oldest": "Oldest",
+ "popular": "Popular",
+ "commented": "most Commented"
+ },
"login": {
"copy": "If you already have a human-connection account, login here.",
"login": "Login",
diff --git a/webapp/pages/index.spec.js b/webapp/pages/index.spec.js
new file mode 100644
index 000000000..8cdf626ab
--- /dev/null
+++ b/webapp/pages/index.spec.js
@@ -0,0 +1,140 @@
+import { config, shallowMount, mount, createLocalVue } from '@vue/test-utils'
+import PostIndex from './index.vue'
+import Vuex from 'vuex'
+import Styleguide from '@human-connection/styleguide'
+import Filters from '~/plugins/vue-filters'
+import VTooltip from 'v-tooltip'
+import FilterMenu from '~/components/FilterMenu/FilterMenu'
+
+const localVue = createLocalVue()
+
+localVue.use(Vuex)
+localVue.use(Styleguide)
+localVue.use(Filters)
+localVue.use(VTooltip)
+
+config.stubs['no-ssr'] = ''
+config.stubs['router-link'] = ''
+config.stubs['nuxt-link'] = ''
+
+describe('PostIndex', () => {
+ let wrapper
+ let Wrapper
+ let store
+ let mocks
+
+ beforeEach(() => {
+ store = new Vuex.Store({
+ getters: {
+ 'posts/posts': () => {
+ return [
+ {
+ id: 'p23',
+ name: 'It is a post',
+ author: {
+ id: 'u1',
+ },
+ },
+ ]
+ },
+ 'auth/user': () => {
+ return { id: 'u23' }
+ },
+ },
+ })
+ mocks = {
+ $t: key => key,
+ $filters: {
+ truncate: a => a,
+ removeLinks: jest.fn(),
+ },
+ // If you are mocking router, than don't use VueRouter with localVue: https://vue-test-utils.vuejs.org/guides/using-with-vue-router.html
+ $router: {
+ history: {
+ push: jest.fn(),
+ },
+ push: jest.fn(),
+ },
+ $toast: {
+ success: jest.fn(),
+ error: jest.fn(),
+ },
+ $apollo: {
+ mutate: jest.fn().mockResolvedValue(),
+ queries: {
+ Post: {
+ refetch: jest.fn(),
+ fetchMore: jest.fn().mockResolvedValue([
+ {
+ id: 'p23',
+ name: 'It is a post',
+ author: {
+ id: 'u1',
+ },
+ },
+ ]),
+ },
+ },
+ },
+ $route: {
+ query: {},
+ },
+ }
+ })
+
+ describe('shallowMount', () => {
+ Wrapper = () => {
+ return shallowMount(PostIndex, {
+ store,
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('refetches Posts when changeFilterBubble is emitted', () => {
+ wrapper.find(FilterMenu).vm.$emit('changeFilterBubble')
+ expect(mocks.$apollo.queries.Post.refetch).toHaveBeenCalledTimes(1)
+ })
+
+ it('clears the search when the filter menu emits clearSearch', () => {
+ wrapper.find(FilterMenu).vm.$emit('clearSearch')
+ expect(wrapper.vm.hashtag).toBeNull()
+ })
+
+ it('calls the changeFilterBubble if there are hasthags in the route query', () => {
+ mocks.$route.query.hashtag = { id: 'hashtag' }
+ wrapper = Wrapper()
+ expect(mocks.$apollo.queries.Post.refetch).toHaveBeenCalledTimes(1)
+ })
+
+ describe('mount', () => {
+ beforeEach(() => {
+ wrapper = mount(PostIndex, {
+ store,
+ mocks,
+ localVue,
+ })
+ })
+
+ it('sets the post in the store when there are posts', () => {
+ wrapper
+ .findAll('li')
+ .at(0)
+ .trigger('click')
+ expect(wrapper.vm.sorting).toEqual('createdAt_desc')
+ })
+
+ it('loads more posts when a user clicks on the load more button', () => {
+ wrapper
+ .findAll('button')
+ .at(2)
+ .trigger('click')
+ expect(mocks.$apollo.queries.Post.fetchMore).toHaveBeenCalledTimes(1)
+ })
+ })
+ })
+})
diff --git a/webapp/pages/index.vue b/webapp/pages/index.vue
index 0930d9a71..8a7276269 100644
--- a/webapp/pages/index.vue
+++ b/webapp/pages/index.vue
@@ -9,6 +9,17 @@
@clearSearch="clearSearch"
/>
+
+
+
+
+