From 7379752194f81f751500c4f882af066bc110558a Mon Sep 17 00:00:00 2001 From: Nicolas Beaussart Date: Wed, 2 Dec 2020 20:46:04 +0100 Subject: [PATCH] :white_check_mark: add tests --- tests/unit/.eslintrc.js | 5 + tests/unit/components/ListError.spec.js | 47 ++++ tests/unit/components/VPagination.spec.js | 34 +++ tests/unit/components/VTag.spec.js | 25 ++ tests/unit/example.spec.js | 51 ++++ .../__snapshots__/article.module.spec.js.snap | 18 ++ tests/unit/store/article.module.spec.js | 260 ++++++++++++++++++ 7 files changed, 440 insertions(+) create mode 100644 tests/unit/.eslintrc.js create mode 100644 tests/unit/components/ListError.spec.js create mode 100644 tests/unit/components/VPagination.spec.js create mode 100644 tests/unit/components/VTag.spec.js create mode 100644 tests/unit/example.spec.js create mode 100644 tests/unit/store/__snapshots__/article.module.spec.js.snap create mode 100644 tests/unit/store/article.module.spec.js diff --git a/tests/unit/.eslintrc.js b/tests/unit/.eslintrc.js new file mode 100644 index 0000000..3600451 --- /dev/null +++ b/tests/unit/.eslintrc.js @@ -0,0 +1,5 @@ +module.exports = { + env: { + jest: true + } +}; diff --git a/tests/unit/components/ListError.spec.js b/tests/unit/components/ListError.spec.js new file mode 100644 index 0000000..571ac8a --- /dev/null +++ b/tests/unit/components/ListError.spec.js @@ -0,0 +1,47 @@ +import { mount } from "@vue/test-utils"; + +import ListErrors from "../../../src/components/ListErrors.vue"; + +const createWrapper = ({ errors }) => { + return mount(ListErrors, { + propsData: { + errors + } + }); +}; + +describe("ListErrors", () => { + let errors; + + beforeEach(() => { + errors = { + title: ["Title Error"], + body: ["can't be blank"], + description: ["can't be blank"] + }; + }); + + it("should display the correct error messages based on object from props", () => { + const wrapper = createWrapper({ errors }); + + const errorMessages = wrapper.findAll("li"); + expect(errorMessages.length).toEqual(3); + expect(errorMessages.at(0).text()).toContain(errors.title); + expect(errorMessages.at(1).text()).toContain(errors.body); + expect(errorMessages.at(2).text()).toContain(errors.description); + }); + + it("should have props with errors as type object", () => { + const wrapper = createWrapper({ errors }); + expect(typeof wrapper.props().errors).toBe("object"); + }); + + it("should have no errors if no errors are passed into the props", () => { + errors = {}; + + const wrapper = createWrapper({ errors }); + + const errorMessages = wrapper.findAll("li"); + expect(errorMessages.length).toEqual(0); + }); +}); diff --git a/tests/unit/components/VPagination.spec.js b/tests/unit/components/VPagination.spec.js new file mode 100644 index 0000000..496a6b2 --- /dev/null +++ b/tests/unit/components/VPagination.spec.js @@ -0,0 +1,34 @@ +import { mount } from "@vue/test-utils"; + +import VPagination from "../../../src/components/VPagination.vue"; + +const createWrapper = ({ currentPage = 1 }) => { + return mount(VPagination, { + propsData: { + pages: [1, 2, 3, 4], + currentPage + } + }); +}; + +describe("VPagination", () => { + it("should render active class to right element", () => { + const wrapper = createWrapper({ currentPage: 2 }); + const activeItem = wrapper.find(".active"); + expect(activeItem.text()).toBe("2"); + }); + + it("should emit an event if page is clicked which is not active", () => { + const wrapper = createWrapper({ currentPage: 1 }); + const pageItem = wrapper.find('[data-test="page-link-2"]'); + pageItem.trigger("click"); + expect(wrapper.emitted("update:currentPage")).toBeTruthy(); + }); + + it("should have the right payload when event is emitted", () => { + const wrapper = createWrapper({ currentPage: 1 }); + const pageItem = wrapper.find('[data-test="page-link-2"]'); + pageItem.trigger("click"); + expect(wrapper.emitted("update:currentPage")[0][0]).toBe(2); + }); +}); diff --git a/tests/unit/components/VTag.spec.js b/tests/unit/components/VTag.spec.js new file mode 100644 index 0000000..35cf4aa --- /dev/null +++ b/tests/unit/components/VTag.spec.js @@ -0,0 +1,25 @@ +import { mount, createLocalVue } from "@vue/test-utils"; + +import router from "../../../src/router/index"; +import VTag from "../../../src/components/VTag"; + +const localVue = createLocalVue(); +const createWrapper = () => { + return mount(VTag, { + localVue, + router, + propsData: { + name: "Foo" + } + }); +}; + +describe("VTag", () => { + it("should update the route on click", async () => { + const wrapper = createWrapper(); + const routerBefore = wrapper.vm.$route.path; + wrapper.find("a").trigger("click"); + await localVue.nextTick(); + expect(wrapper.vm.$route.path).not.toBe(routerBefore); + }); +}); diff --git a/tests/unit/example.spec.js b/tests/unit/example.spec.js new file mode 100644 index 0000000..5b70ca4 --- /dev/null +++ b/tests/unit/example.spec.js @@ -0,0 +1,51 @@ +import { createLocalVue, mount } from "@vue/test-utils"; +import Vuex from "vuex"; +import VueRouter from "vue-router"; + +import Comment from "../../src/components/Comment.vue"; +import DateFilter from "../../src/common/date.filter"; + +const localVue = createLocalVue(); +localVue.filter("date", DateFilter); +localVue.use(Vuex); +localVue.use(VueRouter); + +describe("Comment", () => { + it("should render correct contents", () => { + const router = new VueRouter({ + routes: [ + { + name: "profile", + path: "/profile", + component: null + } + ] + }); + let store = new Vuex.Store({ + getters: { + currentUser: () => ({ + username: "user-3518518" + }) + } + }); + + const wrapper = mount(Comment, { + localVue, + store, + router, + propsData: { + slug: "super-cool-comment-slug-1245781274", + comment: { + body: "body of comment", + author: { + image: "https://vuejs.org/images/logo.png", + username: "user-3518518" + }, + createdAt: "", + id: 1245781274 + } + } + }); + expect(wrapper.isVueInstance()).toBeTruthy(); + }); +}); diff --git a/tests/unit/store/__snapshots__/article.module.spec.js.snap b/tests/unit/store/__snapshots__/article.module.spec.js.snap new file mode 100644 index 0000000..fa0f7c5 --- /dev/null +++ b/tests/unit/store/__snapshots__/article.module.spec.js.snap @@ -0,0 +1,18 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Vuex Article Module should return the data of the api call when calling the function 1`] = ` +Object { + "article": Object { + "author": Object {}, + "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed dictum efficitur justo, nec aliquam quam rutrum in. Pellentesque vulputate augue quis vulputate finibus. Phasellus auctor semper sapien sit amet interdum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas placerat auctor metus. Integer blandit lacinia volutpat.", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sed cursus nisl. Morbi pulvinar nisl urna, tincidunt mattis tortor sollicitudin eget. Nulla viverra justo quis.", + "tagList": Array [ + "lorem", + "ipsum", + "javascript", + "vue", + ], + "title": "Lorem ipsum dolor sit amet", + }, +} +`; diff --git a/tests/unit/store/article.module.spec.js b/tests/unit/store/article.module.spec.js new file mode 100644 index 0000000..19afa5f --- /dev/null +++ b/tests/unit/store/article.module.spec.js @@ -0,0 +1,260 @@ +import { actions } from "../../../src/store/article.module"; +import { + FETCH_ARTICLE, + FETCH_COMMENTS, + COMMENT_CREATE, + COMMENT_DESTROY, + FAVORITE_ADD, + FAVORITE_REMOVE +} from "../../../src/store/actions.type"; + +jest.mock("vue", () => { + return { + axios: { + get: jest.fn().mockImplementation(async articleSlug => { + if (articleSlug.includes("8371b051-cffc-4ff0-887c-2c477615a28e")) { + return { + data: { + article: { + author: {}, + title: "Lorem ipsum dolor sit amet", + description: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sed cursus nisl. Morbi pulvinar nisl urna, tincidunt mattis tortor sollicitudin eget. Nulla viverra justo quis.", + body: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed dictum efficitur justo, nec aliquam quam rutrum in. Pellentesque vulputate augue quis vulputate finibus. Phasellus auctor semper sapien sit amet interdum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas placerat auctor metus. Integer blandit lacinia volutpat.", + tagList: ["lorem", "ipsum", "javascript", "vue"] + } + } + }; + } + if (articleSlug.includes("f986b3d6-95c2-4c4f-a6b9-fbbf79d8cb0c")) { + return { + data: { + comments: [ + { + id: 1, + createdAt: "2018-12-01T15:43:41.235Z", + updatedAt: "2018-12-01T15:43:41.235Z", + body: "Lorem ipsum dolor sit amet.", + author: { + username: "dccf649a-5e7b-4040-b8c3-ecf74598eba2", + bio: null, + image: "https://via.placeholder.com/350x150", + following: false + } + }, + { + id: 2, + createdAt: "2018-12-01T15:43:39.077Z", + updatedAt: "2018-12-01T15:43:39.077Z", + body: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse aliquet.", + author: { + username: "8568a50a-9656-4d55-a023-632029513a2d", + bio: null, + image: "https://via.placeholder.com/350x150", + following: false + } + } + ] + } + }; + } + throw new Error("Article not existing"); + }), + post: jest.fn().mockImplementation(async articleSlug => { + if (articleSlug.includes("582e1e46-6b8b-4f4d-8848-f07b57e015a0")) { + return null; + } + if (articleSlug.includes("5611ee1b-0b95-417f-a917-86687176a627")) { + return { + data: { + article: { + author: {}, + title: "Lorem ipsum dolor sit amet", + description: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sed cursus nisl. Morbi pulvinar nisl urna, tincidunt mattis tortor sollicitudin eget. Nulla viverra justo quis.", + body: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed dictum efficitur justo, nec aliquam quam rutrum in. Pellentesque vulputate augue quis vulputate finibus. Phasellus auctor semper sapien sit amet interdum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas placerat auctor metus. Integer blandit lacinia volutpat.", + tagList: ["lorem", "ipsum", "javascript", "vue"] + } + } + }; + } + throw new Error("Article not existing"); + }), + delete: jest.fn().mockImplementation(async articleSlug => { + if (articleSlug.includes("657a6075-d269-4aec-83fa-b14f579a3e78")) { + return null; + } + if (articleSlug.includes("480fdaf8-027c-43b1-8952-8403f90dcdab")) { + return { + data: { + article: { + author: {}, + title: "Lorem ipsum dolor sit amet", + description: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sed cursus nisl. Morbi pulvinar nisl urna, tincidunt mattis tortor sollicitudin eget. Nulla viverra justo quis.", + body: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed dictum efficitur justo, nec aliquam quam rutrum in. Pellentesque vulputate augue quis vulputate finibus. Phasellus auctor semper sapien sit amet interdum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas placerat auctor metus. Integer blandit lacinia volutpat.", + tagList: ["lorem", "ipsum", "javascript", "vue"] + } + } + }; + } + throw new Error("Article not existing"); + }) + } + }; +}); + +describe("Vuex Article Module", () => { + it("should commit the previous article if it is given", async () => { + const commitFunction = jest.fn(); + const context = { commit: commitFunction }; + const articleSlug = "8371b051-cffc-4ff0-887c-2c477615a28e"; + const prevArticle = { + author: {}, + title: "Aye up, she's a reight bobby dazzler", + description: + "Yer flummoxed. Fair t' middlin, this is. Off f'r a sup down t'pub, to'neet. Ee bye ecky thump!", + body: + "Tha's better bi careful, lass - yer on a Scarborough warning! Tha meks a better door than a winder. Do I 'eckers like, You're in luck m'boy! Am proper knackered, aye I am that is I say.", + tagList: ["aye", "ipsum", "javascript", "vue"] + }; + await actions[FETCH_ARTICLE](context, articleSlug, prevArticle); + expect(commitFunction.mock.calls[0][0]).toBe("setArticle"); + expect(commitFunction.mock.calls[0][1]).toBe(prevArticle); + }); + + it("should return the data of the api call when calling the function", async () => { + const context = { commit: () => {} }; + const articleSlug = "8371b051-cffc-4ff0-887c-2c477615a28e"; + const prevArticle = undefined; + const actionCall = await actions[FETCH_ARTICLE]( + context, + articleSlug, + prevArticle + ); + expect(actionCall).toMatchSnapshot(); + }); + + it("should commit the right name when fetching comments for an existing article", async () => { + const commitFunction = jest.fn(); + const context = { commit: commitFunction }; + const articleSlug = "f986b3d6-95c2-4c4f-a6b9-fbbf79d8cb0c"; + await actions[FETCH_COMMENTS](context, articleSlug); + expect(commitFunction.mock.calls[0][0]).toBe("setComments"); + }); + + it("should commit the exact size of comments", async () => { + const commitFunction = jest.fn(); + const context = { commit: commitFunction }; + const articleSlug = "f986b3d6-95c2-4c4f-a6b9-fbbf79d8cb0c"; + await actions[FETCH_COMMENTS](context, articleSlug); + expect(commitFunction.mock.calls[0][1]).toHaveLength(2); + }); + + it("should return the comments from the fetch comments action", async () => { + const context = { commit: () => {} }; + const articleSlug = "f986b3d6-95c2-4c4f-a6b9-fbbf79d8cb0c"; + const comments = await actions[FETCH_COMMENTS](context, articleSlug); + expect(comments).toHaveLength(2); + }); + + it("should dispatch a fetching comment action after successfully creating a comment", async () => { + const dispatchFunction = jest.fn(); + const context = { dispatch: dispatchFunction }; + const payload = { + slug: "582e1e46-6b8b-4f4d-8848-f07b57e015a0", + comment: "Lorem Ipsum" + }; + await actions[COMMENT_CREATE](context, payload); + expect(dispatchFunction).toHaveBeenLastCalledWith( + "fetchComments", + "582e1e46-6b8b-4f4d-8848-f07b57e015a0" + ); + }); + + it("should dispatch a fetching comment action after successfully deleting a comment", async () => { + const dispatchFunction = jest.fn(); + const context = { dispatch: dispatchFunction }; + const payload = { + slug: "657a6075-d269-4aec-83fa-b14f579a3e78", + commentId: 1 + }; + await actions[COMMENT_DESTROY](context, payload); + expect(dispatchFunction).toHaveBeenLastCalledWith( + "fetchComments", + "657a6075-d269-4aec-83fa-b14f579a3e78" + ); + }); + + it("should commit updating the article in the list action favorize an article", async () => { + const commitFunction = jest.fn(); + const context = { commit: commitFunction }; + const payload = "5611ee1b-0b95-417f-a917-86687176a627"; + await actions[FAVORITE_ADD](context, payload); + expect(commitFunction.mock.calls[0][0]).toBe("updateArticleInList"); + expect(commitFunction.mock.calls[0][1]).toEqual({ + author: {}, + title: "Lorem ipsum dolor sit amet", + description: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sed cursus nisl. Morbi pulvinar nisl urna, tincidunt mattis tortor sollicitudin eget. Nulla viverra justo quis.", + body: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed dictum efficitur justo, nec aliquam quam rutrum in. Pellentesque vulputate augue quis vulputate finibus. Phasellus auctor semper sapien sit amet interdum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas placerat auctor metus. Integer blandit lacinia volutpat.", + tagList: ["lorem", "ipsum", "javascript", "vue"] + }); + }); + + it("should commit setting the article", async () => { + const commitFunction = jest.fn(); + const context = { commit: commitFunction }; + const payload = "5611ee1b-0b95-417f-a917-86687176a627"; + await actions[FAVORITE_ADD](context, payload); + expect(commitFunction.mock.calls[1][0]).toBe("setArticle"); + expect(commitFunction.mock.calls[1][1]).toEqual({ + author: {}, + title: "Lorem ipsum dolor sit amet", + description: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sed cursus nisl. Morbi pulvinar nisl urna, tincidunt mattis tortor sollicitudin eget. Nulla viverra justo quis.", + body: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed dictum efficitur justo, nec aliquam quam rutrum in. Pellentesque vulputate augue quis vulputate finibus. Phasellus auctor semper sapien sit amet interdum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas placerat auctor metus. Integer blandit lacinia volutpat.", + tagList: ["lorem", "ipsum", "javascript", "vue"] + }); + }); + + it("should commit updating the article in the list action favorize an article", async () => { + const commitFunction = jest.fn(); + const context = { commit: commitFunction }; + const payload = "480fdaf8-027c-43b1-8952-8403f90dcdab"; + await actions[FAVORITE_REMOVE](context, payload); + expect(commitFunction.mock.calls[0][0]).toBe("updateArticleInList"); + expect(commitFunction.mock.calls[0][1]).toEqual({ + author: {}, + title: "Lorem ipsum dolor sit amet", + description: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sed cursus nisl. Morbi pulvinar nisl urna, tincidunt mattis tortor sollicitudin eget. Nulla viverra justo quis.", + body: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed dictum efficitur justo, nec aliquam quam rutrum in. Pellentesque vulputate augue quis vulputate finibus. Phasellus auctor semper sapien sit amet interdum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas placerat auctor metus. Integer blandit lacinia volutpat.", + tagList: ["lorem", "ipsum", "javascript", "vue"] + }); + }); + + it("should commit setting the article", async () => { + const commitFunction = jest.fn(); + const context = { commit: commitFunction }; + const payload = "480fdaf8-027c-43b1-8952-8403f90dcdab"; + await actions[FAVORITE_REMOVE](context, payload); + expect(commitFunction.mock.calls[1][0]).toBe("setArticle"); + expect(commitFunction.mock.calls[1][1]).toEqual({ + author: {}, + title: "Lorem ipsum dolor sit amet", + description: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sed cursus nisl. Morbi pulvinar nisl urna, tincidunt mattis tortor sollicitudin eget. Nulla viverra justo quis.", + body: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed dictum efficitur justo, nec aliquam quam rutrum in. Pellentesque vulputate augue quis vulputate finibus. Phasellus auctor semper sapien sit amet interdum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas placerat auctor metus. Integer blandit lacinia volutpat.", + tagList: ["lorem", "ipsum", "javascript", "vue"] + }); + }); +});