From 58bfc0351be946a0e0bb034a241dc2d293199f79 Mon Sep 17 00:00:00 2001 From: Drew Delianides Date: Wed, 21 Dec 2016 20:37:44 -0500 Subject: [PATCH] Studies Tests (#1680) * nearly done studies addition [ci skip] * fix tests and lints for studies * project adjustments for testing * added studies changes * fix failing ci test * add aphrodite reset to slider test * add in more aphrodite stuff * sheesh, add it to all new tests? --- .gitignore | 1 + .meteor/mocks/mongo.js | 6 + imports/pages/studies/EntryList.js | 2 +- imports/pages/studies/__tests__/EntryList.js | 91 ++++ .../pages/studies/__tests__/EntryListItem.js | 48 ++ imports/pages/studies/__tests__/Hero.js | 36 ++ imports/pages/studies/__tests__/Single.js | 113 +++++ .../__tests__/__snapshots__/EntryList.js.snap | 411 ++++++++++++++++ .../__snapshots__/EntryListItem.js.snap | 38 ++ .../__tests__/__snapshots__/Hero.js.snap | 26 + .../__tests__/__snapshots__/Single.js.snap | 101 ++++ .../__tests__/__snapshots__/index.js.snap | 454 ++++++++++++++++++ imports/pages/studies/__tests__/index.js | 118 +++++ .../pages/studies/entry/__tests__/Content.js | 125 +++++ .../studies/entry/__tests__/ScriptureItem.js | 48 ++ .../entry/__tests__/ScriptureWrapper.js | 54 +++ .../pages/studies/entry/__tests__/Slider.js | 51 ++ .../__tests__/__snapshots__/Content.js.snap | 136 ++++++ .../__snapshots__/ScriptureItem.js.snap | 37 ++ .../__snapshots__/ScriptureWrapper.js.snap | 29 ++ .../__tests__/__snapshots__/Slider.js.snap | 59 +++ .../__tests__/__snapshots__/index.js.snap | 42 ++ .../pages/studies/entry/__tests__/index.js | 245 ++++++++++ imports/pages/studies/entry/index.js | 2 + imports/store/header/saga.js | 1 + 25 files changed, 2273 insertions(+), 1 deletion(-) create mode 100644 .meteor/mocks/mongo.js create mode 100644 imports/pages/studies/__tests__/EntryList.js create mode 100644 imports/pages/studies/__tests__/EntryListItem.js create mode 100644 imports/pages/studies/__tests__/Hero.js create mode 100644 imports/pages/studies/__tests__/Single.js create mode 100644 imports/pages/studies/__tests__/__snapshots__/EntryList.js.snap create mode 100644 imports/pages/studies/__tests__/__snapshots__/EntryListItem.js.snap create mode 100644 imports/pages/studies/__tests__/__snapshots__/Hero.js.snap create mode 100644 imports/pages/studies/__tests__/__snapshots__/Single.js.snap create mode 100644 imports/pages/studies/__tests__/__snapshots__/index.js.snap create mode 100644 imports/pages/studies/__tests__/index.js create mode 100644 imports/pages/studies/entry/__tests__/Content.js create mode 100644 imports/pages/studies/entry/__tests__/ScriptureItem.js create mode 100644 imports/pages/studies/entry/__tests__/ScriptureWrapper.js create mode 100644 imports/pages/studies/entry/__tests__/Slider.js create mode 100644 imports/pages/studies/entry/__tests__/__snapshots__/Content.js.snap create mode 100644 imports/pages/studies/entry/__tests__/__snapshots__/ScriptureItem.js.snap create mode 100644 imports/pages/studies/entry/__tests__/__snapshots__/ScriptureWrapper.js.snap create mode 100644 imports/pages/studies/entry/__tests__/__snapshots__/Slider.js.snap create mode 100644 imports/pages/studies/entry/__tests__/__snapshots__/index.js.snap create mode 100644 imports/pages/studies/entry/__tests__/index.js diff --git a/.gitignore b/.gitignore index 39ffc20cf..17c517ffa 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,4 @@ docs # editor files .vscode +.tsconfig diff --git a/.meteor/mocks/mongo.js b/.meteor/mocks/mongo.js new file mode 100644 index 000000000..af6d240e0 --- /dev/null +++ b/.meteor/mocks/mongo.js @@ -0,0 +1,6 @@ + +export const DDP = { + _CurrentInvocation: { + get: jest.fn(() => {}), + }, +} diff --git a/imports/pages/studies/EntryList.js b/imports/pages/studies/EntryList.js index fb08725f4..b25973464 100644 --- a/imports/pages/studies/EntryList.js +++ b/imports/pages/studies/EntryList.js @@ -98,7 +98,7 @@ class StudyEntryWithoutData extends Component { } const STUDY_ENTRY_QUERY = gql` - query GetEntriesFromSeries($id: ID!) { + query GetEntriesFromStudy($id: ID!) { content: node(id: $id) { ... on Content { studyEntries: children(channels: ["study_entries"]) { diff --git a/imports/pages/studies/__tests__/EntryList.js b/imports/pages/studies/__tests__/EntryList.js new file mode 100644 index 000000000..5ac5cc49d --- /dev/null +++ b/imports/pages/studies/__tests__/EntryList.js @@ -0,0 +1,91 @@ +/* eslint-disable */ +import renderer from "react-test-renderer"; +import { shallow } from "enzyme"; +import { shallowToJson } from "enzyme-to-json"; +import { reset, startBuffering } from "aphrodite/lib/inject"; + +beforeEach(() => { + reset(); + startBuffering(); +}); + +afterEach(() => { + reset(); +}); + +import { + StudyEntryWithoutData as StudyEntry, + STUDY_ENTRY_QUERY, +} from "../EntryList"; + +const defaultProps = { + studyEntries: { + loading: false, + content: { + studyEntries: [ + { + title: "Study Entry" + }, + ], + }, + }, + light: true, + focus: "1" +}; + +const generateComponent = (additionalProps = {}) => { + const newProps = { + ...defaultProps, + ...additionalProps, + }; + + return ; +}; + +it("parses study entry query", () => { + expect(STUDY_ENTRY_QUERY).toMatchSnapshot(); +}); + +it("renders with props", () => { + const tree = renderer.create(generateComponent()); + expect(tree).toMatchSnapshot(); +}); + +it("returns null if there is no studyEntries", () => { + const tree = renderer.create(generateComponent({ + studyEntries: { + content: { + studyEntries: [], + } + }, + })); + expect(tree).toMatchSnapshot(); +}); + +it("has a loading state", () => { + const tree = renderer.create(generateComponent({ + studyEntries: { + loading: true + }, + })); + expect(tree).toMatchSnapshot(); +}) + +it("calculates width based on window size", () => { + const wrapper = shallow(generateComponent()); + const result = wrapper.instance().dynamicWidth(); + expect(result).toEqual({ width: "847.2px" }); +}); + +it("calculates tablet version", () => { + window.isTablet = true; + const wrapper = shallow(generateComponent()); + const result = wrapper.instance().dynamicWidth(); + expect(result).toEqual({ width: "429px" }); +}); + +it("overflow contains css object", () => { + const wrapper = shallow(generateComponent()); + const result = wrapper.instance().overflow; + expect(result).toMatchSnapshot(); +}); diff --git a/imports/pages/studies/__tests__/EntryListItem.js b/imports/pages/studies/__tests__/EntryListItem.js new file mode 100644 index 000000000..eb35829b0 --- /dev/null +++ b/imports/pages/studies/__tests__/EntryListItem.js @@ -0,0 +1,48 @@ +/* eslint-disable */ +import renderer from "react-test-renderer"; +import { reset, startBuffering } from "aphrodite/lib/inject"; + +import StudiesEntryListItem from "../EntryListItem"; + +beforeEach(() => { + reset(); + startBuffering(); +}); + +afterEach(() => { + reset(); +}); + +describe("StudiesEntryListItem", () => { + it("takes a single study as a prop", () => { + const study = { + "id": "e2a6f1a585c90a33b88f8e41b26c9ffe", + "entryId": "e2a6f1a585c90a33b88f8e41b26c9ffe", + "title": "Who are you trying to please?", + "status": "open", + "channelName": "study_entries", + "parent": { + "entryId": "9bff3ab47f41d1818fa3dc2803fa141b" + }, + "meta": { + "urlTitle": "who-are-you-trying-to-please", + "siteId": "393ebdf414cdf68c96bb7fd149f7a434", + "date": "Wed Dec 07 2016 00:00:00 GMT+0000 (UTC)", + "channelId": "d89926c004a563d46e0d10ca1a5fea53" + }, + "content": { + "speaker": "" + } + }; + + const tree = renderer.create( + + ); + + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/imports/pages/studies/__tests__/Hero.js b/imports/pages/studies/__tests__/Hero.js new file mode 100644 index 000000000..b92d7adca --- /dev/null +++ b/imports/pages/studies/__tests__/Hero.js @@ -0,0 +1,36 @@ +/* eslint-disable */ +import renderer from "react-test-renderer"; +import { reset, startBuffering } from "aphrodite/lib/inject"; + +import StudyHero from "../Hero"; + +beforeEach(() => { + reset(); + startBuffering(); +}); + +afterEach(() => { + reset(); +}); + +describe("StudyHero", () => { + it("changes class name based on props", () => { + const study = { + "content": { + "isLight": true, + "images":[ + { "url": "http://exampleimage.org" } + ] + } + }; + + const tree = renderer.create( + + ); + + expect(tree).toMatchSnapshot(); + }); +}) + + + diff --git a/imports/pages/studies/__tests__/Single.js b/imports/pages/studies/__tests__/Single.js new file mode 100644 index 000000000..a824a24ba --- /dev/null +++ b/imports/pages/studies/__tests__/Single.js @@ -0,0 +1,113 @@ +/* eslint-disable */ +import renderer from "react-test-renderer"; +import { shallow, mount } from "enzyme"; +import { reset, startBuffering } from "aphrodite/lib/inject"; + +import { StudiesSingleWithoutData } from "../Single"; +import { + nav as navActions, +} from "../../../store"; +import headerActions from "../../../store/header"; + +jest.mock("../../../database/collections/likes", () => {}); +jest.mock("../../../blocks/related-content"); + +jest.mock("../../../mixins/mixins.Shareable"); +jest.mock("../../../mixins/mixins.Header"); + +jest.mock("../EntryList"); +jest.mock("../Hero"); + +jest.mock("../../../store/header", () => ({ + set: jest.fn(), +})); + +jest.mock("../../../store", () => ({ + nav: { + setLevel: jest.fn(), + setAction: jest.fn(), + }, +})); + +const defaultProps = { + dispatch: jest.fn(), + params: { + id: "1", + }, + study: { + content: { + id: "1", + content: { + description: "

study

", + images: [], + }, + }, + }, +}; + +beforeEach(() => { + reset(); + startBuffering(); +}); + +afterEach(() => { + reset(); +}); + +const generateComponent = (additionalProps = {}) => { + const newProps = { + ...defaultProps, + ...additionalProps, + }; + + return ; +}; + +it("renders with no image", () => { + const tree = renderer.create(generateComponent()); + expect(tree).toMatchSnapshot(); +}); + +it("renders loading with no study", () => { + const tree = renderer.create(generateComponent({ + study: {} + })); + expect(tree).toMatchSnapshot(); +}); + +it("renders studies content", () => { + const tree = renderer.create(generateComponent({ + study: { + content: { + id: "1", + content: { + description: "

study

", + images: [ + { fileLabel: "1:1", url: "http://test.com/1x1.jpg" }, + ], + }, + }, + } + })); + + expect(tree).toMatchSnapshot(); +}); + +it("dispatches store on mount", () => { + const mockDispatch = jest.fn(); + + navActions.setLevel = jest.fn(); + navActions.setAction = jest.fn(); + headerActions.set = jest.fn(); + + const wrapper = shallow(generateComponent({ + dispatch: mockDispatch, + })); + + expect(mockDispatch).toHaveBeenCalledTimes(3); + expect(navActions.setLevel).toHaveBeenCalledTimes(1); + expect(navActions.setLevel).toHaveBeenCalledWith("CONTENT"); + expect(navActions.setAction).toHaveBeenCalledTimes(1); + expect(navActions.setAction.mock.calls[0][0]).toBe("CONTENT"); + expect(headerActions.set).toHaveBeenCalledTimes(1); +}); diff --git a/imports/pages/studies/__tests__/__snapshots__/EntryList.js.snap b/imports/pages/studies/__tests__/__snapshots__/EntryList.js.snap new file mode 100644 index 000000000..0e52052fc --- /dev/null +++ b/imports/pages/studies/__tests__/__snapshots__/EntryList.js.snap @@ -0,0 +1,411 @@ +exports[`test has a loading state 1`] = ` +
+
+
+`; + +exports[`test overflow contains css object 1`] = ` +Object { + "WebkitOverflowScrolling": "touch", + "overflowX": "scroll", + "overflowY": "hidden", + "paddingLeft": "20px", +} +`; + +exports[`test parses study entry query 1`] = ` +Object { + "definitions": Array [ + Object { + "directives": Array [], + "kind": "OperationDefinition", + "name": Object { + "kind": "Name", + "value": "GetEntriesFromStudy", + }, + "operation": "query", + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": Object { + "kind": "Name", + "value": "content", + }, + "arguments": Array [ + Object { + "kind": "Argument", + "name": Object { + "kind": "Name", + "value": "id", + }, + "value": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "id", + }, + }, + }, + ], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "node", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "directives": Array [], + "kind": "InlineFragment", + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": Object { + "kind": "Name", + "value": "studyEntries", + }, + "arguments": Array [ + Object { + "kind": "Argument", + "name": Object { + "kind": "Name", + "value": "channels", + }, + "value": Object { + "kind": "ListValue", + "values": Array [ + Object { + "kind": "StringValue", + "value": "study_entries", + }, + ], + }, + }, + ], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "children", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "id", + }, + "selectionSet": null, + }, + Object { + "alias": Object { + "kind": "Name", + "value": "entryId", + }, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "id", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "title", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "status", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "channelName", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "parent", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": Object { + "kind": "Name", + "value": "entryId", + }, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "id", + }, + "selectionSet": null, + }, + ], + }, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "meta", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "urlTitle", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "siteId", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "date", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "channelId", + }, + "selectionSet": null, + }, + ], + }, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "content", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "speaker", + }, + "selectionSet": null, + }, + ], + }, + }, + ], + }, + }, + ], + }, + "typeCondition": Object { + "kind": "NamedType", + "name": Object { + "kind": "Name", + "value": "Content", + }, + }, + }, + ], + }, + }, + ], + }, + "variableDefinitions": Array [ + Object { + "defaultValue": null, + "kind": "VariableDefinition", + "type": Object { + "kind": "NonNullType", + "type": Object { + "kind": "NamedType", + "name": Object { + "kind": "Name", + "value": "ID", + }, + }, + }, + "variable": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "id", + }, + }, + }, + ], + }, + ], + "kind": "Document", + "loc": Object { + "end": 488, + "source": Source { + "body": " + query GetEntriesFromStudy($id: ID!) { + content: node(id: $id) { + ... on Content { + studyEntries: children(channels: [\"study_entries\"]) { + id + entryId: id + title + status + channelName + parent { + entryId: id + } + meta { + urlTitle + siteId + date + channelId + } + content { + speaker + } + } + } + } + } +", + "name": "GraphQL", + }, + "start": 3, + }, +} +`; + +exports[`test renders with props 1`] = ` + +`; + +exports[`test returns null if there is no studyEntries 1`] = `null`; diff --git a/imports/pages/studies/__tests__/__snapshots__/EntryListItem.js.snap b/imports/pages/studies/__tests__/__snapshots__/EntryListItem.js.snap new file mode 100644 index 000000000..58f0f9c0c --- /dev/null +++ b/imports/pages/studies/__tests__/__snapshots__/EntryListItem.js.snap @@ -0,0 +1,38 @@ +exports[`StudiesEntryListItem takes a single study as a prop 1`] = ` + +
+
+
+ 2 +
+
+

+ Who are you trying to please? +

+
+
+`; diff --git a/imports/pages/studies/__tests__/__snapshots__/Hero.js.snap b/imports/pages/studies/__tests__/__snapshots__/Hero.js.snap new file mode 100644 index 000000000..bd93f33cf --- /dev/null +++ b/imports/pages/studies/__tests__/__snapshots__/Hero.js.snap @@ -0,0 +1,26 @@ +exports[`StudyHero changes class name based on props 1`] = ` +
+
+
+
+
+
+
+
+`; diff --git a/imports/pages/studies/__tests__/__snapshots__/Single.js.snap b/imports/pages/studies/__tests__/__snapshots__/Single.js.snap new file mode 100644 index 000000000..fd79e283c --- /dev/null +++ b/imports/pages/studies/__tests__/__snapshots__/Single.js.snap @@ -0,0 +1,101 @@ +exports[`test renders loading with no study 1`] = ` +
+
+
+
+
+`; + +exports[`test renders studies content 1`] = ` +
+
+
+ + +
+
study", + } + } /> +
+
+
+`; + +exports[`test renders with no image 1`] = ` +
+
+
+ + +
+
study", + } + } /> +
+
+
+`; diff --git a/imports/pages/studies/__tests__/__snapshots__/index.js.snap b/imports/pages/studies/__tests__/__snapshots__/index.js.snap new file mode 100644 index 000000000..b7ff53e3e --- /dev/null +++ b/imports/pages/studies/__tests__/__snapshots__/index.js.snap @@ -0,0 +1,454 @@ +exports[`test parses series query 1`] = ` +Object { + "definitions": Array [ + Object { + "directives": Array [], + "kind": "OperationDefinition", + "name": Object { + "kind": "Name", + "value": "getSeries", + }, + "operation": "query", + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": null, + "arguments": Array [ + Object { + "kind": "Argument", + "name": Object { + "kind": "Name", + "value": "channel", + }, + "value": Object { + "kind": "StringValue", + "value": "studies", + }, + }, + Object { + "kind": "Argument", + "name": Object { + "kind": "Name", + "value": "limit", + }, + "value": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "limit", + }, + }, + }, + Object { + "kind": "Argument", + "name": Object { + "kind": "Name", + "value": "skip", + }, + "value": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "skip", + }, + }, + }, + ], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "content", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "id", + }, + "selectionSet": null, + }, + Object { + "alias": Object { + "kind": "Name", + "value": "entryId", + }, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "id", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "title", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "status", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "channelName", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "meta", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "urlTitle", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "siteId", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "date", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "channelId", + }, + "selectionSet": null, + }, + ], + }, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "content", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": null, + "arguments": Array [ + Object { + "kind": "Argument", + "name": Object { + "kind": "Name", + "value": "sizes", + }, + "value": Object { + "kind": "ListValue", + "values": Array [ + Object { + "kind": "StringValue", + "value": "large", + }, + ], + }, + }, + ], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "images", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "fileName", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "fileType", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "fileLabel", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "url", + }, + "selectionSet": null, + }, + ], + }, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "isLight", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "colors", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "id", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "value", + }, + "selectionSet": null, + }, + Object { + "alias": null, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "description", + }, + "selectionSet": null, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + "variableDefinitions": Array [ + Object { + "defaultValue": null, + "kind": "VariableDefinition", + "type": Object { + "kind": "NonNullType", + "type": Object { + "kind": "NamedType", + "name": Object { + "kind": "Name", + "value": "Int", + }, + }, + }, + "variable": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "limit", + }, + }, + }, + Object { + "defaultValue": null, + "kind": "VariableDefinition", + "type": Object { + "kind": "NonNullType", + "type": Object { + "kind": "NamedType", + "name": Object { + "kind": "Name", + "value": "Int", + }, + }, + }, + "variable": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "skip", + }, + }, + }, + ], + }, + ], + "kind": "Document", + "loc": Object { + "end": 508, + "source": Source { + "body": " + query getSeries($limit: Int!, $skip: Int!){ + content(channel: \"studies\", limit: $limit, skip: $skip) { + id + entryId: id + title + status + channelName + meta { + urlTitle + siteId + date + channelId + } + content { + images(sizes: [\"large\"]) { + fileName + fileType + fileLabel + url + } + isLight + colors { + id + value + description + } + } + } + } +", + "name": "GraphQL", + }, + "start": 3, + }, +} +`; + +exports[`test renders loading if no content 1`] = ` + +`; + +exports[`test renders with props 1`] = ` + +`; diff --git a/imports/pages/studies/__tests__/index.js b/imports/pages/studies/__tests__/index.js new file mode 100644 index 000000000..eb513f102 --- /dev/null +++ b/imports/pages/studies/__tests__/index.js @@ -0,0 +1,118 @@ +/* eslint-disable */ +import { shallow, mount } from "enzyme"; +import { shallowToJson } from "enzyme-to-json"; +import { reset, startBuffering } from "aphrodite/lib/inject"; + +import { + TemplateWithoutData as Studies, + SERIES_QUERY, +} from "../index"; + +import { + nav as navActions, +} from "../../../store"; + +beforeEach(() => { + reset(); + startBuffering(); +}); + +afterEach(() => { + reset(); +}); + +jest.mock("../../../mixins/mixins.Likeable", () => {}); +jest.mock("../../../mixins/mixins.Header", () => {}); + +jest.mock("../../../store", () => ({ + nav: { + setLevel: jest.fn(), + }, +})); + +const defaultProps = { + dispatch: jest.fn(), + data: { + loading: false, + refetch: jest.fn(), + content: [{}, {}], + }, + Loading: jest.fn(), +}; + +const mockHeaderAction = jest.fn(); +const MockHeaderAction = (Component) => ( + class MockHeaderAction extends React.Component { + constructor () { + super(...arguments); + this.headerAction = mockHeaderAction; + } + render() { + return + } + } +); + +const generateMockedComponent = (additionalProps = {}) => { + const newProps = { + ...defaultProps, + ...additionalProps, + }; + const MockedStudies = MockHeaderAction(Studies); + return ; +}; + +const generateComponent = (additionalProps = {}) => { + const newProps = { + ...defaultProps, + ...additionalProps, + }; + + return ; +}; + +it("parses series query", () => { + expect(SERIES_QUERY).toMatchSnapshot(); +}); + +it("renders with props", () => { + const wrapper = shallow(generateMockedComponent()); + expect(shallowToJson(wrapper)).toMatchSnapshot(); +}); + +it("renders loading if no content", () => { + const wrapper = shallow(generateMockedComponent({ + data: { + loading: false, + refetch: jest.fn(), + content: [], + }, + })); + expect(shallowToJson(wrapper)).toMatchSnapshot(); +}); + +it("updates the nav and header on mount", () => { + const mockDispatch = jest.fn(); + navActions.setLevel = jest.fn(); + const wrapper = shallow(generateComponent({ + dispatch: mockDispatch, + })); + expect(mockDispatch).toHaveBeenCalledTimes(1); + expect(navActions.setLevel).toHaveBeenCalledTimes(1); + expect(navActions.setLevel).toHaveBeenCalledWith("TOP"); +}); + +it("handleRefresh calls refetch", () => { + const mockRefetch = jest.fn().mockReturnValue(new Promise((r) => r())); + const wrapper = shallow(generateComponent({ + data: { + loading: false, + refetch: mockRefetch, + content: [{}, {}], + }, + })); + wrapper.instance().handleRefresh(jest.fn(), jest.fn()); + expect(mockRefetch).toHaveBeenCalledTimes(1); +}); + + diff --git a/imports/pages/studies/entry/__tests__/Content.js b/imports/pages/studies/entry/__tests__/Content.js new file mode 100644 index 000000000..931d1ad18 --- /dev/null +++ b/imports/pages/studies/entry/__tests__/Content.js @@ -0,0 +1,125 @@ +/* eslint-disable */ +import renderer from "react-test-renderer"; +import { shallowToJson, mountToJson } from "enzyme-to-json"; +import { reset, startBuffering } from "aphrodite/lib/inject"; + +import Content from "../Content"; + +beforeEach(() => { + reset(); + startBuffering(); +}); + +afterEach(() => { + reset(); +}); + + + +jest.mock("../../../../blocks/related-content"); +jest.mock("../../../../components/players/video"); + +const defaultProps = { + studyEntry: { + content: { + ooyalaId: null, + images: [], + body: "

study body

", + }, + }, + classes: [], + onClickLink: jest.fn(), +}; + +const generateComponent = (additionalProps = {}) => { + const newProps = { + ...defaultProps, + ...additionalProps, + }; + + return ; +}; + +it("renders with props", () => { + const tree = renderer.create(generateComponent()); + expect(tree).toMatchSnapshot(); +}); + +it("renders with an image and no video", () => { + const tree = renderer.create(generateComponent({ + studyEntry:{ + content: { + images: [ + { + "fileName": "Galatiansstudy2x1.png", + "fileType": null, + "fileLabel": "2:1", + "url": "//drhztd8q3iayu.cloudfront.net/newspring/collection/studies/Galatiansstudy2x1.large.png", + "size": "large" + }, + ], + }, + }, + })); + expect(tree).toMatchSnapshot(); +}); + +it("renders with an ooyala video", () => { + const tree = renderer.create(generateComponent({ + studyEntry: { + content: { + ooyalaId: "fake-ooyala-Id", + } + }, + })); + expect(tree).toMatchSnapshot(); +}); + +it("renders with scripture", () => { + const tree = renderer.create(generateComponent({ + studyEntry: { + content: { + images: [ + { + "fileName": "Galatiansstudy2x1.png", + "fileType": null, + "fileLabel": "2:1", + "url": "//drhztd8q3iayu.cloudfront.net/newspring/collection/studies/Galatiansstudy2x1.large.png", + "size": "large" + }, + ], + scripture: [ + { + "book": "Galatians", + "passage": "2:11-21", + }, + ], + }, + }, + })); + expect(tree).toMatchSnapshot(); +}); + +it("renders with related content", () => { + const tree = renderer.create(generateComponent({ + studyEntry: { + content: { + images: [ + { + "fileName": "Galatiansstudy2x1.png", + "fileType": null, + "fileLabel": "2:1", + "url": "//drhztd8q3iayu.cloudfront.net/newspring/collection/studies/Galatiansstudy2x1.large.png", + "size": "large" + }, + ], + tags: [ + "grace", + "love", + "salvation" + ], + } + } + })); + expect(tree).toMatchSnapshot(); +}); diff --git a/imports/pages/studies/entry/__tests__/ScriptureItem.js b/imports/pages/studies/entry/__tests__/ScriptureItem.js new file mode 100644 index 000000000..78bce871c --- /dev/null +++ b/imports/pages/studies/entry/__tests__/ScriptureItem.js @@ -0,0 +1,48 @@ +/* eslint-disable */ +import { shallow } from "enzyme"; +import { shallowToJson } from "enzyme-to-json"; +import { Meteor } from "meteor/meteor"; + +import { reset, startBuffering } from "aphrodite/lib/inject"; + +import ScriptureItem from "../ScriptureItem"; + +beforeEach(() => { + reset(); + startBuffering(); +}); + +afterEach(() => { + reset(); +}); + +const defaultProps = { + scripture: "Job 2", +}; + +const generateComponent = () => ( + +); + +it("renders loading without scriptureData", () => { + Meteor.call = jest.fn(); + const wrapper = shallow(generateComponent()); + expect(shallowToJson(wrapper)).toMatchSnapshot(); +}); + +it("calls getScripture meteor method", () => { + Meteor.call = jest.fn(); + const wrapper = shallow(generateComponent()); + expect(Meteor.call).toHaveBeenCalledTimes(1); + expect(Meteor.call.mock.calls[0][0]).toBe("getScripture"); + expect(Meteor.call.mock.calls[0][1]).toBe(defaultProps.scripture); +}); + +it("renders scripture when state updated", () => { + Meteor.call = jest.fn(); + const wrapper = shallow(generateComponent()); + wrapper.setState({ + scriptureData: "

scipture

", + }); + expect(shallowToJson(wrapper)).toMatchSnapshot(); +}); diff --git a/imports/pages/studies/entry/__tests__/ScriptureWrapper.js b/imports/pages/studies/entry/__tests__/ScriptureWrapper.js new file mode 100644 index 000000000..b41b92d8e --- /dev/null +++ b/imports/pages/studies/entry/__tests__/ScriptureWrapper.js @@ -0,0 +1,54 @@ +/* eslint-disable */ +import { shallow } from "enzyme"; +import { shallowToJson } from "enzyme-to-json"; +import { reset, startBuffering } from "aphrodite/lib/inject"; + +import ScriptureWrapper from "../ScriptureWrapper"; + +beforeEach(() => { + reset(); + startBuffering(); +}); + +afterEach(() => { + reset(); +}); + +const defaultProps = { + studyEntry: { + content: { + scripture: [ + { book: "Job", passage: "2" }, + { book: "Job", passage: "3" }, + ], + }, + }, + classes: [], +}; + +const generateComponent = (additionalProps = {}) => { + const newProps = { + ...defaultProps, + ...additionalProps, + }; + return ; +}; + +it("renders scriptures", () => { + const wrapper = shallow(generateComponent()); + expect(shallowToJson(wrapper)).toMatchSnapshot(); +}); + +it("getClasses returns default classes", () => { + const wrapper = shallow(generateComponent()); + const result = wrapper.instance().getClasses(); + expect(result).toMatchSnapshot(); +}); + +it("getClasses appends additional classes", () => { + const wrapper = shallow(generateComponent({ + classes: ["test", "test2"], + })); + const result = wrapper.instance().getClasses(); + expect(result).toMatchSnapshot(); +}); diff --git a/imports/pages/studies/entry/__tests__/Slider.js b/imports/pages/studies/entry/__tests__/Slider.js new file mode 100644 index 000000000..5d10e62d2 --- /dev/null +++ b/imports/pages/studies/entry/__tests__/Slider.js @@ -0,0 +1,51 @@ +/* eslint-disable */ +import renderer from "react-test-renderer"; +import { shallow, mount } from "enzyme"; +import { shallowToJson, mountToJson } from "enzyme-to-json"; +import { reset, startBuffering } from "aphrodite/lib/inject"; + +import Slider from "../Slider"; + +jest.mock("../../../../components/controls/toggle"); +jest.mock("../Content"); +jest.mock("../ScriptureWrapper"); + +beforeEach(() => { + reset(); + startBuffering(); +}); + +afterEach(() => { + reset(); +}); + + +const defaultProps = { + studyEntry: { + content: { + ooyalaId: null, + images: [], + body: "

study body

", + }, + }, + toggleColor: "", + isLight: false, +}; + +const generateComponent = (additionalProps = {}) => { + const newProps = { + ...defaultProps, + ...additionalProps, + }; + + return ; +}; + +it("renders with props", () => { + const tree = renderer.create(generateComponent()); + expect(tree).toMatchSnapshot(); +}); + + + + diff --git a/imports/pages/studies/entry/__tests__/__snapshots__/Content.js.snap b/imports/pages/studies/entry/__tests__/__snapshots__/Content.js.snap new file mode 100644 index 000000000..765da54a5 --- /dev/null +++ b/imports/pages/studies/entry/__tests__/__snapshots__/Content.js.snap @@ -0,0 +1,136 @@ +exports[`test renders with an image and no video 1`] = ` +
+
+
+

