From a883052e03df1a2dc260d6924073b99f401b5cb8 Mon Sep 17 00:00:00 2001 From: Pavel Mineev Date: Sun, 22 Mar 2020 21:50:26 +0300 Subject: [PATCH] Fix saving of comment sorting * Add tests --- frontend/app/@types/global.d.ts | 8 ++++ frontend/app/common/fetcher.test.ts | 13 ------- frontend/app/store/comments/actions.test.ts | 31 +++++++++++++++ frontend/app/store/comments/actions.ts | 4 +- frontend/app/store/comments/utils.test.ts | 22 +++++++++++ frontend/app/store/comments/utils.ts | 3 +- frontend/app/testUtils/index.ts | 5 ++- frontend/app/testUtils/mockHeaders.ts | 43 +++++++++++---------- frontend/jest.config.js | 2 +- frontend/package-lock.json | 26 +++++++++++++ frontend/package.json | 1 + 11 files changed, 121 insertions(+), 37 deletions(-) create mode 100644 frontend/app/store/comments/actions.test.ts create mode 100644 frontend/app/store/comments/utils.test.ts diff --git a/frontend/app/@types/global.d.ts b/frontend/app/@types/global.d.ts index d891e2b8..77495f01 100644 --- a/frontend/app/@types/global.d.ts +++ b/frontend/app/@types/global.d.ts @@ -8,4 +8,12 @@ declare global { changeTheme(theme: Theme): void; }; } + + namespace NodeJS { + interface Global { + Headers: typeof Headers; + localStorage: typeof Storage; + fetch: typeof fetch; + } + } } diff --git a/frontend/app/common/fetcher.test.ts b/frontend/app/common/fetcher.test.ts index ca1fbdaa..f433f27a 100644 --- a/frontend/app/common/fetcher.test.ts +++ b/frontend/app/common/fetcher.test.ts @@ -1,19 +1,6 @@ import fetcher from './fetcher'; -import { mockHeaders } from '@app/testUtils/mockHeaders'; describe('fetcher', () => { - beforeAll(() => { - mockHeaders.mock(); - }); - - afterAll(() => { - mockHeaders.restore(); - }); - - afterEach(() => { - (window.fetch as any).mockRestore(); - }); - describe('errors', () => { it('should throw json on api json response with >= 400 status code', async () => { const response = { diff --git a/frontend/app/store/comments/actions.test.ts b/frontend/app/store/comments/actions.test.ts new file mode 100644 index 00000000..06c11619 --- /dev/null +++ b/frontend/app/store/comments/actions.test.ts @@ -0,0 +1,31 @@ +import { mockStore } from '@app/testUtils/mockStore'; + +import { updateSorting } from './actions'; +import { COMMENTS_SET_SORT } from './types'; +import { LS_SORT_KEY } from '@app/common/constants'; + +describe('Store comments actions', () => { + beforeAll(() => { + require('jest-fetch-mock').enableMocks(); + }); + afterAll(() => { + require('jest-fetch-mock').resetMocks(); + }); + + it('handles changing a purchase status and fetches all purchases', async () => { + const newSort = '+controversy'; + const store = mockStore({ + comments: { + sort: '+active', + }, + hiddenUsers: {}, + }); + + await store.dispatch(updateSorting(newSort)); + + const [setCommentAction] = store.getActions(); + + expect(setCommentAction).toEqual({ type: COMMENTS_SET_SORT, payload: newSort }); + expect(localStorage.setItem).toHaveBeenCalledWith(LS_SORT_KEY, newSort); + }); +}); diff --git a/frontend/app/store/comments/actions.ts b/frontend/app/store/comments/actions.ts index 93f77b9f..e7f0349b 100644 --- a/frontend/app/store/comments/actions.ts +++ b/frontend/app/store/comments/actions.ts @@ -14,6 +14,8 @@ import { COMMENTS_REQUEST_FETCHING, COMMENTS_REQUEST_SUCCESS, } from './types'; +import { setItem } from '@app/common/local-storage'; +import { LS_SORT_KEY } from '@app/common/constants'; /** sets comments, and put pinned comments in cache */ export const setComments = (comments: Node[]): StoreAction => dispatch => { @@ -111,11 +113,11 @@ export function unsetCommentMode(mode: StoreState['comments']['activeComment'] = export function updateSorting(sort: Sorting): StoreAction { return async (dispath, getState) => { const { sort: prevSort } = getState().comments; - dispath({ type: COMMENTS_REQUEST_FETCHING }); dispath({ type: COMMENTS_SET_SORT, payload: sort }); try { await dispath(fetchComments(sort)); + setItem(LS_SORT_KEY, sort); } catch (e) { dispath({ type: COMMENTS_SET_SORT, payload: prevSort }); } diff --git a/frontend/app/store/comments/utils.test.ts b/frontend/app/store/comments/utils.test.ts new file mode 100644 index 00000000..28441b9d --- /dev/null +++ b/frontend/app/store/comments/utils.test.ts @@ -0,0 +1,22 @@ +import { getInitialSort } from './utils'; +import { DEFAULT_SORT, LS_SORT_KEY } from '@app/common/constants'; + +describe('store comments utils', () => { + beforeEach(() => { + localStorage.clear(); + }); + + describe('getInitialSort', () => { + it('should return default sorting', () => { + expect(getInitialSort()).toBe(DEFAULT_SORT); + }); + + it('should return value from local storage', () => { + const currentSort = '+active'; + + localStorage.setItem(LS_SORT_KEY, currentSort); + expect(getInitialSort()).toBe(currentSort); + expect(localStorage.getItem).toHaveBeenCalledWith(LS_SORT_KEY); + }); + }); +}); diff --git a/frontend/app/store/comments/utils.ts b/frontend/app/store/comments/utils.ts index 770c59ef..bb4bec81 100644 --- a/frontend/app/store/comments/utils.ts +++ b/frontend/app/store/comments/utils.ts @@ -1,5 +1,6 @@ import { Comment, Node, Sorting } from '@app/common/types'; import { LS_SORT_KEY, DEFAULT_SORT } from '@app/common/constants'; +import { getItem } from '@app/common/local-storage'; /** * Filters tree node @@ -43,7 +44,7 @@ export function getPinnedComments(threads: Node[]): Comment[] { } export function getInitialSort() { - const sort = localStorage.getItem(LS_SORT_KEY) as Sorting; + const sort = getItem(LS_SORT_KEY) as Sorting; if (sort) { return sort; diff --git a/frontend/app/testUtils/index.ts b/frontend/app/testUtils/index.ts index 22e7baa4..ba6d34bb 100644 --- a/frontend/app/testUtils/index.ts +++ b/frontend/app/testUtils/index.ts @@ -1,9 +1,12 @@ import 'jest-extended'; import 'jest-enzyme'; -import { StaticStore } from '@app/common/static_store'; import { configure } from 'enzyme'; import PreactAdapter from 'enzyme-adapter-preact-pure'; +import { StaticStore } from '@app/common/static_store'; + +import './mockHeaders'; + configure({ adapter: new PreactAdapter() }); require('document-register-element/pony')(window); diff --git a/frontend/app/testUtils/mockHeaders.ts b/frontend/app/testUtils/mockHeaders.ts index 047f5496..52a9873c 100644 --- a/frontend/app/testUtils/mockHeaders.ts +++ b/frontend/app/testUtils/mockHeaders.ts @@ -1,22 +1,25 @@ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const originalHeaders = (window as any).Headers; +global.Headers = class HeadersMock implements Headers { + private headers = new Map(); -export const mockHeaders = { - mock: () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (window as any).Headers = class { - // eslint-disable-next-line @typescript-eslint/no-empty-function - append() {} - has() { - return false; - } - get() { - return null; - } - }; - }, - restore: () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (window as any).Headers = originalHeaders; - }, + append(key: string, value: string) { + this.headers.set(key, value); + } + set(key: string, value: string) { + this.headers.set(key, value); + } + has(key: string) { + return this.headers.has(key); + } + get(key: string) { + return this.headers.get(key) || null; + } + delete(key: string) { + this.headers.delete(key); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + forEach(callbackfn: (value: string, key: string, parent: Headers) => void, thisArg?: any) { + this.headers.forEach((value, key) => { + callbackfn.call(thisArg || this, value, key, this); + }); + } }; diff --git a/frontend/jest.config.js b/frontend/jest.config.js index c1e3eaca..39360dc5 100644 --- a/frontend/jest.config.js +++ b/frontend/jest.config.js @@ -15,6 +15,6 @@ module.exports = { '^react$': 'preact/compat', '^react-dom$': 'preact/compat', }, - setupFilesAfterEnv: ['/app/testUtils/index.ts'], + setupFilesAfterEnv: ['/app/testUtils/index.ts', 'jest-localstorage-mock'], transformIgnorePatterns: ['/node_modules/(?!intl-messageformat|intl-messageformat-parser).+\\.js$'], }; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 26b8a0db..e48d8caf 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -6676,6 +6676,16 @@ "sha.js": "^2.4.8" } }, + "cross-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.4.tgz", + "integrity": "sha512-MSHgpjQqgbT/94D4CyADeNoYh52zMkCX4pcJvPP5WqPsLFMKjr2TCMg381ox5qI0ii2dPwaLx/00477knXqXVw==", + "dev": true, + "requires": { + "node-fetch": "2.6.0", + "whatwg-fetch": "3.0.0" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -13436,6 +13446,16 @@ } } }, + "jest-fetch-mock": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz", + "integrity": "sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==", + "dev": true, + "requires": { + "cross-fetch": "^3.0.4", + "promise-polyfill": "^8.1.3" + } + }, "jest-get-type": { "version": "24.8.0", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.8.0.tgz", @@ -20745,6 +20765,12 @@ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", "dev": true }, + "promise-polyfill": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.3.tgz", + "integrity": "sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g==", + "dev": true + }, "prompts": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 125061f9..3e15122d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -69,6 +69,7 @@ "jest": "^25.1.0", "jest-enzyme": "^7.1.2", "jest-extended": "^0.11.2", + "jest-fetch-mock": "^3.0.3", "jest-localstorage-mock": "^2.4.0", "lint-staged": "^9.4.2", "mini-css-extract-plugin": "^0.8.0",