Implement Replies

This commit is contained in:
Chi Vinh Le
2018-07-09 16:45:36 -03:00
parent 84dd673c2e
commit 25c931cc05
25 changed files with 1007 additions and 139 deletions
+6 -1
View File
@@ -15,7 +15,12 @@ const config: Config = {
"core/client/stream/**/*.graphql",
"core/client/server/**/*.graphql",
],
ignore: ["core/**/*.d.ts", "core/**/*.graphql.ts"],
ignore: [
"core/**/*.d.ts",
"core/**/*.graphql.ts",
"**/test/**/*",
"core/**/*.spec.*",
],
executor: new CommandExecutor("npm run compile:relay-stream", {
runOnInit: true,
}),
+5
View File
@@ -224,6 +224,11 @@ module.exports = {
jsx: "preserve",
noEmit: false,
},
// Overwrites the behavior of `include` and `exclude` to only
// include files that are actually being imported and which
// are necessary to compile the bundle.
onlyCompileBundledFiles: true,
},
},
],
@@ -0,0 +1,16 @@
import React, { StatelessComponent } from "react";
export interface IndentProps {
level?: number;
children: React.ReactNode;
}
const Indent: StatelessComponent<IndentProps> = props => {
return (
<div style={{ marginLeft: "16px", marginTop: "8px", marginBottom: "8px" }}>
{props.children}
</div>
);
};
export default Indent;
@@ -0,0 +1,36 @@
import { shallow } from "enzyme";
import { noop } from "lodash";
import React from "react";
import sinon from "sinon";
import ReplyList from "./ReplyList";
it("renders correctly", () => {
const props = {
commentID: "comment-id",
comments: [{ id: "comment-1" }, { id: "comment-2" }],
onLoadMore: noop,
hasMore: false,
};
const wrapper = shallow(<ReplyList {...props} />);
expect(wrapper).toMatchSnapshot();
});
describe("when there is more", () => {
const props = {
commentID: "comment-id",
comments: [{ id: "comment-1" }, { id: "comment-2" }],
onLoadMore: sinon.spy(),
hasMore: true,
};
const wrapper = shallow(<ReplyList {...props} />);
it("renders a load more button", () => {
expect(wrapper).toMatchSnapshot();
});
it("calls onLoadMore", () => {
wrapper.find("#talk-reply-list--show-all--comment-id").simulate("click");
expect(props.onLoadMore.calledOnce).toBe(true);
});
});
@@ -0,0 +1,37 @@
import * as React from "react";
import { StatelessComponent } from "react";
import { Button } from "talk-ui/components";
import CommentContainer from "../containers/CommentContainer";
import Indent from "./Indent";
export interface ReplyListProps {
commentID: string;
comments: ReadonlyArray<{ id: string }>;
onLoadMore: () => void;
hasMore: boolean;
}
const ReplyList: StatelessComponent<ReplyListProps> = props => {
return (
<Indent>
{props.comments.map(comment => (
<CommentContainer key={comment.id} data={comment} gutterBottom />
))}
{props.hasMore && (
<Button
id={`talk-reply-list--show-all--${props.commentID}`}
onClick={props.onLoadMore}
secondary
invert
fullWidth
>
Show All Replies
</Button>
)}
</Indent>
);
};
export default ReplyList;
@@ -7,7 +7,7 @@ import Stream from "./Stream";
it("renders correctly", () => {
const props = {
id: "asset-id",
assetID: "asset-id",
isClosed: false,
comments: [{ id: "comment-1" }, { id: "comment-2" }],
onLoadMore: noop,
@@ -19,7 +19,7 @@ it("renders correctly", () => {
it("renders when comments is null", () => {
const props = {
id: "asset-id",
assetID: "asset-id",
isClosed: false,
comments: null,
onLoadMore: noop,
@@ -31,7 +31,7 @@ it("renders when comments is null", () => {
describe("when there is more", () => {
const props = {
id: "asset-id",
assetID: "asset-id",
isClosed: false,
comments: [{ id: "comment-1" }, { id: "comment-2" }],
onLoadMore: sinon.spy(),
@@ -44,7 +44,7 @@ describe("when there is more", () => {
});
it("calls onLoadMore", () => {
wrapper.find("#talk-stream--loadmore").simulate("click");
wrapper.find("#talk-stream--load-more").simulate("click");
expect(props.onLoadMore.calledOnce).toBe(true);
});
});
+12 -7
View File
@@ -1,13 +1,15 @@
import * as React from "react";
import { StatelessComponent } from "react";
import Logo from "talk-stream/components/Logo";
import CommentContainer from "talk-stream/containers/CommentContainer";
import PostCommentFormContainer from "talk-stream/containers/PostCommentFormContainer";
import { Button } from "talk-ui/components";
import CommentContainer from "../containers/CommentContainer";
import PostCommentFormContainer from "../containers/PostCommentFormContainer";
import ReplyListContainer from "../containers/ReplyListContainer";
import Logo from "./Logo";
export interface StreamProps {
id: string;
assetID: string;
isClosed: boolean;
comments: ReadonlyArray<{ id: string }> | null;
onLoadMore: () => void;
@@ -22,13 +24,16 @@ const Stream: StatelessComponent<StreamProps> = props => {
return (
<div>
<Logo gutterBottom />
<PostCommentFormContainer assetID={props.id} />
<PostCommentFormContainer assetID={props.assetID} />
{props.comments.map(comment => (
<CommentContainer key={comment.id} data={comment} gutterBottom />
<div key={comment.id}>
<CommentContainer data={comment} gutterBottom />
<ReplyListContainer comment={comment} />
</div>
))}
{props.hasMore && (
<Button
id={"talk-stream--loadmore"}
id={"talk-stream--load-more"}
onClick={props.onLoadMore}
secondary
invert
@@ -0,0 +1,56 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<Indent>
<Relay(CommentContainer)
data={
Object {
"id": "comment-1",
}
}
gutterBottom={true}
key="comment-1"
/>
<Relay(CommentContainer)
data={
Object {
"id": "comment-2",
}
}
gutterBottom={true}
key="comment-2"
/>
</Indent>
`;
exports[`when there is more renders a load more button 1`] = `
<Indent>
<Relay(CommentContainer)
data={
Object {
"id": "comment-1",
}
}
gutterBottom={true}
key="comment-1"
/>
<Relay(CommentContainer)
data={
Object {
"id": "comment-2",
}
}
gutterBottom={true}
key="comment-2"
/>
<withPropsOnChange(Button)
fullWidth={true}
id="talk-reply-list--show-all--comment-id"
invert={true}
onClick={[Function]}
secondary={true}
>
Show All Replies
</withPropsOnChange(Button)>
</Indent>
`;
@@ -8,24 +8,44 @@ exports[`renders correctly 1`] = `
<withContext(createMutationContainer(PostCommentFormContainer))
assetID="asset-id"
/>
<Relay(CommentContainer)
data={
Object {
"id": "comment-1",
}
}
gutterBottom={true}
<div
key="comment-1"
/>
<Relay(CommentContainer)
data={
Object {
"id": "comment-2",
>
<Relay(CommentContainer)
data={
Object {
"id": "comment-1",
}
}
}
gutterBottom={true}
gutterBottom={true}
/>
<Relay(ReplyListContainer)
comment={
Object {
"id": "comment-1",
}
}
/>
</div>
<div
key="comment-2"
/>
>
<Relay(CommentContainer)
data={
Object {
"id": "comment-2",
}
}
gutterBottom={true}
/>
<Relay(ReplyListContainer)
comment={
Object {
"id": "comment-2",
}
}
/>
</div>
</div>
`;
@@ -43,27 +63,47 @@ exports[`when there is more renders a load more button 1`] = `
<withContext(createMutationContainer(PostCommentFormContainer))
assetID="asset-id"
/>
<Relay(CommentContainer)
data={
Object {
"id": "comment-1",
}
}
gutterBottom={true}
<div
key="comment-1"
/>
<Relay(CommentContainer)
data={
Object {
"id": "comment-2",
>
<Relay(CommentContainer)
data={
Object {
"id": "comment-1",
}
}
}
gutterBottom={true}
gutterBottom={true}
/>
<Relay(ReplyListContainer)
comment={
Object {
"id": "comment-1",
}
}
/>
</div>
<div
key="comment-2"
/>
>
<Relay(CommentContainer)
data={
Object {
"id": "comment-2",
}
}
gutterBottom={true}
/>
<Relay(ReplyListContainer)
comment={
Object {
"id": "comment-2",
}
}
/>
</div>
<withPropsOnChange(Button)
fullWidth={true}
id="talk-stream--loadmore"
id="talk-stream--load-more"
invert={true}
onClick={[Function]}
secondary={true}
@@ -9,6 +9,16 @@ import Comment, { CommentProps } from "../components/Comment";
type InnerProps = { data: Data } & Omit<CommentProps, keyof Data>;
// tslint:disable-next-line:no-unused-expression
graphql`
fragment CommentContainer_comment on Comment {
author {
username
}
body
}
`;
export const CommentContainer: StatelessComponent<InnerProps> = props => {
const { data, ...rest } = props;
return <Comment {...rest} {...props.data} />;
@@ -17,10 +27,7 @@ export const CommentContainer: StatelessComponent<InnerProps> = props => {
const enhanced = withFragmentContainer<{ data: Data }>({
data: graphql`
fragment CommentContainer on Comment {
author {
username
}
body
...CommentContainer_comment @relay(mask: false)
}
`,
})(CommentContainer);
@@ -0,0 +1,37 @@
import { shallow } from "enzyme";
import { noop } from "lodash";
import React from "react";
import { ReplyListContainer } from "./ReplyListContainer";
it("renders correctly", () => {
const props: any = {
comment: {
id: "comment-id",
replies: {
edges: [{ node: { id: "comment-1" } }, { node: { id: "comment-2" } }],
},
},
relay: {
hasMore: noop,
isLoading: noop,
},
};
const wrapper = shallow(<ReplyListContainer {...props} />);
expect(wrapper).toMatchSnapshot();
});
it("renders correctly when replies are null", () => {
const props: any = {
comment: {
id: "comment-id",
replies: null,
},
relay: {
hasMore: noop,
isLoading: noop,
},
};
const wrapper = shallow(<ReplyListContainer {...props} />);
expect(wrapper).toMatchSnapshot();
});
@@ -0,0 +1,125 @@
import React from "react";
import { graphql, RelayPaginationProp } from "react-relay";
import { withPaginationContainer } from "talk-framework/lib/relay";
import { PropTypesOf } from "talk-framework/types";
import { ReplyListContainer_comment as Data } from "talk-stream/__generated__/ReplyListContainer_comment.graphql";
import {
COMMENT_SORT,
ReplyListContainerPaginationQueryVariables,
} from "talk-stream/__generated__/ReplyListContainerPaginationQuery.graphql";
import ReplyList from "../components/ReplyList";
export interface InnerProps {
comment: Data;
relay: RelayPaginationProp;
}
export class ReplyListContainer extends React.Component<InnerProps> {
public render() {
if (this.props.comment.replies === null) {
return null;
}
const comments = this.props.comment.replies.edges.map(edge => edge.node);
return (
<ReplyList
commentID={this.props.comment.id}
comments={comments}
onLoadMore={this.loadMore}
hasMore={this.props.relay.hasMore()}
/>
);
}
private loadMore = () => {
if (!this.props.relay.hasMore() || this.props.relay.isLoading()) {
return;
}
this.props.relay.loadMore(
999999999, // Fetch All Replies
error => {
if (error) {
// tslint:disable-next-line:no-console
console.error(error);
}
}
);
};
}
// TODO: (cvle) This should be autogenerated.
interface FragmentVariables {
count: number;
cursor?: string;
orderBy: COMMENT_SORT;
}
const enhanced = withPaginationContainer<
{ comment: Data },
InnerProps,
FragmentVariables,
ReplyListContainerPaginationQueryVariables
>(
{
comment: graphql`
fragment ReplyListContainer_comment on Comment
@argumentDefinitions(
count: { type: "Int!", defaultValue: 5 }
cursor: { type: "Cursor" }
orderBy: { type: "COMMENT_SORT!", defaultValue: CREATED_AT_ASC }
) {
id
replies(first: $count, after: $cursor, orderBy: $orderBy)
@connection(key: "ReplyList_replies") {
edges {
node {
id
...CommentContainer
}
}
}
}
`,
},
{
direction: "forward",
getConnectionFromProps(props) {
return props.comment && props.comment.replies;
},
// This is also the default implementation of `getFragmentVariables` if it isn't provided.
getFragmentVariables(prevVars, totalCount) {
return {
...prevVars,
count: totalCount,
};
},
getVariables(props, { count, cursor }, fragmentVariables) {
return {
count,
cursor,
orderBy: fragmentVariables.orderBy,
commentID: props.comment.id,
};
},
query: graphql`
# Pagination query to be fetched upon calling 'loadMore'.
# Notice that we re-use our fragment, and the shape of this query matches our fragment spec.
query ReplyListContainerPaginationQuery(
$count: Int!
$cursor: Cursor
$orderBy: COMMENT_SORT!
$commentID: ID!
) {
comment(id: $commentID) {
...ReplyListContainer_comment
@arguments(count: $count, cursor: $cursor, orderBy: $orderBy)
}
}
`,
}
)(ReplyListContainer);
export type ReplyListContainerProps = PropTypesOf<typeof enhanced>;
export default enhanced;
@@ -4,7 +4,7 @@ import React from "react";
import { StreamContainer } from "./StreamContainer";
it("renders username and body", () => {
it("renders correctly", () => {
const props: any = {
asset: {
id: "asset-id",
@@ -11,7 +11,7 @@ import {
import Stream from "../components/Stream";
export interface InnerProps {
interface InnerProps {
asset: Data;
relay: RelayPaginationProp;
}
@@ -23,7 +23,8 @@ export class StreamContainer extends React.Component<InnerProps> {
: null;
return (
<Stream
{...this.props.asset}
assetID={this.props.asset.id}
isClosed={this.props.asset.isClosed}
comments={comments}
onLoadMore={this.loadMore}
hasMore={this.props.relay.hasMore()}
@@ -77,6 +78,7 @@ const enhanced = withPaginationContainer<
node {
id
...CommentContainer
...ReplyListContainer_comment
}
}
}
@@ -0,0 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<ReplyList
commentID="comment-id"
comments={
Array [
Object {
"id": "comment-1",
},
Object {
"id": "comment-2",
},
]
}
onLoadMore={[Function]}
/>
`;
exports[`renders correctly when replies are null 1`] = `""`;
@@ -1,7 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders username and body 1`] = `
exports[`renders correctly 1`] = `
<Stream
assetID="asset-id"
comments={
Array [
Object {
@@ -12,7 +13,6 @@ exports[`renders username and body 1`] = `
},
]
}
id="asset-id"
isClosed={false}
onLoadMore={[Function]}
/>
@@ -36,47 +36,53 @@ exports[`loads more comments 1`] = `
</button>
</div>
</form>
<div
className="root gutterBottom"
>
<p
className="root body1 gutterBottom author"
<div>
<div
className="root gutterBottom"
>
Markus
</p>
<p
className="root body1"
>
Joining Too
</p>
<p
className="root body1 gutterBottom author"
>
Markus
</p>
<p
className="root body1"
>
Joining Too
</p>
</div>
</div>
<div
className="root gutterBottom"
>
<p
className="root body1 gutterBottom author"
<div>
<div
className="root gutterBottom"
>
Lukas
</p>
<p
className="root body1"
>
What's up?
</p>
<p
className="root body1 gutterBottom author"
>
Lukas
</p>
<p
className="root body1"
>
What's up?
</p>
</div>
</div>
<div
className="root gutterBottom"
>
<p
className="root body1 gutterBottom author"
<div>
<div
className="root gutterBottom"
>
Isabelle
</p>
<p
className="root body1"
>
Hey!
</p>
<p
className="root body1 gutterBottom author"
>
Isabelle
</p>
<p
className="root body1"
>
Hey!
</p>
</div>
</div>
</div>
</div>
@@ -118,37 +124,41 @@ exports[`renders comment stream 1`] = `
</button>
</div>
</form>
<div
className="root gutterBottom"
>
<p
className="root body1 gutterBottom author"
<div>
<div
className="root gutterBottom"
>
Markus
</p>
<p
className="root body1"
>
Joining Too
</p>
<p
className="root body1 gutterBottom author"
>
Markus
</p>
<p
className="root body1"
>
Joining Too
</p>
</div>
</div>
<div
className="root gutterBottom"
>
<p
className="root body1 gutterBottom author"
<div>
<div
className="root gutterBottom"
>
Lukas
</p>
<p
className="root body1"
>
What's up?
</p>
<p
className="root body1 gutterBottom author"
>
Lukas
</p>
<p
className="root body1"
>
What's up?
</p>
</div>
</div>
<button
className="root root invert fullWidth secondary"
id="talk-stream--loadmore"
id="talk-stream--load-more"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
@@ -0,0 +1,111 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders comment stream 1`] = `
<div
className="root"
>
<div>
<h1
className="root heading1 gutterBottom"
>
Talk NEO
</h1>
<form
autoComplete="off"
onSubmit={[Function]}
>
<div>
<textarea
className="textarea"
name="body"
onChange={[Function]}
value=""
/>
</div>
<div
className="postButtonContainer"
>
<button
className="root root primary"
disabled={false}
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
>
Post
</button>
</div>
</form>
<div>
<div
className="root gutterBottom"
>
<p
className="root body1 gutterBottom author"
>
Markus
</p>
<p
className="root body1"
>
Joining Too
</p>
</div>
</div>
<div>
<div
className="root gutterBottom"
>
<p
className="root body1 gutterBottom author"
>
Markus
</p>
<p
className="root body1"
>
I like yoghurt
</p>
</div>
<div
style={
Object {
"marginBottom": "8px",
"marginLeft": "16px",
"marginTop": "8px",
}
}
>
<div
className="root gutterBottom"
>
<p
className="root body1 gutterBottom author"
>
Markus
</p>
<p
className="root body1"
>
Joining Too
</p>
</div>
<div
className="root gutterBottom"
>
<p
className="root body1 gutterBottom author"
>
Lukas
</p>
<p
className="root body1"
>
What's up?
</p>
</div>
</div>
</div>
</div>
</div>
`;
@@ -36,33 +36,37 @@ exports[`renders comment stream 1`] = `
</button>
</div>
</form>
<div
className="root gutterBottom"
>
<p
className="root body1 gutterBottom author"
<div>
<div
className="root gutterBottom"
>
Markus
</p>
<p
className="root body1"
>
Joining Too
</p>
<p
className="root body1 gutterBottom author"
>
Markus
</p>
<p
className="root body1"
>
Joining Too
</p>
</div>
</div>
<div
className="root gutterBottom"
>
<p
className="root body1 gutterBottom author"
<div>
<div
className="root gutterBottom"
>
Lukas
</p>
<p
className="root body1"
>
What's up?
</p>
<p
className="root body1 gutterBottom author"
>
Lukas
</p>
<p
className="root body1"
>
What's up?
</p>
</div>
</div>
</div>
</div>
@@ -0,0 +1,181 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders comment stream 1`] = `
<div
className="root"
>
<div>
<h1
className="root heading1 gutterBottom"
>
Talk NEO
</h1>
<form
autoComplete="off"
onSubmit={[Function]}
>
<div>
<textarea
className="textarea"
name="body"
onChange={[Function]}
value=""
/>
</div>
<div
className="postButtonContainer"
>
<button
className="root root primary"
disabled={false}
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
>
Post
</button>
</div>
</form>
<div>
<div
className="root gutterBottom"
>
<p
className="root body1 gutterBottom author"
>
Markus
</p>
<p
className="root body1"
>
Joining Too
</p>
</div>
<div
style={
Object {
"marginBottom": "8px",
"marginLeft": "16px",
"marginTop": "8px",
}
}
>
<div
className="root gutterBottom"
>
<p
className="root body1 gutterBottom author"
>
Lukas
</p>
<p
className="root body1"
>
What's up?
</p>
</div>
<button
className="root root invert fullWidth secondary"
id="talk-reply-list--show-all--comment-0"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
>
Show All Replies
</button>
</div>
</div>
</div>
</div>
`;
exports[`show all replies 1`] = `
<div
className="root"
>
<div>
<h1
className="root heading1 gutterBottom"
>
Talk NEO
</h1>
<form
autoComplete="off"
onSubmit={[Function]}
>
<div>
<textarea
className="textarea"
name="body"
onChange={[Function]}
value=""
/>
</div>
<div
className="postButtonContainer"
>
<button
className="root root primary"
disabled={false}
onBlur={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
>
Post
</button>
</div>
</form>
<div>
<div
className="root gutterBottom"
>
<p
className="root body1 gutterBottom author"
>
Markus
</p>
<p
className="root body1"
>
Joining Too
</p>
</div>
<div
style={
Object {
"marginBottom": "8px",
"marginLeft": "16px",
"marginTop": "8px",
}
}
>
<div
className="root gutterBottom"
>
<p
className="root body1 gutterBottom author"
>
Lukas
</p>
<p
className="root body1"
>
What's up?
</p>
</div>
<button
className="root root invert fullWidth secondary"
id="talk-reply-list--show-all--comment-0"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
>
Show All Replies
</button>
</div>
</div>
</div>
</div>
`;
@@ -3,7 +3,6 @@ import { createFetch } from "relay-local-schema";
import {
commitLocalUpdate,
Environment,
FetchFunction,
Network,
RecordProxy,
RecordSource,
+30
View File
@@ -49,3 +49,33 @@ export const assets = [
},
},
];
export const commentWithReplies = {
id: "comment-with-replies",
author: users[0],
body: "I like yoghurt",
createdAt: "2018-07-06T18:24:00",
replies: {
edges: [
{ node: comments[0], cursor: comments[0].createdAt },
{ node: comments[1], cursor: comments[1].createdAt },
],
pageInfo: {
hasNextPage: false,
},
},
};
export const assetWithReplies = {
id: "asset-with-replies",
isClosed: false,
comments: {
edges: [
{ node: comments[0], cursor: comments[0].createdAt },
{ node: commentWithReplies, cursor: commentWithReplies.createdAt },
],
pageInfo: {
hasNextPage: false,
},
},
};
@@ -82,7 +82,7 @@ it("renders comment stream", async () => {
it("loads more comments", async () => {
testRenderer.root
.findByProps({ id: "talk-stream--loadmore" })
.findByProps({ id: "talk-stream--load-more" })
.props.onClick();
// Wait for loading.
@@ -0,0 +1,42 @@
import React from "react";
import TestRenderer from "react-test-renderer";
import { RecordProxy } from "relay-runtime";
import { timeout } from "talk-common/utils";
import { TalkContext, TalkContextProvider } from "talk-framework/lib/bootstrap";
import AppQuery from "talk-stream/queries/AppQuery";
import createEnvironment from "./createEnvironment";
import { assetWithReplies } from "./fixtures";
const resolvers = {
Query: {
asset: () => assetWithReplies,
},
};
const environment = createEnvironment({
// Set this to true, to see graphql responses.
logNetwork: false,
resolvers,
initLocalState: (localRecord: RecordProxy) => {
localRecord.setValue(assetWithReplies.id, "assetID");
},
});
const context: TalkContext = {
relayEnvironment: environment,
localeMessages: [],
};
const testRenderer = TestRenderer.create(
<TalkContextProvider value={context}>
<AppQuery />
</TalkContextProvider>
);
it("renders comment stream", async () => {
// Wait for loading.
await timeout();
expect(testRenderer.toJSON()).toMatchSnapshot();
});
@@ -0,0 +1,100 @@
import React from "react";
import TestRenderer from "react-test-renderer";
import { RecordProxy } from "relay-runtime";
import sinon from "sinon";
import { timeout } from "talk-common/utils";
import { TalkContext, TalkContextProvider } from "talk-framework/lib/bootstrap";
import AppQuery from "talk-stream/queries/AppQuery";
import createEnvironment from "./createEnvironment";
import { assets, comments } from "./fixtures";
const assetStub = {
...assets[0],
comments: {
pageInfo: {
hasNextPage: false,
},
edges: [
{
node: {
...comments[0],
replies: {
edges: sinon
.stub()
.onFirstCall()
.returns([
{
node: comments[1],
cursor: comments[1].createdAt,
},
])
.onSecondCall()
.returns([
{
node: comments[2],
cursor: comments[2].createdAt,
},
]),
pageInfo: sinon
.stub()
.onFirstCall()
.returns({
endCursor: comments[1].createdAt,
hasNextPage: true,
})
.onSecondCall()
.returns({
endCursor: comments[2].createdAt,
hasNextPage: false,
}),
},
},
cursor: comments[0].createdAt,
},
],
},
};
const resolvers = {
Query: {
asset: () => assetStub,
},
};
const environment = createEnvironment({
// Set this to true, to see graphql responses.
logNetwork: false,
resolvers,
initLocalState: (localRecord: RecordProxy) => {
localRecord.setValue(assetStub.id, "assetID");
},
});
const context: TalkContext = {
relayEnvironment: environment,
localeMessages: [],
};
const testRenderer = TestRenderer.create(
<TalkContextProvider value={context}>
<AppQuery />
</TalkContextProvider>
);
it("renders comment stream", async () => {
// Wait for loading.
await timeout();
expect(testRenderer.toJSON()).toMatchSnapshot();
});
it("show all replies", async () => {
testRenderer.root
.findByProps({ id: `talk-reply-list--show-all--${comments[0].id}` })
.props.onClick();
// Wait for loading.
await timeout();
expect(testRenderer.toJSON()).toMatchSnapshot();
});