+
+
+

+`; + +exports[`test renders with an ooyala video 1`] = ` +
+
+

+
+
+

+`; + +exports[`test renders with props 1`] = ` +
+
+

+
study body

", + } + } /> +
+
+`; + +exports[`test renders with related content 1`] = ` +
+
+
+

+
+
+

+`; + +exports[`test renders with scripture 1`] = ` +
+
+`; diff --git a/imports/pages/studies/entry/__tests__/__snapshots__/ScriptureItem.js.snap b/imports/pages/studies/entry/__tests__/__snapshots__/ScriptureItem.js.snap new file mode 100644 index 000000000..43751efd0 --- /dev/null +++ b/imports/pages/studies/entry/__tests__/__snapshots__/ScriptureItem.js.snap @@ -0,0 +1,37 @@ +exports[`test renders loading without scriptureData 1`] = ` +
+

+ Job 2 +

+

+ ESV +

+
+ +
+
+`; + +exports[`test renders scripture when state updated 1`] = ` +
+

+ Job 2 +

+

+ ESV +

+
scipture", + } + } /> +
+`; diff --git a/imports/pages/studies/entry/__tests__/__snapshots__/ScriptureWrapper.js.snap b/imports/pages/studies/entry/__tests__/__snapshots__/ScriptureWrapper.js.snap new file mode 100644 index 000000000..adde58f07 --- /dev/null +++ b/imports/pages/studies/entry/__tests__/__snapshots__/ScriptureWrapper.js.snap @@ -0,0 +1,29 @@ +exports[`test getClasses appends additional classes 1`] = `"hard-sides hard-top background--light-primary soft-sides@palm-wide-and-up test test2"`; + +exports[`test getClasses returns default classes 1`] = `"hard-sides hard-top background--light-primary soft-sides@palm-wide-and-up"`; + +exports[`test renders scriptures 1`] = ` +
+ + +

