Add integration test

This commit is contained in:
Chi Vinh Le
2018-08-31 17:15:40 +02:00
parent 428c35a931
commit 25e8cb517b
8 changed files with 717 additions and 19 deletions
@@ -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;
}
@@ -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,
@@ -27,13 +27,21 @@ export interface PostCommentFormProps {
const PostCommentForm: StatelessComponent<PostCommentFormProps> = props => (
<Form onSubmit={props.onSubmit}>
{({ handleSubmit, submitting }) => (
<form autoComplete="off" onSubmit={handleSubmit} className={styles.root}>
<form
autoComplete="off"
onSubmit={handleSubmit}
className={styles.root}
id="comments-postCommentForm-form"
>
<HorizontalGutter>
<Field name="body" validate={required}>
{({ input, meta }) => (
<div>
<Localized id="comments-postCommentForm-rteLabel">
<AriaInfo component="label" htmlFor="postCommentField">
<AriaInfo
component="label"
htmlFor="comments-postCommentForm-field"
>
Post a comment
</AriaInfo>
</Localized>
@@ -42,7 +50,7 @@ const PostCommentForm: StatelessComponent<PostCommentFormProps> = props => (
attrs={{ placeholder: true }}
>
<RTE
inputId="postCommentField"
inputId="comments-postCommentForm-field"
onChange={({ html }) => input.onChange(html)}
value={input.value}
placeholder="Post a comment"
@@ -0,0 +1,557 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`post a comment 1`] = `
<div
className="Flex-root App-root Flex-flex Flex-justifyCenter"
>
<div
className="HorizontalGutter-root Stream-root HorizontalGutter-double"
>
<div
className="HorizontalGutter-root HorizontalGutter-half"
>
<div
className="Flex-root"
>
<div
className="Flex-flex Flex-halfItemGutter Flex-wrap"
>
<div
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Signed in as
<span
className="Typography-root Typography-bodyCopyBold Typography-colorTextPrimary"
>
Markus
</span>
.
</div>
<div
className="Flex-root Typography-root Typography-bodyCopy Typography-colorTextPrimary Flex-flex"
>
<span>
Not you? 
</span>
<button
className="BaseButton-root Button-root Button-sizeSmall Button-colorPrimary Button-variantUnderlined"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
type="button"
>
Sign Out
</button>
</div>
</div>
</div>
<form
autoComplete="off"
className="PostCommentForm-root"
id="comments-postCommentForm-form"
onSubmit={[Function]}
>
<div
className="HorizontalGutter-root HorizontalGutter-full"
>
<div>
<label
className="AriaInfo-root"
htmlFor="comments-postCommentForm-field"
>
Post a comment
</label>
<div>
<div
className=""
>
<div
className="Toolbar-toolbar"
>
<button
className="Button-button"
disabled={false}
onClick={[Function]}
title="Bold"
type="button"
>
<span
aria-hidden="true"
className="Icon-root Icon-sm"
>
format_bold
</span>
</button>
<button
className="Button-button"
disabled={false}
onClick={[Function]}
title="Italic"
type="button"
>
<span
aria-hidden="true"
className="Icon-root Icon-sm"
>
format_italic
</span>
</button>
<button
className="Button-button"
disabled={false}
onClick={[Function]}
title="Blockquote"
type="button"
>
<span
aria-hidden="true"
className="Icon-root Icon-sm"
>
format_quote
</span>
</button>
</div>
<div
aria-hidden="true"
className="RTE-placeholder RTE-placeholder"
>
Post a comment
</div>
<div
aria-placeholder="Post a comment"
className="RTE-contentEditable RTE-content"
contentEditable={true}
dangerouslySetInnerHTML={
Object {
"__html": "",
}
}
id="comments-postCommentForm-field"
onBlur={[Function]}
onChange={[Function]}
onCut={[Function]}
onFocus={[Function]}
onInput={[Function]}
onKeyDown={[Function]}
onPaste={[Function]}
onSelect={[Function]}
/>
</div>
</div>
</div>
<div
className="Flex-root Flex-flex Flex-justifySpaceBetween Flex-alignFlexStart Flex-directionRow"
>
<div
className="PostCommentForm-poweredBy"
>
<span
className="Typography-root Typography-inputDescription Typography-colorTextSecondary"
>
Powered by
<span
className="Typography-root Typography-heading4 Typography-colorTextPrimary"
>
The Coral Project
</span>
</span>
</div>
<button
className="BaseButton-root Button-root Button-sizeRegular Button-colorPrimary Button-variantFilled"
disabled={false}
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
type="submit"
>
Submit
</button>
</div>
</div>
</form>
</div>
<div
aria-live="polite"
className="HorizontalGutter-root HorizontalGutter-full"
id="talk-comments-stream-log"
role="log"
>
<div
className="HorizontalGutter-root HorizontalGutter-full"
>
<div
className="Comment-root"
role="article"
>
<div
className="Flex-root TopBar-root Flex-flex Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Markus
</span>
<time
className="Timestamp-root RelativeTime-root"
dateTime="2018-07-06T18:24:00.000Z"
title="2018-07-06T18:24:00.000Z"
>
2018-07-06T18:24:00.000Z
</time>
</div>
<div
className="HTMLContent-root"
dangerouslySetInnerHTML={
Object {
"__html": "<strong>Hello world</strong>",
}
}
/>
<div
className="Comment-footer"
/>
</div>
</div>
<div
className="HorizontalGutter-root HorizontalGutter-full"
>
<div
className="Comment-root"
role="article"
>
<div
className="Flex-root TopBar-root Flex-flex Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Markus
</span>
<time
className="Timestamp-root RelativeTime-root"
dateTime="2018-07-06T18:24:00.000Z"
title="2018-07-06T18:24:00.000Z"
>
2018-07-06T18:24:00.000Z
</time>
</div>
<div
className="HTMLContent-root"
dangerouslySetInnerHTML={
Object {
"__html": "Joining Too",
}
}
/>
<div
className="Comment-footer"
/>
</div>
</div>
<div
className="HorizontalGutter-root HorizontalGutter-full"
>
<div
className="Comment-root"
role="article"
>
<div
className="Flex-root TopBar-root Flex-flex Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Lukas
</span>
<time
className="Timestamp-root RelativeTime-root"
dateTime="2018-07-06T18:20:00.000Z"
title="2018-07-06T18:20:00.000Z"
>
2018-07-06T18:20:00.000Z
</time>
</div>
<div
className="HTMLContent-root"
dangerouslySetInnerHTML={
Object {
"__html": "What's up?",
}
}
/>
<div
className="Comment-footer"
/>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders comment stream 1`] = `
<div
className="Flex-root App-root Flex-flex Flex-justifyCenter"
>
<div
className="HorizontalGutter-root Stream-root HorizontalGutter-double"
>
<div
className="HorizontalGutter-root HorizontalGutter-half"
>
<div
className="Flex-root"
>
<div
className="Flex-flex Flex-halfItemGutter Flex-wrap"
>
<div
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Signed in as
<span
className="Typography-root Typography-bodyCopyBold Typography-colorTextPrimary"
>
Markus
</span>
.
</div>
<div
className="Flex-root Typography-root Typography-bodyCopy Typography-colorTextPrimary Flex-flex"
>
<span>
Not you? 
</span>
<button
className="BaseButton-root Button-root Button-sizeSmall Button-colorPrimary Button-variantUnderlined"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
type="button"
>
Sign Out
</button>
</div>
</div>
</div>
<form
autoComplete="off"
className="PostCommentForm-root"
id="comments-postCommentForm-form"
onSubmit={[Function]}
>
<div
className="HorizontalGutter-root HorizontalGutter-full"
>
<div>
<label
className="AriaInfo-root"
htmlFor="comments-postCommentForm-field"
>
Post a comment
</label>
<div>
<div
className=""
>
<div
className="Toolbar-toolbar"
>
<button
className="Button-button"
disabled={false}
onClick={[Function]}
title="Bold"
type="button"
>
<span
aria-hidden="true"
className="Icon-root Icon-sm"
>
format_bold
</span>
</button>
<button
className="Button-button"
disabled={false}
onClick={[Function]}
title="Italic"
type="button"
>
<span
aria-hidden="true"
className="Icon-root Icon-sm"
>
format_italic
</span>
</button>
<button
className="Button-button"
disabled={false}
onClick={[Function]}
title="Blockquote"
type="button"
>
<span
aria-hidden="true"
className="Icon-root Icon-sm"
>
format_quote
</span>
</button>
</div>
<div
aria-hidden="true"
className="RTE-placeholder RTE-placeholder"
>
Post a comment
</div>
<div
aria-placeholder="Post a comment"
className="RTE-contentEditable RTE-content"
contentEditable={true}
dangerouslySetInnerHTML={
Object {
"__html": "",
}
}
id="comments-postCommentForm-field"
onBlur={[Function]}
onChange={[Function]}
onCut={[Function]}
onFocus={[Function]}
onInput={[Function]}
onKeyDown={[Function]}
onPaste={[Function]}
onSelect={[Function]}
/>
</div>
</div>
</div>
<div
className="Flex-root Flex-flex Flex-justifySpaceBetween Flex-alignFlexStart Flex-directionRow"
>
<div
className="PostCommentForm-poweredBy"
>
<span
className="Typography-root Typography-inputDescription Typography-colorTextSecondary"
>
Powered by
<span
className="Typography-root Typography-heading4 Typography-colorTextPrimary"
>
The Coral Project
</span>
</span>
</div>
<button
className="BaseButton-root Button-root Button-sizeRegular Button-colorPrimary Button-variantFilled"
disabled={false}
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
type="submit"
>
Submit
</button>
</div>
</div>
</form>
</div>
<div
aria-live="polite"
className="HorizontalGutter-root HorizontalGutter-full"
id="talk-comments-stream-log"
role="log"
>
<div
className="HorizontalGutter-root HorizontalGutter-full"
>
<div
className="Comment-root"
role="article"
>
<div
className="Flex-root TopBar-root Flex-flex Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Markus
</span>
<time
className="Timestamp-root RelativeTime-root"
dateTime="2018-07-06T18:24:00.000Z"
title="2018-07-06T18:24:00.000Z"
>
2018-07-06T18:24:00.000Z
</time>
</div>
<div
className="HTMLContent-root"
dangerouslySetInnerHTML={
Object {
"__html": "Joining Too",
}
}
/>
<div
className="Comment-footer"
/>
</div>
</div>
<div
className="HorizontalGutter-root HorizontalGutter-full"
>
<div
className="Comment-root"
role="article"
>
<div
className="Flex-root TopBar-root Flex-flex Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Lukas
</span>
<time
className="Timestamp-root RelativeTime-root"
dateTime="2018-07-06T18:20:00.000Z"
title="2018-07-06T18:20:00.000Z"
>
2018-07-06T18:20:00.000Z
</time>
</div>
<div
className="HTMLContent-root"
dangerouslySetInnerHTML={
Object {
"__html": "What's up?",
}
}
/>
<div
className="Comment-footer"
/>
</div>
</div>
</div>
</div>
</div>
`;
@@ -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: "<strong>Hello world!</strong>",
clientMutationId: "0",
},
})
.returns({
commentEdge: {
cursor: "2018-07-06T18:24:00.000Z",
node: {
id: "comment-x",
author: users[0],
body: "<strong>Hello world</strong>",
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(
<TalkContextProvider value={context}>
<AppContainer />
</TalkContextProvider>,
{ 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: "<strong>Hello world!</strong>" });
testRenderer.root
.findByProps({ id: "comments-postCommentForm-form" })
.props.onSubmit();
// Wait for loading.
await timeout();
expect(testRenderer.toJSON()).toMatchSnapshot();
});
+9
View File
@@ -5,6 +5,15 @@ declare var global: any;
const jsdom = new JSDOM("<!doctype html><html><body></body></html>");
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")