From 7bd643b98b6e50c7b0a360b5307ad585871875de Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 19 Jan 2023 13:39:25 +0100 Subject: [PATCH 1/5] feat(frontend): unit tetst community page --- frontend/package.json | 2 + frontend/src/pages/Community.spec.js | 7 ++ frontend/yarn.lock | 116 ++++++++++++++++++++++++++- 3 files changed, 122 insertions(+), 3 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 55e28b45c..705dea0b2 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -66,6 +66,7 @@ "vuex-persistedstate": "^4.0.0-beta.3" }, "devDependencies": { + "@apollo/client": "^3.7.4", "@intlify/eslint-plugin-vue-i18n": "^1.4.0", "@vue/cli-plugin-babel": "^3.7.0", "@vue/cli-plugin-eslint": "^3.7.0", @@ -76,6 +77,7 @@ "babel-plugin-transform-require-context": "^0.1.1", "cross-env": "^7.0.3", "dotenv-webpack": "^7.0.3", + "mock-apollo-client": "^1.2.1", "postcss": "^8.4.8", "postcss-html": "^1.3.0", "postcss-scss": "^4.0.3", diff --git a/frontend/src/pages/Community.spec.js b/frontend/src/pages/Community.spec.js index 41ecc75e9..2dd119233 100644 --- a/frontend/src/pages/Community.spec.js +++ b/frontend/src/pages/Community.spec.js @@ -3,6 +3,13 @@ import Community from './Community' import { toastErrorSpy, toastSuccessSpy } from '@test/testSetup' import { createContribution, updateContribution, deleteContribution } from '@/graphql/mutations' import { listContributions, listAllContributions } from '@/graphql/queries' +import { createMockClient } from 'mock-apollo-client' +import VueApollo from 'vue-apollo' + +const mockClient = createMockClient() +const apolloProvider = new VueApollo({ + defaultClient: mockClient, +}) const localVue = global.localVue diff --git a/frontend/yarn.lock b/frontend/yarn.lock index f374ac7bd..4abfbddf4 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2,6 +2,25 @@ # yarn lockfile v1 +"@apollo/client@^3.7.4": + version "3.7.4" + resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.7.4.tgz#28c3fb7f89365ccaf185bc8b51860041f37629b3" + integrity sha512-bgiCKRmLSBImX4JRrw8NjqGo0AQE/mowCdHX1PJp2r5zIXrJx0UeaAYmx1qJY69Oz/KR7SKlLt4xK+bOP1jx7A== + dependencies: + "@graphql-typed-document-node/core" "^3.1.1" + "@wry/context" "^0.7.0" + "@wry/equality" "^0.5.0" + "@wry/trie" "^0.3.0" + graphql-tag "^2.12.6" + hoist-non-react-statics "^3.3.2" + optimism "^0.16.1" + prop-types "^15.7.2" + response-iterator "^0.2.6" + symbol-observable "^4.0.0" + ts-invariant "^0.10.3" + tslib "^2.3.0" + zen-observable-ts "^1.2.5" + "@babel/code-frame@7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" @@ -1904,6 +1923,11 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@graphql-typed-document-node/core@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.1.tgz#076d78ce99822258cf813ecc1e7fa460fa74d052" + integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg== + "@hapi/address@2.x.x": version "2.1.4" resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" @@ -3159,6 +3183,13 @@ "@types/node" ">=6" tslib "^1.9.3" +"@wry/context@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.7.0.tgz#be88e22c0ddf62aeb0ae9f95c3d90932c619a5c8" + integrity sha512-LcDAiYWRtwAoSOArfk7cuYvFXytxfVrdX7yxoUmK7pPITLk5jYh2F8knCwS7LjgYL8u1eidPlKKV6Ikqq0ODqQ== + dependencies: + tslib "^2.3.0" + "@wry/equality@^0.1.2": version "0.1.11" resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.1.11.tgz#35cb156e4a96695aa81a9ecc4d03787bc17f1790" @@ -3166,6 +3197,20 @@ dependencies: tslib "^1.9.3" +"@wry/equality@^0.5.0": + version "0.5.3" + resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.5.3.tgz#fafebc69561aa2d40340da89fa7dc4b1f6fb7831" + integrity sha512-avR+UXdSrsF2v8vIqIgmeTY0UR91UT+IyablCyKe/uk22uOJ8fusKZnH9JH9e1/EtLeNJBtagNmL3eJdnOV53g== + dependencies: + tslib "^2.3.0" + +"@wry/trie@^0.3.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.3.2.tgz#a06f235dc184bd26396ba456711f69f8c35097e6" + integrity sha512-yRTyhWSls2OY/pYLfwff867r8ekooZ4UI+/gxot5Wj8EFwSf2rG+n+Mo/6LoLQm1TKA4GRj2+LCpbfS937dClQ== + dependencies: + tslib "^2.3.0" + "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" @@ -7453,6 +7498,13 @@ graceful-fs@^4.2.4: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== +graphql-tag@^2.12.6: + version "2.12.6" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" + integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== + dependencies: + tslib "^2.1.0" + graphql-tag@^2.4.2: version "2.12.5" resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.5.tgz#5cff974a67b417747d05c8d9f5f3cb4495d0db8f" @@ -7636,6 +7688,13 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" @@ -9915,7 +9974,7 @@ loglevel@^1.6.8: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw== -loose-envify@^1.0.0, loose-envify@^1.2.0: +loose-envify@^1.0.0, loose-envify@^1.2.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -10260,6 +10319,11 @@ mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +mock-apollo-client@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/mock-apollo-client/-/mock-apollo-client-1.2.1.tgz#e3bfdc3ff73b1fea28fa7e91ec82e43ba8cbfa39" + integrity sha512-QYQ6Hxo+t7hard1bcHHbsHxlNQYTQsaMNsm2Psh/NbwLMi2R4tGzplJKt97MUWuARHMq3GHB4PTLj/gxej4Caw== + moment@^2.19.2: version "2.29.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" @@ -10767,6 +10831,14 @@ optimism@^0.10.0: dependencies: "@wry/context" "^0.4.0" +optimism@^0.16.1: + version "0.16.2" + resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.16.2.tgz#519b0c78b3b30954baed0defe5143de7776bf081" + integrity sha512-zWNbgWj+3vLEjZNIh/okkY2EUfX+vB9TJopzIZwT1xxaMqC5hRLLraePod4c5n4He08xuXNH+zhKFFCu390wiQ== + dependencies: + "@wry/context" "^0.7.0" + "@wry/trie" "^0.3.0" + optionator@^0.8.1, optionator@^0.8.2: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" @@ -11721,6 +11793,15 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" +prop-types@^15.7.2: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + proto-list@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" @@ -11900,7 +11981,7 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -react-is@^16.8.4: +react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.4: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -12269,6 +12350,11 @@ resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.1 is-core-module "^2.2.0" path-parse "^1.0.6" +response-iterator@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/response-iterator/-/response-iterator-0.2.6.tgz#249005fb14d2e4eeb478a3f735a28fd8b4c9f3da" + integrity sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw== + restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -13406,6 +13492,11 @@ symbol-observable@^1.0.2: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== +symbol-observable@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" + integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== + symbol-tree@^3.2.2, symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" @@ -13704,6 +13795,13 @@ tryer@^1.0.1: resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== +ts-invariant@^0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.10.3.tgz#3e048ff96e91459ffca01304dbc7f61c1f642f6c" + integrity sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ== + dependencies: + tslib "^2.1.0" + ts-invariant@^0.4.0: version "0.4.4" resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.4.4.tgz#97a523518688f93aafad01b0e80eb803eb2abd86" @@ -13757,6 +13855,11 @@ tslib@^2.1.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== +tslib@^2.3.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" + integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== + tsutils@^3.17.1: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -14919,7 +15022,14 @@ zen-observable-ts@^0.8.21: tslib "^1.9.3" zen-observable "^0.8.0" -zen-observable@^0.8.0: +zen-observable-ts@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz#6c6d9ea3d3a842812c6e9519209365a122ba8b58" + integrity sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg== + dependencies: + zen-observable "0.8.15" + +zen-observable@0.8.15, zen-observable@^0.8.0: version "0.8.15" resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== From be65595bee695c31321617a5b534f071ed34f824 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 19 Jan 2023 18:21:00 +0100 Subject: [PATCH 2/5] refcator tests for apollo calls --- frontend/src/pages/Community.spec.js | 450 ++++++++++++++++----------- frontend/src/pages/Community.vue | 145 ++++----- frontend/test/testSetup.js | 1 + 3 files changed, 325 insertions(+), 271 deletions(-) diff --git a/frontend/src/pages/Community.spec.js b/frontend/src/pages/Community.spec.js index 2dd119233..34fc3dba4 100644 --- a/frontend/src/pages/Community.spec.js +++ b/frontend/src/pages/Community.spec.js @@ -1,8 +1,8 @@ import { mount } from '@vue/test-utils' import Community from './Community' -import { toastErrorSpy, toastSuccessSpy } from '@test/testSetup' +import { toastErrorSpy, toastSuccessSpy, toastInfoSpy } from '@test/testSetup' import { createContribution, updateContribution, deleteContribution } from '@/graphql/mutations' -import { listContributions, listAllContributions } from '@/graphql/queries' +import { listContributions, listAllContributions, openCreations } from '@/graphql/queries' import { createMockClient } from 'mock-apollo-client' import VueApollo from 'vue-apollo' @@ -12,54 +12,48 @@ const apolloProvider = new VueApollo({ }) const localVue = global.localVue +localVue.use(VueApollo) const mockStoreDispach = jest.fn() -const apolloQueryMock = jest.fn() -const apolloMutationMock = jest.fn() -const apolloRefetchMock = jest.fn() +const routerPushMock = jest.fn() describe('Community', () => { let wrapper - const mocks = { - $t: jest.fn((t) => t), - $d: jest.fn((d) => d), - $apollo: { - query: apolloQueryMock, - mutate: apolloMutationMock, - queries: { - OpenCreations: { - refetch: apolloRefetchMock, + mockClient.setRequestHandler( + openCreations, + jest + .fn() + .mockRejectedValueOnce({ message: 'Open Creations failed!' }) + .mockResolvedValue({ + data: { + openCreations: [ + { + month: 0, + year: 2023, + amount: '1000', + }, + { + month: 1, + year: 2023, + amount: '1000', + }, + { + month: 2, + year: 2023, + amount: '1000', + }, + ], }, - }, - }, - $store: { - dispatch: mockStoreDispach, - state: { - creation: ['1000', '1000', '1000'], - }, - }, - $i18n: { - locale: 'en', - }, - $router: { - push: jest.fn(), - }, - $route: { - hash: 'my', - }, - } + }), + ) - const Wrapper = () => { - return mount(Community, { - localVue, - mocks, - }) - } - - describe('mount', () => { - beforeEach(() => { - apolloQueryMock.mockResolvedValue({ + mockClient.setRequestHandler( + listContributions, + jest + .fn() + .mockRejectedValueOnce({ message: 'List Contributions failed!' }) + .mockResolvedValue({ data: { listContributions: { contributionList: [ @@ -71,10 +65,40 @@ describe('Community', () => { deletedAt: null, confirmedBy: null, confirmedAt: null, + firstName: 'Bibi', + contributionDate: '2022-07-15T08:47:06.000Z', + lastName: 'Bloxberg', + state: 'IN_PROGRESS', + messagesCount: 0, + }, + { + id: 1550, + amount: '200', + memo: 'Fleisig, fleisig am Arbeiten gewesen', + createdAt: '2022-07-15T08:47:06.000Z', + deletedAt: null, + confirmedBy: null, + confirmedAt: null, + firstName: 'Bibi', + contributionDate: '2022-06-15T08:47:06.000Z', + lastName: 'Bloxberg', + state: 'CONFIRMED', + messagesCount: 0, }, ], contributionCount: 1, }, + }, + }), + ) + + mockClient.setRequestHandler( + listAllContributions, + jest + .fn() + .mockRejectedValueOnce({ message: 'List All Contributions failed!' }) + .mockResolvedValue({ + data: { listAllContributions: { contributionList: [ { @@ -82,29 +106,137 @@ describe('Community', () => { amount: '200', memo: 'Fleisig, fleisig am Arbeiten mein lieber Freund, 50 Zeichen sind viel', createdAt: '2022-07-15T08:47:06.000Z', + contributionDate: '2022-07-15T08:47:06.000Z', deletedAt: null, confirmedBy: null, confirmedAt: null, + firstName: 'Bibi', + lastName: 'Bloxberg', + }, + { + id: 1550, + amount: '200', + memo: 'Fleisig, fleisig am Arbeiten gewesen', + createdAt: '2022-07-15T08:47:06.000Z', + deletedAt: null, + confirmedBy: null, + confirmedAt: null, + firstName: 'Bibi', + contributionDate: '2022-06-15T08:47:06.000Z', + lastName: 'Bloxberg', + messagesCount: 0, }, { id: 1556, amount: '400', memo: 'Ein anderer lieber Freund ist auch sehr felißig am Arbeiten!!!!', createdAt: '2022-07-16T08:47:06.000Z', + contributionDate: '2022-07-16T08:47:06.000Z', deletedAt: null, confirmedBy: null, confirmedAt: null, + firstName: 'Bob', + lastName: 'der Baumeister', }, ], - contributionCount: 2, + contributionCount: 3, }, }, - }) + }), + ) + + mockClient.setRequestHandler( + createContribution, + jest + .fn() + .mockRejectedValueOnce({ message: 'Create Contribution failed!' }) + .mockResolvedValue({ + data: { + createContribution: true, + }, + }), + ) + + mockClient.setRequestHandler( + updateContribution, + jest + .fn() + .mockRejectedValueOnce({ message: 'Update Contribution failed!' }) + .mockResolvedValue({ + data: { + updateContribution: true, + }, + }), + ) + + mockClient.setRequestHandler( + deleteContribution, + jest + .fn() + .mockRejectedValueOnce({ message: 'Delete Contribution failed!' }) + .mockResolvedValue({ + data: { + deleteContribution: true, + }, + }), + ) + + const mocks = { + $t: jest.fn((t) => t), + $d: jest.fn((d) => d), + $store: { + dispatch: mockStoreDispach, + state: { + user: { + firstName: 'Bibi', + lastName: 'Bloxberg', + }, + }, + }, + $i18n: { + locale: 'en', + }, + $router: { + push: routerPushMock, + }, + $route: { + hash: '#edit', + }, + } + + const Wrapper = () => { + return mount(Community, { + localVue, + mocks, + apolloProvider, + }) + } + + let apolloMutateSpy + let refetchContributionsSpy + let refetchAllContributionsSpy + let refetchOpenCreationsSpy + + describe('mount', () => { + beforeEach(() => { + jest.clearAllMocks() wrapper = Wrapper() + apolloMutateSpy = jest.spyOn(wrapper.vm.$apollo, 'mutate') + refetchContributionsSpy = jest.spyOn(wrapper.vm.$apollo.queries.ListContributions, 'refetch') + refetchAllContributionsSpy = jest.spyOn( + wrapper.vm.$apollo.queries.ListAllContributions, + 'refetch', + ) + refetchOpenCreationsSpy = jest.spyOn(wrapper.vm.$apollo.queries.OpenCreations, 'refetch') }) - it('has a DIV .community-page', () => { - expect(wrapper.find('div.community-page').exists()).toBe(true) + describe('server response for queries is error', () => { + it('toasts three errors', () => { + expect(toastErrorSpy).toBeCalledTimes(3) + expect(toastErrorSpy).toBeCalledWith('Open Creations failed!') + expect(toastErrorSpy).toBeCalledWith('List Contributions failed!') + expect(toastErrorSpy).toBeCalledWith('List All Contributions failed!') + }) }) describe('tabs', () => { @@ -112,60 +244,51 @@ describe('Community', () => { expect(wrapper.findAll('div[role="tabpanel"]')).toHaveLength(3) }) - it.todo('check for correct tabIndex if state is "IN_PROGRESS" or not') + it('check for correct tabIndex if state is "IN_PROGRESS" or not', () => { + expect(routerPushMock).toBeCalledWith({ path: '/community#my' }) + }) + + it('toasts an info', () => { + expect(toastInfoSpy).toBeCalledWith( + 'Du hast eine Rückfrage auf eine Contribution. Bitte beantworte diese!', + ) + }) }) describe('API calls after creation', () => { + it('has a DIV .community-page', () => { + expect(wrapper.find('div.community-page').exists()).toBe(true) + }) + it('emits update transactions', () => { expect(wrapper.emitted('update-transactions')).toEqual([[0]]) }) - - it('queries list of own contributions', () => { - expect(apolloQueryMock).toBeCalledWith({ - fetchPolicy: 'no-cache', - query: listContributions, - variables: { - currentPage: 1, - pageSize: 25, - }, - }) - }) - - it('queries list of all contributions', () => { - expect(apolloQueryMock).toBeCalledWith({ - fetchPolicy: 'no-cache', - query: listAllContributions, - variables: { - currentPage: 1, - pageSize: 25, - }, - }) - }) - - describe('server response is error', () => { - beforeEach(() => { - jest.clearAllMocks() - apolloQueryMock.mockRejectedValue({ message: 'Ups' }) - wrapper = Wrapper() - }) - - it('toasts two errors', () => { - expect(toastErrorSpy).toBeCalledTimes(2) - expect(toastErrorSpy).toBeCalledWith('Ups') - }) - }) }) - describe('set contrubtion', () => { + describe('save contrubtion', () => { + describe('with error', () => { + const now = new Date().toISOString() + beforeEach(async () => { + await wrapper.setData({ + form: { + id: null, + date: now, + memo: 'Mein Beitrag zur Gemeinschaft für diesen Monat ...', + amount: '200', + }, + }) + await wrapper.find('form').trigger('submit') + }) + + it('toasts the error message', () => { + expect(toastErrorSpy).toBeCalledWith('Create Contribution failed!') + }) + }) + describe('with success', () => { const now = new Date().toISOString() beforeEach(async () => { jest.clearAllMocks() - apolloMutationMock.mockResolvedValue({ - data: { - createContribution: true, - }, - }) await wrapper.setData({ form: { id: null, @@ -178,7 +301,7 @@ describe('Community', () => { }) it('calls the create contribution mutation', () => { - expect(apolloMutationMock).toBeCalledWith({ + expect(apolloMutateSpy).toBeCalledWith({ fetchPolicy: 'no-cache', mutation: createContribution, variables: { @@ -194,62 +317,49 @@ describe('Community', () => { }) it('updates the contribution list', () => { - expect(apolloQueryMock).toBeCalledWith({ - fetchPolicy: 'no-cache', - query: listContributions, - variables: { - currentPage: 1, - pageSize: 25, - }, - }) + expect(refetchContributionsSpy).toBeCalled() }) - it('verifies the login (to get the new creations available)', () => { - expect(apolloRefetchMock).toBeCalled() + it('updates the all contribution list', () => { + expect(refetchAllContributionsSpy).toBeCalled() }) - it('set all data to the default values)', () => { + it('updates the open creations', () => { + expect(refetchOpenCreationsSpy).toBeCalled() + }) + + it('sets all data to the default values)', () => { expect(wrapper.vm.form.id).toBe(null) expect(wrapper.vm.form.date).toBe('') expect(wrapper.vm.form.memo).toBe('') expect(wrapper.vm.form.amount).toBe('') }) }) - - describe('with error', () => { - const now = new Date().toISOString() - beforeEach(async () => { - jest.clearAllMocks() - apolloMutationMock.mockRejectedValue({ - message: 'Ouch!', - }) - await wrapper.setData({ - form: { - id: null, - date: now, - memo: 'Mein Beitrag zur Gemeinschaft für diesen Monat ...', - amount: '200', - }, - }) - await wrapper.find('form').trigger('submit') - }) - - it('toasts the error message', () => { - expect(toastErrorSpy).toBeCalledWith('Ouch!') - }) - }) }) describe('update contrubtion', () => { + describe('with error', () => { + const now = new Date().toISOString() + beforeEach(async () => { + await wrapper + .findComponent({ name: 'ContributionForm' }) + .vm.$emit('update-contribution', { + id: 2, + date: now, + memo: 'Mein Beitrag zur Gemeinschaft für diesen Monat ...', + amount: '400', + }) + }) + + it('toasts the error message', () => { + expect(toastErrorSpy).toBeCalledWith('Update Contribution failed!') + }) + }) + describe('with success', () => { const now = new Date().toISOString() beforeEach(async () => { jest.clearAllMocks() - apolloMutationMock.mockResolvedValue({ - data: { - updateContribution: true, - }, - }) await wrapper .findComponent({ name: 'ContributionForm' }) .vm.$emit('update-contribution', { @@ -261,7 +371,7 @@ describe('Community', () => { }) it('calls the update contribution mutation', () => { - expect(apolloMutationMock).toBeCalledWith({ + expect(apolloMutateSpy).toBeCalledWith({ fetchPolicy: 'no-cache', mutation: updateContribution, variables: { @@ -278,40 +388,15 @@ describe('Community', () => { }) it('updates the contribution list', () => { - expect(apolloQueryMock).toBeCalledWith({ - fetchPolicy: 'no-cache', - query: listContributions, - variables: { - currentPage: 1, - pageSize: 25, - }, - }) + expect(refetchContributionsSpy).toBeCalled() }) - it('verifies the login (to get the new creations available)', () => { - expect(apolloRefetchMock).toBeCalled() - }) - }) - - describe('with error', () => { - const now = new Date().toISOString() - beforeEach(async () => { - jest.clearAllMocks() - apolloMutationMock.mockRejectedValue({ - message: 'Oh No!', - }) - await wrapper - .findComponent({ name: 'ContributionForm' }) - .vm.$emit('update-contribution', { - id: 2, - date: now, - memo: 'Mein Beitrag zur Gemeinschaft für diesen Monat ...', - amount: '400', - }) + it('updates the all contribution list', () => { + expect(refetchAllContributionsSpy).toBeCalled() }) - it('toasts the error message', () => { - expect(toastErrorSpy).toBeCalledWith('Oh No!') + it('updates the open creations', () => { + expect(refetchOpenCreationsSpy).toBeCalled() }) }) }) @@ -324,19 +409,25 @@ describe('Community', () => { contributionListComponent = await wrapper.findComponent({ name: 'ContributionList' }) }) - describe('with success', () => { + describe('with error', () => { beforeEach(async () => { jest.clearAllMocks() - apolloMutationMock.mockResolvedValue({ - data: { - deleteContribution: true, - }, - }) contributionListComponent.vm.$emit('delete-contribution', { id: 2 }) }) + it('toasts the error message', () => { + expect(toastErrorSpy).toBeCalledWith('Delete Contribution failed!') + }) + }) + + describe('with success', () => { + beforeEach(async () => { + jest.clearAllMocks() + await contributionListComponent.vm.$emit('delete-contribution', { id: 2 }) + }) + it('calls the API', () => { - expect(apolloMutationMock).toBeCalledWith({ + expect(apolloMutateSpy).toBeCalledWith({ fetchPolicy: 'no-cache', mutation: deleteContribution, variables: { @@ -350,32 +441,15 @@ describe('Community', () => { }) it('updates the contribution list', () => { - expect(apolloQueryMock).toBeCalledWith({ - fetchPolicy: 'no-cache', - query: listContributions, - variables: { - currentPage: 1, - pageSize: 25, - }, - }) + expect(refetchContributionsSpy).toBeCalled() }) - it('verifies the login (to get the new creations available)', () => { - expect(apolloRefetchMock).toBeCalled() - }) - }) - - describe('with error', () => { - beforeEach(async () => { - jest.clearAllMocks() - apolloMutationMock.mockRejectedValue({ - message: 'Oh my god!', - }) - contributionListComponent.vm.$emit('delete-contribution', { id: 2 }) + it('updates the all contribution list', () => { + expect(refetchAllContributionsSpy).toBeCalled() }) - it('toasts the error message', () => { - expect(toastErrorSpy).toBeCalledWith('Oh my god!') + it('updates the open creations', () => { + expect(refetchOpenCreationsSpy).toBeCalled() }) }) }) diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue index 13aad1a72..5bfa4f99a 100644 --- a/frontend/src/pages/Community.vue +++ b/frontend/src/pages/Community.vue @@ -10,7 +10,7 @@ />
item.state === 'IN_PROGRESS')) { + this.tabIndex = 1 + if (this.$route.hash !== '#my') { + this.$router.push({ path: '/community#my' }) + } + this.toastInfo('Du hast eine Rückfrage auf eine Contribution. Bitte beantworte diese!') + } + }, + error({ message }) { + this.toastError(message) + }, + }, }, watch: { $route(to, from) { @@ -160,7 +206,12 @@ export default { this.$root.$emit('bv::toggle::collapse', value.id) }) }, - setContribution(data) { + refetchData() { + this.$apollo.queries.ListAllContributions.refetch() + this.$apollo.queries.ListContributions.refetch() + this.$apollo.queries.OpenCreations.refetch() + }, + saveContribution(data) { this.$apollo .mutate({ fetchPolicy: 'no-cache', @@ -173,15 +224,7 @@ export default { }) .then((result) => { this.toastSuccess(this.$t('contribution.submitted')) - this.updateListContributions({ - currentPage: this.currentPage, - pageSize: this.pageSize, - }) - this.updateListAllContributions({ - currentPage: this.currentPage, - pageSize: this.pageSize, - }) - this.$apollo.queries.OpenCreations.refetch() + this.refetchData() }) .catch((err) => { this.toastError(err.message) @@ -201,15 +244,7 @@ export default { }) .then((result) => { this.toastSuccess(this.$t('contribution.updated')) - this.updateListContributions({ - currentPage: this.currentPage, - pageSize: this.pageSize, - }) - this.updateListAllContributions({ - currentPage: this.currentPage, - pageSize: this.pageSize, - }) - this.$apollo.queries.OpenCreations.refetch() + this.refetchData() }) .catch((err) => { this.toastError(err.message) @@ -226,68 +261,21 @@ export default { }) .then((result) => { this.toastSuccess(this.$t('contribution.deleted')) - this.updateListContributions({ - currentPage: this.currentPage, - pageSize: this.pageSize, - }) - this.updateListAllContributions({ - currentPage: this.currentPage, - pageSize: this.pageSize, - }) - this.$apollo.queries.OpenCreations.refetch() + this.refetchData() }) .catch((err) => { this.toastError(err.message) }) }, updateListAllContributions(pagination) { - this.$apollo - .query({ - fetchPolicy: 'no-cache', - query: listAllContributions, - variables: { - currentPage: pagination.currentPage, - pageSize: pagination.pageSize, - }, - }) - .then((result) => { - const { - data: { listAllContributions }, - } = result - this.contributionCountAll = listAllContributions.contributionCount - this.itemsAll = listAllContributions.contributionList - }) - .catch((err) => { - this.toastError(err.message) - }) + this.currentPageAll = pagination.currentPage + this.pageSizeAll = pagination.pageSize + this.$apollo.queries.ListAllContributions.refetch() }, updateListContributions(pagination) { - this.$apollo - .query({ - fetchPolicy: 'no-cache', - query: listContributions, - variables: { - currentPage: pagination.currentPage, - pageSize: pagination.pageSize, - }, - }) - .then((result) => { - const { - data: { listContributions }, - } = result - this.contributionCount = listContributions.contributionCount - this.items = listContributions.contributionList - if (this.items.find((item) => item.state === 'IN_PROGRESS')) { - this.tabIndex = 1 - if (this.$route.hash !== '#my') { - this.$router.push({ path: '/community#my' }) - } - this.toastInfo('Du hast eine Rückfrage auf eine Contribution. Bitte beantworte diese!') - } - }) - .catch((err) => { - this.toastError(err.message) - }) + this.currentPage = pagination.currentPage + this.pageSize = pagination.pageSize + this.$apollo.queries.ListContributions.refetch() }, updateContributionForm(item) { this.form.id = item.id @@ -306,16 +294,7 @@ export default { this.items.find((item) => item.id === id).state = 'PENDING' }, }, - created() { - this.updateListContributions({ - currentPage: this.currentPage, - pageSize: this.pageSize, - }) - this.updateListAllContributions({ - currentPage: this.currentPage, - pageSize: this.pageSize, - }) this.updateTransactions(0) this.tabIndex = 1 this.$router.push({ path: '/community#my' }) diff --git a/frontend/test/testSetup.js b/frontend/test/testSetup.js index 06e84b269..ffe4caf41 100644 --- a/frontend/test/testSetup.js +++ b/frontend/test/testSetup.js @@ -22,6 +22,7 @@ import { loadFilters } from '@/filters/amount' import { toasters } from '@/mixins/toaster' export const toastErrorSpy = jest.spyOn(toasters.methods, 'toastError') export const toastSuccessSpy = jest.spyOn(toasters.methods, 'toastSuccess') +export const toastInfoSpy = jest.spyOn(toasters.methods, 'toastInfo') Object.keys(rules).forEach((rule) => { extend(rule, { From a13c1a3cf52717224155cd3c5c0e362ce63ee493 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 19 Jan 2023 19:29:06 +0100 Subject: [PATCH 3/5] further tests --- frontend/src/pages/Community.spec.js | 52 ++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/Community.spec.js b/frontend/src/pages/Community.spec.js index 34fc3dba4..379994b73 100644 --- a/frontend/src/pages/Community.spec.js +++ b/frontend/src/pages/Community.spec.js @@ -406,7 +406,7 @@ describe('Community', () => { beforeEach(async () => { await wrapper.setData({ tabIndex: 1 }) - contributionListComponent = await wrapper.findComponent({ name: 'ContributionList' }) + contributionListComponent = wrapper.findComponent({ name: 'ContributionList' }) }) describe('with error', () => { @@ -454,7 +454,7 @@ describe('Community', () => { }) }) - describe.skip('update contribution form', () => { + describe('update contribution form', () => { const now = new Date().toISOString() beforeEach(async () => { await wrapper.setData({ tabIndex: 1 }) @@ -472,12 +472,58 @@ describe('Community', () => { expect(wrapper.vm.form.id).toBe(2) expect(wrapper.vm.form.date).toBe(now) expect(wrapper.vm.form.memo).toBe('Mein Beitrag zur Gemeinschaft für diesen Monat ...') - expect(wrapper.vm.form.amount).toBe('400') + expect(wrapper.vm.form.amount).toBe('400.00') }) it('sets tab index back to 0', () => { expect(wrapper.vm.tabIndex).toBe(0) }) }) + + describe('update list all contributions', () => { + beforeEach(async () => { + jest.clearAllMocks() + await wrapper.setData({ tabIndex: 2 }) + await wrapper + .findAllComponents({ name: 'ContributionList' }) + .at(1) + .vm.$emit('update-list-contributions', { + currentPage: 2, + pageSize: 5, + }) + }) + + it('updates page size and current page', () => { + expect(wrapper.vm.pageSizeAll).toBe(5) + expect(wrapper.vm.currentPageAll).toBe(2) + }) + + it('updates the all contribution list', () => { + expect(refetchAllContributionsSpy).toBeCalled() + }) + }) + + describe('update list contributions', () => { + beforeEach(async () => { + jest.clearAllMocks() + await wrapper.setData({ tabIndex: 1 }) + await wrapper + .findAllComponents({ name: 'ContributionList' }) + .at(0) + .vm.$emit('update-list-contributions', { + currentPage: 2, + pageSize: 5, + }) + }) + + it('updates page size and current page', () => { + expect(wrapper.vm.pageSize).toBe(5) + expect(wrapper.vm.currentPage).toBe(2) + }) + + it('updates the all contribution list', () => { + expect(refetchContributionsSpy).toBeCalled() + }) + }) }) }) From b997a34aaf64358233e42bfd457b9eec50f7fc1d Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 19 Jan 2023 19:32:11 +0100 Subject: [PATCH 4/5] coverage frontend to 95% --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index dfac48371..54653b831 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -437,7 +437,7 @@ jobs: report_name: Coverage Frontend type: lcov result_path: ./coverage/lcov.info - min_coverage: 93 + min_coverage: 95 token: ${{ github.token }} ############################################################################## From 3b9a553513515d7e4f713b5fb227e0568db790b9 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 20 Jan 2023 10:42:16 +0100 Subject: [PATCH 5/5] localized message --- frontend/src/pages/Community.spec.js | 4 +- frontend/src/pages/Community.vue | 502 +++++++++++++-------------- 2 files changed, 252 insertions(+), 254 deletions(-) diff --git a/frontend/src/pages/Community.spec.js b/frontend/src/pages/Community.spec.js index 2beec7571..ecfc01716 100644 --- a/frontend/src/pages/Community.spec.js +++ b/frontend/src/pages/Community.spec.js @@ -249,9 +249,7 @@ describe('Community', () => { }) it('toasts an info', () => { - expect(toastInfoSpy).toBeCalledWith( - 'contribution.alert.answerQuestionToast', - ) + expect(toastInfoSpy).toBeCalledWith('contribution.alert.answerQuestionToast') }) }) diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue index a17466840..5b771eac9 100644 --- a/frontend/src/pages/Community.vue +++ b/frontend/src/pages/Community.vue @@ -48,258 +48,258 @@