+ Scripture taken from The Holy Bible, English Standard Version. Copyright ©2001 by + + Crossway Bibles + + , a publishing ministry of Good News Publishers. Used by permission. All rights reserved. Text provided by the + + Crossway Bibles Web Service + + . +

+
+`; diff --git a/imports/pages/studies/entry/__tests__/__snapshots__/Slider.js.snap b/imports/pages/studies/entry/__tests__/__snapshots__/Slider.js.snap new file mode 100644 index 000000000..f77a93d3e --- /dev/null +++ b/imports/pages/studies/entry/__tests__/__snapshots__/Slider.js.snap @@ -0,0 +1,59 @@ +exports[`test renders with props 1`] = ` +
+
+
+
+
+
+
+
+
+
+
+
+
+`; diff --git a/imports/pages/studies/entry/__tests__/__snapshots__/index.js.snap b/imports/pages/studies/entry/__tests__/__snapshots__/index.js.snap new file mode 100644 index 000000000..010b0d79a --- /dev/null +++ b/imports/pages/studies/entry/__tests__/__snapshots__/index.js.snap @@ -0,0 +1,42 @@ +exports[`test renders loading with no studyEntry 1`] = ` +
+
+ +
+
+`; + +exports[`test renders without scripture or image 1`] = ` +devotion", + "images": Array [], + }, + "id": "1", + }, + } + }> +
+
+ + +
+ + +
+
+ +`; diff --git a/imports/pages/studies/entry/__tests__/index.js b/imports/pages/studies/entry/__tests__/index.js new file mode 100644 index 000000000..57d328866 --- /dev/null +++ b/imports/pages/studies/entry/__tests__/index.js @@ -0,0 +1,245 @@ +/* eslint-disable */ +import renderer from "react-test-renderer"; +import { reset, startBuffering } from "aphrodite/lib/inject"; +import { shallow, mount } from "enzyme"; +import { shallowToJson, mountToJson } from "enzyme-to-json"; + +import { + StudyEntrySingleWithoutData as StudyEntry, +} from "../index"; + +import { + nav as navActions, + header as headerActions, + live as liveActions, +} from "../../../../store"; + +import StudyEntryList from "../../EntryList"; +import Content from "../Content"; +import Slider from "../Slider"; + +jest.mock("../../../../mixins/mixins.Likeable", () => {}); +jest.mock("../../../../mixins/mixins.Shareable", () => {}); +jest.mock("../../../../store", () => ({ + nav: { + setLevel: jest.fn(), + setAction: jest.fn(), + }, + header: { + set: jest.fn(), + }, + live: { + hide: jest.fn(), + unfloat: jest.fn(), + floatDouble: jest.fn(), + show: jest.fn(), + }, +})); + +const defaultProps = { + dispatch: jest.fn(), + live: {}, + studyEntry: { + content: { + id: "1", + content: { + body: "

devotion

", + images: [], + }, + }, + }, + study: {}, + params: {} +}; + +beforeEach(() => { + reset(); + startBuffering(); +}); + +afterEach(() => { + reset(); +}); + +const mockHeaderAction = jest.fn(); +const MockHeaderAction = (Component) => ( + class MockHeaderAction extends React.Component { + constructor () { + super(...arguments); + this.headerAction = mockHeaderAction; + } + render() { + return + } + } +); + +const generateMockedComponent = (additionalProps = {}) => { + const newProps = { + ...defaultProps, + ...additionalProps, + }; + const MockedStudyEntry = MockHeaderAction(StudyEntry); + return ; +}; + +const generateComponent = (additionalProps = {}) => { + const newProps = { + ...defaultProps, + ...additionalProps, + }; + + return ; +}; + +it("renders without scripture or image", () => { + const wrapper = mount(generateComponent()); + expect(mountToJson(wrapper)).toMatchSnapshot(); +}); + +it("renders loading with no studyEntry", () => { + const wrapper = shallow(generateComponent({ + StudyEntry: {}, + })); + expect(shallowToJson(wrapper)).toMatchSnapshot(); +}); + +it("dispatches to the store on mount", () => { + const mockDispatch = jest.fn(); + liveActions.hide = jest.fn(); + navActions.setLevel = jest.fn(); + navActions.setAction = jest.fn(); + headerActions.set = jest.fn(); + const wrapper = shallow(generateComponent({ + dispatch: mockDispatch, + })); + expect(mockDispatch).toHaveBeenCalledTimes(3); + expect(liveActions.hide).toHaveBeenCalledTimes(1); + expect(navActions.setLevel).toHaveBeenCalledTimes(1); + expect(navActions.setLevel).toHaveBeenCalledWith("CONTENT"); + expect(navActions.setAction).toHaveBeenCalledTimes(1); + expect(navActions.setAction.mock.calls[0][0]).toBe("CONTENT"); +}); + +xit("updates when nextState is different", () => { + const wrapper = shallow(generateComponent()); + const result = wrapper.instance().shouldComponentUpdate({}, {}); + expect(result).toBe(true); +}); + +xit("updates when next content is different", () => { + const wrapper = shallow(generateComponent()); + wrapper.setState({ selectedIndex: 1 }); + const nextProps = { + studyEntry: { + content: { + id: "2", + content: { + body: "

study changed

", + images: [], + }, + }, + }, + }; + const result = wrapper.instance().shouldComponentUpdate(nextProps, wrapper.state()); + expect(result).toBe(true); + expect(wrapper.state().selectedIndex).toBe(1); +}); + +xit("does not update when content is the same", () => { + const wrapper = shallow(generateComponent()); + const result = wrapper.instance().shouldComponentUpdate(defaultProps, wrapper.state()); + expect(result).toBe(false); +}); + +xit("updates live bar when component updates", () => { + const wrapper = shallow(generateComponent()); + const mockHandleLiveBar = jest.fn(); + wrapper.instance().handleLiveBar = mockHandleLiveBar; + wrapper.instance().componentWillUpdate({}, {}); + expect(mockHandleLiveBar).toHaveBeenCalledTimes(1); +}); + +xit("unfloats the live bar on unmount", () => { + const mockDispatch = jest.fn(); + liveActions.unfloat = jest.fn(); + const wrapper = shallow(generateComponent({ + dispatch: mockDispatch, + })); + wrapper.instance().componentWillUnmount(); + expect(mockDispatch).toHaveBeenCalledTimes(6); + expect(liveActions.unfloat).toHaveBeenCalledTimes(1); +}); + +xit("onClickLink updates the state", () => { + const wrapper = shallow(generateComponent()); + const mockPreventDefault = jest.fn(); + wrapper.instance().onClickLink({ + preventDefault: mockPreventDefault, + }); + expect(mockPreventDefault).toHaveBeenCalledTimes(1); + expect(wrapper.state().selectedIndex).toBe(1); + expect(wrapper.state().liveSet).toBe(false); + expect(wrapper.state().livePush).toBe(false); +}); + +xit("getLiveClasses returns blank if not live", () => { + const wrapper = shallow(generateComponent()); + const result = wrapper.instance().getLiveClasses(); + expect(result).toEqual([]); +}); + +xit("getLiveClasses returns styles if live and livePush", () => { + const wrapper = shallow(generateComponent({ + live: { + live: true, + }, + })); + wrapper.setState({ livePush: true }); + const result = wrapper.instance().getLiveClasses(); + expect(result).toEqual(["push-double-top"]); +}); + +xit("updates live bar if live", () => { + jest.useFakeTimers(); + liveActions.show = jest.fn(); + const wrapper = shallow(generateComponent({ + live: { + live: true, + }, + })); + expect(wrapper.state().liveSet).toBe(true); + jest.runAllTimers(); + expect(liveActions.show).toHaveBeenCalledTimes(1); +}); + +xit("updates live bar with push if scripture", () => { + jest.useFakeTimers(); + liveActions.float = jest.fn(); + liveActions.show = jest.fn(); + const wrapper = shallow(generateComponent({ + studyEntry: { + content: { + id: "1", + content: { + body: "

devotion

", + images: [], + scripture: [ + { book: "Job", passage: "2" }, + ], + }, + }, + }, + live: { + live: true, + }, + })); + expect(wrapper.state().liveSet).toBe(true); + jest.runAllTimers(); + expect(wrapper.state().livePush).toBe(true); + expect(liveActions.float).toHaveBeenCalledTimes(1); + expect(liveActions.show).toHaveBeenCalledTimes(1); +}); + + + diff --git a/imports/pages/studies/entry/index.js b/imports/pages/studies/entry/index.js index c5f6c3b58..2519f82a7 100644 --- a/imports/pages/studies/entry/index.js +++ b/imports/pages/studies/entry/index.js @@ -33,6 +33,8 @@ class StudyEntrySingle extends Component { params: PropTypes.object.isRequried, } + state = {}; + componentWillMount() { if (process.env.WEB) return; diff --git a/imports/store/header/saga.js b/imports/store/header/saga.js index 345c32801..5451363d9 100644 --- a/imports/store/header/saga.js +++ b/imports/store/header/saga.js @@ -1,3 +1,4 @@ +import "regenerator-runtime/runtime"; import { takeLatest } from "redux-saga"; import { fork, select } from "redux-saga/effects"; import { addSaga } from "../utilities";