diff --git a/package-lock.json b/package-lock.json index 473eb21e2..25c60ef44 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1580,6 +1580,15 @@ "lodash.deburr": "^4.1.0" } }, + "@sinonjs/commons": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.0.2.tgz", + "integrity": "sha512-WR3dlgqJP4QNrLC4iXN/5/2WaLQQ0VijOOkmflqFGVJ6wLEpbSjo7c0ZeGIdtY8Crk7xBBp87sM6+Mkerz7alw==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, "@sinonjs/formatio": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", @@ -15230,9 +15239,9 @@ "dev": true }, "just-extend": { - "version": "1.1.27", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", - "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-3.0.0.tgz", + "integrity": "sha512-Fu3T6pKBuxjWT/p4DkqGHFRsysc8OauWr4ZRTY9dIx07Y9O0RkoR5jcv28aeD1vuAwhm3nLkDurwLXoALp4DpQ==", "dev": true }, "jwa": { @@ -16780,13 +16789,13 @@ "dev": true }, "nise": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.2.tgz", - "integrity": "sha512-BxH/DxoQYYdhKgVAfqVy4pzXRZELHOIewzoesxpjYvpU+7YOalQhGNPf7wAx8pLrTNPrHRDlLOkAl8UI0ZpXjw==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.4.tgz", + "integrity": "sha512-pxE0c9PzgrUTyhfv5p+5eMIdfU2bLEsq8VQEuE0kxM4zP7SujSar7rk9wpI2F7RyyCEvLyj5O7Is3RER5F36Fg==", "dev": true, "requires": { "@sinonjs/formatio": "^2.0.0", - "just-extend": "^1.1.27", + "just-extend": "^3.0.0", "lolex": "^2.3.2", "path-to-regexp": "^1.7.0", "text-encoding": "^0.6.4" @@ -22515,25 +22524,26 @@ "dev": true }, "sinon": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.1.3.tgz", - "integrity": "sha512-yeTza8xIZZdiXntCHJAzKll/sSYE+DuJOS8hiSapzaLqdW8eCNVVC9je9SZYYTkPm2bLts9x6UYxwuMAVVrM6Q==", + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.1.5.tgz", + "integrity": "sha512-TcbRoWs1SdY6NOqfj0c9OEQquBoZH+qEf8799m1jjcbfWrrpyCQ3B/BpX7+NKa7Vn33Jl+Z50H4Oys3bzygK2Q==", "dev": true, "requires": { + "@sinonjs/commons": "^1.0.1", "@sinonjs/formatio": "^2.0.0", "@sinonjs/samsam": "^2.0.0", "diff": "^3.5.0", "lodash.get": "^4.4.2", - "lolex": "^2.4.2", - "nise": "^1.3.3", + "lolex": "^2.7.1", + "nise": "^1.4.2", "supports-color": "^5.4.0", "type-detect": "^4.0.8" }, "dependencies": { "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" diff --git a/package.json b/package.json index ac9113a07..f48dcff66 100644 --- a/package.json +++ b/package.json @@ -207,7 +207,7 @@ "relay-runtime": "^1.7.0-rc.1", "sane": "^2.5.2", "simulant": "^0.2.2", - "sinon": "^6.1.3", + "sinon": "^6.1.5", "style-loader": "^0.21.0", "ts-jest": "^23.0.0", "ts-loader": "^4.4.2", diff --git a/src/core/client/framework/testHelpers/createSinonStub.ts b/src/core/client/framework/testHelpers/createSinonStub.ts new file mode 100644 index 000000000..5a7016d90 --- /dev/null +++ b/src/core/client/framework/testHelpers/createSinonStub.ts @@ -0,0 +1,9 @@ +import sinon, { SinonStub } from "sinon"; + +export default function createSinonStub( + ...callbacks: Array<(s: SinonStub) => void> +): SinonStub { + const stub = sinon.stub(); + callbacks.forEach(cb => cb(stub)); + return stub; +} diff --git a/src/core/client/framework/testHelpers/index.ts b/src/core/client/framework/testHelpers/index.ts index 484fb1d65..345e7be68 100644 --- a/src/core/client/framework/testHelpers/index.ts +++ b/src/core/client/framework/testHelpers/index.ts @@ -3,6 +3,7 @@ export { CreateRelayEnvironmentParams, } from "./createRelayEnvironment"; export { default as createFluentBundle } from "./createFluentBundle"; +export { default as createSinonStub } from "./createSinonStub"; export { default as removeFragmentRefs, NoFragmentRefs, diff --git a/src/core/client/stream/components/PostCommentForm.tsx b/src/core/client/stream/components/PostCommentForm.tsx index e1019ec84..00f544b86 100644 --- a/src/core/client/stream/components/PostCommentForm.tsx +++ b/src/core/client/stream/components/PostCommentForm.tsx @@ -27,13 +27,21 @@ export interface PostCommentFormProps { const PostCommentForm: StatelessComponent = props => (
{({ handleSubmit, submitting }) => ( - + {({ input, meta }) => (
- + Post a comment @@ -42,7 +50,7 @@ const PostCommentForm: StatelessComponent = props => ( attrs={{ placeholder: true }} > input.onChange(html)} value={input.value} placeholder="Post a comment" diff --git a/src/core/client/stream/test/__snapshots__/postComment.spec.tsx.snap b/src/core/client/stream/test/__snapshots__/postComment.spec.tsx.snap new file mode 100644 index 000000000..145f4be33 --- /dev/null +++ b/src/core/client/stream/test/__snapshots__/postComment.spec.tsx.snap @@ -0,0 +1,557 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`post a comment 1`] = ` +
+
+
+
+
+
+ Signed in as + + Markus + + . +
+
+ + Not you?  + + +
+
+
+ +
+
+ +
+
+
+ + + +
+ +
+
+
+
+
+
+ + Powered by + + ⁨The Coral Project⁩ + + +
+ +
+
+ +
+
+
+
+
+ + Markus + + +
+
Hello world", + } + } + /> +
+
+
+
+
+
+ + Markus + + +
+
+
+
+
+
+
+
+ + Lukas + + +
+
+
+
+
+
+
+
+`; + +exports[`renders comment stream 1`] = ` +
+
+
+
+
+
+ Signed in as + + Markus + + . +
+
+ + Not you?  + + +
+
+
+
+
+
+ +
+
+
+ + + +
+ +
+
+
+
+
+
+ + Powered by + + ⁨The Coral Project⁩ + + +
+ +
+
+ +
+
+
+
+
+ + Markus + + +
+
+
+
+
+
+
+
+ + Lukas + + +
+
+
+
+
+
+
+
+`; diff --git a/src/core/client/stream/test/postComment.spec.tsx b/src/core/client/stream/test/postComment.spec.tsx new file mode 100644 index 000000000..0546901db --- /dev/null +++ b/src/core/client/stream/test/postComment.spec.tsx @@ -0,0 +1,104 @@ +import React from "react"; +import TestRenderer, { ReactTestRenderer } from "react-test-renderer"; +import { RecordProxy } from "relay-runtime"; + +import { timeout } from "talk-common/utils"; +import { TalkContext, TalkContextProvider } from "talk-framework/lib/bootstrap"; +import { PostMessageService } from "talk-framework/lib/postMessage"; +import { RestClient } from "talk-framework/lib/rest"; +import { createInMemoryStorage } from "talk-framework/lib/storage"; +import { createSinonStub } from "talk-framework/testHelpers"; +import AppContainer from "talk-stream/containers/AppContainer"; + +import createEnvironment from "./createEnvironment"; +import createFluentBundle from "./createFluentBundle"; +import createNodeMock from "./createNodeMock"; +import { assets, users } from "./fixtures"; + +let testRenderer: ReactTestRenderer; +beforeEach(() => { + const resolvers = { + Query: { + asset: createSinonStub( + s => s.throws(), + s => s.withArgs(undefined, { id: assets[0].id }).returns(assets[0]) + ), + me: createSinonStub( + s => s.throws(), + s => s.withArgs(undefined, { clientAuthRevision: 0 }).returns(users[0]) + ), + }, + Mutation: { + createComment: createSinonStub( + s => s.throws(), + s => + s + .withArgs(undefined, { + input: { + assetID: assets[0].id, + body: "Hello world!", + clientMutationId: "0", + }, + }) + .returns({ + commentEdge: { + cursor: "2018-07-06T18:24:00.000Z", + node: { + id: "comment-x", + author: users[0], + body: "Hello world", + createdAt: "2018-07-06T18:24:00.000Z", + }, + }, + clientMutationId: "0", + }) + ), + }, + }; + + const environment = createEnvironment({ + // Set this to true, to see graphql responses. + logNetwork: false, + resolvers, + initLocalState: (localRecord: RecordProxy) => { + localRecord.setValue(assets[0].id, "assetID"); + localRecord.setValue(0, "authRevision"); + }, + }); + + const context: TalkContext = { + relayEnvironment: environment, + localeBundles: [createFluentBundle()], + localStorage: createInMemoryStorage(), + sessionStorage: createInMemoryStorage(), + rest: new RestClient("http://localhost/api"), + postMessage: new PostMessageService(), + }; + + testRenderer = TestRenderer.create( + + + , + { createNodeMock } + ); +}); + +it("renders comment stream", async () => { + // Wait for loading. + await timeout(); + expect(testRenderer.toJSON()).toMatchSnapshot(); +}); + +it("post a comment", async () => { + testRenderer.root + .findByProps({ inputId: "comments-postCommentForm-field" }) + .props.onChange({ html: "Hello world!" }); + + testRenderer.root + .findByProps({ id: "comments-postCommentForm-form" }) + .props.onSubmit(); + + // Wait for loading. + await timeout(); + expect(testRenderer.toJSON()).toMatchSnapshot(); +}); diff --git a/src/core/client/test/jsdom.ts b/src/core/client/test/jsdom.ts index 9e5518731..5ec90c988 100644 --- a/src/core/client/test/jsdom.ts +++ b/src/core/client/test/jsdom.ts @@ -5,6 +5,15 @@ declare var global: any; const jsdom = new JSDOM(""); const { window } = jsdom; +// tiny shim for getSelection for the RTE. +// tslint:disable:no-empty +window.getSelection = () => + ({ + addRange() {}, + removeAllRanges() {}, + } as any); +// tslint:enable:no-empty + function copyProps(src: any, target: any) { const props = Object.getOwnPropertyNames(src) .filter(prop => typeof target[prop] === "undefined")