Implement reply

This commit is contained in:
Chi Vinh Le
2018-09-06 00:06:58 +02:00
parent ee30003390
commit 110becb075
26 changed files with 2076 additions and 84 deletions
@@ -49,6 +49,7 @@ export class CommentContainer extends Component<InnerProps, State> {
footer={
<>
<ReplyButton
id={`comments-commentContainer-replyButton-${comment.id}`}
onClick={this.openReplyDialog}
active={showReplyDialog}
/>
@@ -0,0 +1,171 @@
import { shallow } from "enzyme";
import { noop } from "lodash";
import React from "react";
import sinon from "sinon";
import { PropTypesOf } from "talk-framework/types";
import { timeout } from "talk-common/utils";
import {
createFakePymStorage,
removeFragmentRefs,
} from "talk-framework/testHelpers";
import { ReplyCommentFormContainer } from "./ReplyCommentFormContainer";
const ReplyCommentFormContainerN = removeFragmentRefs(
ReplyCommentFormContainer
);
function getContextKey(commentID: string) {
return `replyCommentFormBody-${commentID}`;
}
it("renders correctly", async () => {
const props: PropTypesOf<typeof ReplyCommentFormContainerN> = {
// tslint:disable-next-line:no-empty
createComment: (() => {}) as any,
asset: {
id: "asset-id",
},
comment: {
id: "comment-id",
},
pymSessionStorage: createFakePymStorage(),
};
const wrapper = shallow(<ReplyCommentFormContainerN {...props} />);
await timeout();
wrapper.update();
expect(wrapper).toMatchSnapshot();
});
it("renders with initialValues", async () => {
const props: PropTypesOf<typeof ReplyCommentFormContainerN> = {
// tslint:disable-next-line:no-empty
createComment: (() => {}) as any,
asset: {
id: "asset-id",
},
comment: {
id: "comment-id",
},
pymSessionStorage: createFakePymStorage(),
};
await props.pymSessionStorage.setItem(
getContextKey(props.comment.id),
"Hello World!"
);
const wrapper = shallow(<ReplyCommentFormContainerN {...props} />);
await timeout();
wrapper.update();
expect(wrapper).toMatchSnapshot();
});
it("save values", async () => {
const props: PropTypesOf<typeof ReplyCommentFormContainerN> = {
// tslint:disable-next-line:no-empty
createComment: (() => {}) as any,
asset: {
id: "asset-id",
},
comment: {
id: "comment-id",
},
pymSessionStorage: createFakePymStorage(),
};
await props.pymSessionStorage.setItem(
getContextKey(props.comment.id),
"Hello World!"
);
const wrapper = shallow(<ReplyCommentFormContainerN {...props} />);
await timeout();
wrapper.update();
wrapper
.first()
.props()
.onChange({ values: { body: "changed" } });
expect(
await props.pymSessionStorage.getItem(getContextKey(props.comment.id))
).toBe("changed");
});
it("creates a comment", async () => {
const assetID = "asset-id";
const input = { body: "Hello World!" };
const createCommentStub = sinon.stub();
const form = { reset: noop };
const onCloseStub = sinon.stub();
const props: PropTypesOf<typeof ReplyCommentFormContainerN> = {
// tslint:disable-next-line:no-empty
createComment: createCommentStub,
asset: {
id: "asset-id",
},
comment: {
id: "comment-id",
},
pymSessionStorage: createFakePymStorage(),
onClose: onCloseStub,
};
await props.pymSessionStorage.setItem(
getContextKey(props.comment.id),
"Hello World!"
);
const wrapper = shallow(<ReplyCommentFormContainerN {...props} />);
await timeout();
wrapper.update();
wrapper
.first()
.props()
.onSubmit(input, form);
expect(
createCommentStub.calledWith({
assetID,
parentID: props.comment.id,
...input,
})
).toBeTruthy();
await timeout();
expect(onCloseStub.calledOnce).toBe(true);
});
it("closes on cancel", async () => {
const onCloseStub = sinon.stub();
const props: PropTypesOf<typeof ReplyCommentFormContainerN> = {
// tslint:disable-next-line:no-empty
createComment: (() => {}) as any,
asset: {
id: "asset-id",
},
comment: {
id: "comment-id",
},
pymSessionStorage: createFakePymStorage(),
onClose: onCloseStub,
};
await props.pymSessionStorage.setItem(
getContextKey(props.comment.id),
"Hello World!"
);
const wrapper = shallow(<ReplyCommentFormContainerN {...props} />);
await timeout();
wrapper.update();
wrapper.findWhere(w => !!w.prop("onCancel")).prop("onCancel")();
// Calls close.
expect(onCloseStub.calledOnce).toBe(true);
// Removes saved value.
expect(
await props.pymSessionStorage.getItem(getContextKey(props.comment.id))
).toBeNull();
});
@@ -67,6 +67,7 @@ export class ReplyCommentFormContainer extends Component<InnerProps, State> {
parentID: this.props.comment.id,
...input,
});
this.props.pymSessionStorage.removeItem(this.contextKey);
if (this.props.onClose) {
this.props.onClose();
@@ -95,6 +96,7 @@ export class ReplyCommentFormContainer extends Component<InnerProps, State> {
}
return (
<ReplyCommentForm
id={this.props.comment.id}
onSubmit={this.handleOnSubmit}
onChange={this.handleOnChange}
initialValues={this.state.initialValues}
@@ -18,6 +18,15 @@ interface InnerProps {
relay: RelayPaginationProp;
}
// tslint:disable-next-line:no-unused-expression
graphql`
fragment StreamContainer_comment on Comment {
id
...CommentContainer_comment
...ReplyListContainer_comment
}
`;
export class StreamContainer extends React.Component<InnerProps> {
public state = {
disableLoadMore: false,
@@ -81,9 +90,7 @@ const enhanced = withPaginationContainer<
@connection(key: "Stream_comments") {
edges {
node {
id
...CommentContainer_comment
...ReplyListContainer_comment
...StreamContainer_comment @relay(mask: false)
}
}
}
@@ -14,6 +14,7 @@ exports[`renders body only 1`] = `
<React.Fragment>
<ReplyButton
active={false}
id="comments-commentContainer-replyButton"
onClick={[Function]}
/>
<withContext(withLocalStateContainer(PermalinkContainer))
@@ -41,6 +42,7 @@ exports[`renders username and body 1`] = `
<React.Fragment>
<ReplyButton
active={false}
id="comments-commentContainer-replyButton"
onClick={[Function]}
/>
<withContext(withLocalStateContainer(PermalinkContainer))
@@ -0,0 +1,22 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<ReplyCommentForm
onCancel={[Function]}
onChange={[Function]}
onSubmit={[Function]}
/>
`;
exports[`renders with initialValues 1`] = `
<ReplyCommentForm
initialValues={
Object {
"body": "Hello World!",
}
}
onCancel={[Function]}
onChange={[Function]}
onSubmit={[Function]}
/>
`;