decidim-comments 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/app/assets/javascripts/decidim/comments/bundle.js +43 -44
- data/app/assets/javascripts/decidim/comments/bundle.js.map +1 -1
- data/app/commands/decidim/comments/vote_comment.rb +38 -0
- data/app/frontend/application/icon.component.jsx +9 -4
- data/app/frontend/application/icon.component.test.jsx +12 -2
- data/app/frontend/comments/add_comment_form.component.jsx +43 -11
- data/app/frontend/comments/add_comment_form.mutation.graphql +1 -4
- data/app/frontend/comments/comment.component.jsx +67 -7
- data/app/frontend/comments/comment.component.test.jsx +49 -1
- data/app/frontend/comments/comment_data.fragment.graphql +3 -0
- data/app/frontend/comments/comment_order_selector.component.jsx +51 -6
- data/app/frontend/comments/comment_order_selector.component.test.jsx +12 -1
- data/app/frontend/comments/comment_thread.component.jsx +11 -5
- data/app/frontend/comments/comment_thread.component.test.jsx +13 -3
- data/app/frontend/comments/comment_thread.fragment.graphql +1 -3
- data/app/frontend/comments/comments.component.jsx +37 -11
- data/app/frontend/comments/comments.component.test.jsx +44 -7
- data/app/frontend/comments/comments.query.graphql +2 -2
- data/app/frontend/comments/down_vote.fragment.graphql +6 -0
- data/app/frontend/comments/down_vote.mutation.graphql +7 -0
- data/app/frontend/comments/down_vote_button.component.jsx +84 -0
- data/app/frontend/comments/down_vote_button.component.test.jsx +48 -0
- data/app/frontend/comments/up_vote.fragment.graphql +6 -0
- data/app/frontend/comments/up_vote.mutation.graphql +7 -0
- data/app/frontend/comments/up_vote_button.component.jsx +84 -0
- data/app/frontend/comments/up_vote_button.component.test.jsx +48 -0
- data/app/frontend/comments/vote_button.component.jsx +19 -0
- data/app/frontend/comments/vote_button_component.test.jsx +38 -0
- data/app/frontend/support/generate_comments_data.js +7 -2
- data/app/helpers/decidim/comments/comments_helper.rb +1 -1
- data/app/models/decidim/comments/application_record.rb +9 -0
- data/app/models/decidim/comments/comment.rb +19 -4
- data/app/models/decidim/comments/comment_vote.rb +22 -0
- data/app/models/decidim/comments/seed.rb +27 -0
- data/app/queries/decidim/comments/comments_with_replies.rb +88 -0
- data/app/resolvers/decidim/comments/vote_comment_resolver.rb +20 -0
- data/app/types/decidim/comments/comment_mutation_type.rb +19 -0
- data/app/types/decidim/comments/comment_type.rb +38 -2
- data/config/locales/en.yml +1 -0
- data/db/migrate/20161130143508_create_comments.rb +4 -2
- data/db/migrate/20161219150806_create_comment_votes.rb +13 -0
- data/lib/decidim/comments/mutation_extensions.rb +9 -0
- data/lib/decidim/comments/query_extensions.rb +3 -5
- data/lib/decidim/comments/test/factories.rb +22 -0
- metadata +26 -49
@@ -5,6 +5,7 @@ import gql from 'graphql-tag';
|
|
5
5
|
import { Comments } from './comments.component';
|
6
6
|
import CommentThread from './comment_thread.component';
|
7
7
|
import AddCommentForm from './add_comment_form.component';
|
8
|
+
import CommentOrderSelector from './comment_order_selector.component';
|
8
9
|
|
9
10
|
import commentsQuery from './comments.query.graphql'
|
10
11
|
|
@@ -18,6 +19,8 @@ describe('<Comments />', () => {
|
|
18
19
|
let currentUser = null;
|
19
20
|
const commentableId = "1";
|
20
21
|
const commentableType = "Decidim::ParticipatoryProcess";
|
22
|
+
const orderBy = "older";
|
23
|
+
const reorderComments = () => {};
|
21
24
|
|
22
25
|
const commentThreadFragment = gql`
|
23
26
|
fragment CommentThread on Comment {
|
@@ -25,12 +28,14 @@ describe('<Comments />', () => {
|
|
25
28
|
}
|
26
29
|
`;
|
27
30
|
|
31
|
+
stubComponent(CommentOrderSelector)
|
32
|
+
|
28
33
|
stubComponent(CommentThread, {
|
29
34
|
fragments: {
|
30
35
|
comment: commentThreadFragment
|
31
36
|
}
|
32
37
|
});
|
33
|
-
|
38
|
+
|
34
39
|
stubComponent(AddCommentForm);
|
35
40
|
|
36
41
|
beforeEach(() => {
|
@@ -49,6 +54,7 @@ describe('<Comments />', () => {
|
|
49
54
|
comments: commentsData
|
50
55
|
},
|
51
56
|
variables: {
|
57
|
+
orderBy,
|
52
58
|
commentableId,
|
53
59
|
commentableType
|
54
60
|
}
|
@@ -58,14 +64,20 @@ describe('<Comments />', () => {
|
|
58
64
|
comments = result.comments;
|
59
65
|
});
|
60
66
|
|
67
|
+
it("should render loading-comments calss and the respective loading text", () => {
|
68
|
+
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{}} reorderComments={reorderComments} orderBy={orderBy} loading />);
|
69
|
+
expect(wrapper.find('.loading-comments')).to.be.present();
|
70
|
+
expect(wrapper.find('h2')).to.have.text("Loading comments ...");
|
71
|
+
});
|
72
|
+
|
61
73
|
it("should render a div of id comments", () => {
|
62
|
-
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{}} />);
|
74
|
+
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{}} reorderComments={reorderComments} orderBy={orderBy} />);
|
63
75
|
expect(wrapper.find('#comments')).to.be.present();
|
64
76
|
});
|
65
77
|
|
66
78
|
describe("should render a CommentThread component for each comment", () => {
|
67
79
|
it("and pass filter comment data as a prop to it", () => {
|
68
|
-
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{}} />);
|
80
|
+
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{}} reorderComments={reorderComments} orderBy={orderBy} />);
|
69
81
|
expect(wrapper).to.have.exactly(comments.length).descendants(CommentThread);
|
70
82
|
wrapper.find(CommentThread).forEach((node, idx) => {
|
71
83
|
expect(node).to.have.prop("comment").deep.equal(filter(commentThreadFragment, comments[idx]));
|
@@ -73,22 +85,30 @@ describe('<Comments />', () => {
|
|
73
85
|
});
|
74
86
|
|
75
87
|
it("and pass the currentUser as a prop to it", () => {
|
76
|
-
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{}} />);
|
88
|
+
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{}} reorderComments={reorderComments} orderBy={orderBy} />);
|
77
89
|
expect(wrapper).to.have.exactly(comments.length).descendants(CommentThread);
|
78
90
|
wrapper.find(CommentThread).forEach((node) => {
|
79
91
|
expect(node).to.have.prop("currentUser").deep.equal(currentUser);
|
80
92
|
});
|
81
93
|
});
|
94
|
+
|
95
|
+
it("and pass the option votable as a prop to it", () => {
|
96
|
+
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{ votable: true }} reorderComments={reorderComments} orderBy={orderBy} />);
|
97
|
+
expect(wrapper).to.have.exactly(comments.length).descendants(CommentThread);
|
98
|
+
wrapper.find(CommentThread).forEach((node) => {
|
99
|
+
expect(node).to.have.prop("votable").equal(true);
|
100
|
+
});
|
101
|
+
});
|
82
102
|
});
|
83
103
|
|
84
104
|
it("should render comments count", () => {
|
85
|
-
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{}} />);
|
105
|
+
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{}} reorderComments={reorderComments} orderBy={orderBy} />);
|
86
106
|
const rex = new RegExp(`${comments.length} comments`);
|
87
107
|
expect(wrapper.find('h2.section-heading')).to.have.text().match(rex);
|
88
108
|
});
|
89
109
|
|
90
110
|
it("should render a AddCommentForm component and pass 'options.arguable' as a prop", () => {
|
91
|
-
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{ arguable: true }} />);
|
111
|
+
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{ arguable: true }} reorderComments={reorderComments} orderBy={orderBy} />);
|
92
112
|
expect(wrapper).to.have.exactly(1).descendants(AddCommentForm);
|
93
113
|
expect(wrapper.find(AddCommentForm)).to.have.prop('arguable').equal(true);
|
94
114
|
});
|
@@ -99,8 +119,25 @@ describe('<Comments />', () => {
|
|
99
119
|
});
|
100
120
|
|
101
121
|
it("should not render a AddCommentForm component", () => {
|
102
|
-
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{}} />);
|
122
|
+
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{}} reorderComments={reorderComments} orderBy={orderBy} />);
|
103
123
|
expect(wrapper.find(AddCommentForm)).not.to.be.present();
|
104
124
|
});
|
105
125
|
});
|
126
|
+
|
127
|
+
describe("should render a CommentOrderSelector component", () => {
|
128
|
+
it("should render a CommentOrderSelector component", () => {
|
129
|
+
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{}} reorderComments={reorderComments} orderBy={orderBy} />);
|
130
|
+
expect(wrapper.find(CommentOrderSelector)).to.be.present();
|
131
|
+
});
|
132
|
+
|
133
|
+
it("and pass the reorderComments as a prop to it", () => {
|
134
|
+
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{}} reorderComments={reorderComments} orderBy={orderBy} />);
|
135
|
+
expect(wrapper.find(CommentOrderSelector)).to.have.prop('reorderComments').deep.equal(reorderComments);
|
136
|
+
});
|
137
|
+
|
138
|
+
it("and pass the orderBy as a prop to it", () => {
|
139
|
+
const wrapper = shallow(<Comments comments={comments} commentableId={commentableId} commentableType={commentableType} currentUser={currentUser} options={{}} reorderComments={reorderComments} orderBy={orderBy} />);
|
140
|
+
expect(wrapper.find(CommentOrderSelector)).to.have.prop('defaultOrderBy').equal('older');
|
141
|
+
});
|
142
|
+
});
|
106
143
|
});
|
@@ -1,9 +1,9 @@
|
|
1
|
-
query GetComments($commentableId: String!, $commentableType: String
|
1
|
+
query GetComments($commentableId: String!, $commentableType: String!, $orderBy: String) {
|
2
2
|
currentUser {
|
3
3
|
name
|
4
4
|
avatarUrl
|
5
5
|
}
|
6
|
-
comments(commentableId: $commentableId, commentableType: $commentableType) {
|
6
|
+
comments(commentableId: $commentableId, commentableType: $commentableType, orderBy: $orderBy) {
|
7
7
|
id
|
8
8
|
...CommentThread
|
9
9
|
}
|
@@ -0,0 +1,84 @@
|
|
1
|
+
import { PropTypes } from 'react';
|
2
|
+
import { propType } from 'graphql-anywhere';
|
3
|
+
import { graphql } from 'react-apollo';
|
4
|
+
import gql from 'graphql-tag';
|
5
|
+
|
6
|
+
import VoteButton from './vote_button.component';
|
7
|
+
|
8
|
+
import downVoteMutation from './down_vote.mutation.graphql';
|
9
|
+
|
10
|
+
import commentFragment from './comment.fragment.graphql';
|
11
|
+
import commentDataFragment from './comment_data.fragment.graphql';
|
12
|
+
import upVoteFragment from './up_vote.fragment.graphql';
|
13
|
+
import downVoteFragment from './down_vote.fragment.graphql';
|
14
|
+
|
15
|
+
export const DownVoteButton = ({ comment: { downVotes, upVoted, downVoted }, downVote }) => (
|
16
|
+
<VoteButton
|
17
|
+
buttonClassName="comment__votes--down"
|
18
|
+
iconName="icon-chevron-bottom"
|
19
|
+
votes={downVotes}
|
20
|
+
voteAction={downVote}
|
21
|
+
disabled={upVoted || downVoted}
|
22
|
+
/>
|
23
|
+
);
|
24
|
+
|
25
|
+
DownVoteButton.fragments = {
|
26
|
+
comment: gql`
|
27
|
+
${downVoteFragment}
|
28
|
+
`
|
29
|
+
};
|
30
|
+
|
31
|
+
DownVoteButton.propTypes = {
|
32
|
+
comment: propType(DownVoteButton.fragments.comment).isRequired,
|
33
|
+
downVote: PropTypes.func.isRequired
|
34
|
+
};
|
35
|
+
|
36
|
+
const DownVoteButtonWithMutation = graphql(gql`
|
37
|
+
${downVoteMutation}
|
38
|
+
${commentFragment}
|
39
|
+
${commentDataFragment}
|
40
|
+
${upVoteFragment}
|
41
|
+
${downVoteFragment}
|
42
|
+
`, {
|
43
|
+
props: ({ ownProps, mutate }) => ({
|
44
|
+
downVote: () => mutate({
|
45
|
+
variables: {
|
46
|
+
id: ownProps.comment.id
|
47
|
+
},
|
48
|
+
optimisticResponse: {
|
49
|
+
__typename: 'Mutation',
|
50
|
+
comment: {
|
51
|
+
__typename: 'CommentMutation',
|
52
|
+
downVote: {
|
53
|
+
__typename: 'Comment',
|
54
|
+
...ownProps.comment,
|
55
|
+
downVotes: ownProps.comment.downVotes + 1,
|
56
|
+
downVoted: true
|
57
|
+
}
|
58
|
+
}
|
59
|
+
},
|
60
|
+
updateQueries: {
|
61
|
+
GetComments: (prev, { mutationResult: { data } }) => {
|
62
|
+
const commentReducer = (comment) => {
|
63
|
+
const replies = comment.replies || [];
|
64
|
+
|
65
|
+
if (comment.id === ownProps.comment.id) {
|
66
|
+
return data.comment.downVote;
|
67
|
+
}
|
68
|
+
return {
|
69
|
+
...comment,
|
70
|
+
replies: replies.map(commentReducer)
|
71
|
+
};
|
72
|
+
};
|
73
|
+
|
74
|
+
return {
|
75
|
+
...prev,
|
76
|
+
comments: prev.comments.map(commentReducer)
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|
80
|
+
})
|
81
|
+
})
|
82
|
+
})(DownVoteButton);
|
83
|
+
|
84
|
+
export default DownVoteButtonWithMutation;
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import { shallow } from 'enzyme';
|
2
|
+
import { filter } from 'graphql-anywhere';
|
3
|
+
import gql from 'graphql-tag';
|
4
|
+
|
5
|
+
import { DownVoteButton } from './down_vote_button.component';
|
6
|
+
|
7
|
+
import VoteButton from './vote_button.component';
|
8
|
+
|
9
|
+
import downVoteFragment from './down_vote.fragment.graphql';
|
10
|
+
|
11
|
+
import stubComponent from '../support/stub_component';
|
12
|
+
import generateCommentsData from '../support/generate_comments_data';
|
13
|
+
|
14
|
+
describe("<DownVoteButton />", () => {
|
15
|
+
let comment = {};
|
16
|
+
const downVote = () => {};
|
17
|
+
|
18
|
+
stubComponent(VoteButton);
|
19
|
+
|
20
|
+
beforeEach(() => {
|
21
|
+
let commentsData = generateCommentsData(1);
|
22
|
+
|
23
|
+
const fragment = gql`
|
24
|
+
${downVoteFragment}
|
25
|
+
`;
|
26
|
+
|
27
|
+
comment = filter(fragment, commentsData[0]);
|
28
|
+
});
|
29
|
+
|
30
|
+
it("should render a VoteButton component with the correct props", () => {
|
31
|
+
const wrapper = shallow(<DownVoteButton comment={comment} downVote={downVote} />);
|
32
|
+
expect(wrapper.find(VoteButton)).to.have.prop("buttonClassName").equal("comment__votes--down");
|
33
|
+
expect(wrapper.find(VoteButton)).to.have.prop("iconName").equal("icon-chevron-bottom");
|
34
|
+
expect(wrapper.find(VoteButton)).to.have.prop("votes").equal(comment.downVotes);
|
35
|
+
});
|
36
|
+
|
37
|
+
it("should pass disabled prop as true if comment downVoted is true", () => {
|
38
|
+
comment.downVoted = true;
|
39
|
+
const wrapper = shallow(<DownVoteButton comment={comment} downVote={downVote} />);
|
40
|
+
expect(wrapper.find(VoteButton)).to.have.prop("disabled").equal(true);
|
41
|
+
});
|
42
|
+
|
43
|
+
it("should pass disabled prop as true if comment downVoted is true", () => {
|
44
|
+
comment.downVoted = true;
|
45
|
+
const wrapper = shallow(<DownVoteButton comment={comment} downVote={downVote} />);
|
46
|
+
expect(wrapper.find(VoteButton)).to.have.prop("disabled").equal(true);
|
47
|
+
});
|
48
|
+
});
|
@@ -0,0 +1,84 @@
|
|
1
|
+
import { PropTypes } from 'react';
|
2
|
+
import { propType } from 'graphql-anywhere';
|
3
|
+
import { graphql } from 'react-apollo';
|
4
|
+
import gql from 'graphql-tag';
|
5
|
+
|
6
|
+
import VoteButton from './vote_button.component';
|
7
|
+
|
8
|
+
import upVoteMutation from './up_vote.mutation.graphql';
|
9
|
+
|
10
|
+
import commentFragment from './comment.fragment.graphql';
|
11
|
+
import commentDataFragment from './comment_data.fragment.graphql';
|
12
|
+
import upVoteFragment from './up_vote.fragment.graphql';
|
13
|
+
import downVoteFragment from './down_vote.fragment.graphql';
|
14
|
+
|
15
|
+
export const UpVoteButton = ({ comment: { upVotes, upVoted, downVoted }, upVote }) => (
|
16
|
+
<VoteButton
|
17
|
+
buttonClassName="comment__votes--up"
|
18
|
+
iconName="icon-chevron-top"
|
19
|
+
votes={upVotes}
|
20
|
+
voteAction={upVote}
|
21
|
+
disabled={upVoted || downVoted}
|
22
|
+
/>
|
23
|
+
);
|
24
|
+
|
25
|
+
UpVoteButton.fragments = {
|
26
|
+
comment: gql`
|
27
|
+
${upVoteFragment}
|
28
|
+
`
|
29
|
+
};
|
30
|
+
|
31
|
+
UpVoteButton.propTypes = {
|
32
|
+
comment: propType(UpVoteButton.fragments.comment).isRequired,
|
33
|
+
upVote: PropTypes.func.isRequired
|
34
|
+
};
|
35
|
+
|
36
|
+
const UpVoteButtonWithMutation = graphql(gql`
|
37
|
+
${upVoteMutation}
|
38
|
+
${commentFragment}
|
39
|
+
${commentDataFragment}
|
40
|
+
${upVoteFragment}
|
41
|
+
${downVoteFragment}
|
42
|
+
`, {
|
43
|
+
props: ({ ownProps, mutate }) => ({
|
44
|
+
upVote: () => mutate({
|
45
|
+
variables: {
|
46
|
+
id: ownProps.comment.id
|
47
|
+
},
|
48
|
+
optimisticResponse: {
|
49
|
+
__typename: 'Mutation',
|
50
|
+
comment: {
|
51
|
+
__typename: 'CommentMutation',
|
52
|
+
upVote: {
|
53
|
+
__typename: 'Comment',
|
54
|
+
...ownProps.comment,
|
55
|
+
upVotes: ownProps.comment.upVotes + 1,
|
56
|
+
upVoted: true
|
57
|
+
}
|
58
|
+
}
|
59
|
+
},
|
60
|
+
updateQueries: {
|
61
|
+
GetComments: (prev, { mutationResult: { data } }) => {
|
62
|
+
const commentReducer = (comment) => {
|
63
|
+
const replies = comment.replies || [];
|
64
|
+
|
65
|
+
if (comment.id === ownProps.comment.id) {
|
66
|
+
return data.comment.upVote;
|
67
|
+
}
|
68
|
+
return {
|
69
|
+
...comment,
|
70
|
+
replies: replies.map(commentReducer)
|
71
|
+
};
|
72
|
+
};
|
73
|
+
|
74
|
+
return {
|
75
|
+
...prev,
|
76
|
+
comments: prev.comments.map(commentReducer)
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|
80
|
+
})
|
81
|
+
})
|
82
|
+
})(UpVoteButton);
|
83
|
+
|
84
|
+
export default UpVoteButtonWithMutation;
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import { shallow } from 'enzyme';
|
2
|
+
import { filter } from 'graphql-anywhere';
|
3
|
+
import gql from 'graphql-tag';
|
4
|
+
|
5
|
+
import { UpVoteButton } from './up_vote_button.component';
|
6
|
+
|
7
|
+
import VoteButton from './vote_button.component';
|
8
|
+
|
9
|
+
import upVoteFragment from './up_vote.fragment.graphql';
|
10
|
+
|
11
|
+
import stubComponent from '../support/stub_component';
|
12
|
+
import generateCommentsData from '../support/generate_comments_data';
|
13
|
+
|
14
|
+
describe("<UpVoteButton />", () => {
|
15
|
+
let comment = {};
|
16
|
+
const upVote = () => {};
|
17
|
+
|
18
|
+
stubComponent(VoteButton);
|
19
|
+
|
20
|
+
beforeEach(() => {
|
21
|
+
let commentsData = generateCommentsData(1);
|
22
|
+
|
23
|
+
const fragment = gql`
|
24
|
+
${upVoteFragment}
|
25
|
+
`;
|
26
|
+
|
27
|
+
comment = filter(fragment, commentsData[0]);
|
28
|
+
});
|
29
|
+
|
30
|
+
it("should render a VoteButton component with the correct props", () => {
|
31
|
+
const wrapper = shallow(<UpVoteButton comment={comment} upVote={upVote} />);
|
32
|
+
expect(wrapper.find(VoteButton)).to.have.prop("buttonClassName").equal("comment__votes--up");
|
33
|
+
expect(wrapper.find(VoteButton)).to.have.prop("iconName").equal("icon-chevron-top");
|
34
|
+
expect(wrapper.find(VoteButton)).to.have.prop("votes").equal(comment.upVotes);
|
35
|
+
});
|
36
|
+
|
37
|
+
it("should pass disabled prop as true if comment upVoted is true", () => {
|
38
|
+
comment.upVoted = true;
|
39
|
+
const wrapper = shallow(<UpVoteButton comment={comment} upVote={upVote} />);
|
40
|
+
expect(wrapper.find(VoteButton)).to.have.prop("disabled").equal(true);
|
41
|
+
});
|
42
|
+
|
43
|
+
it("should pass disabled prop as true if comment downVoted is true", () => {
|
44
|
+
comment.downVoted = true;
|
45
|
+
const wrapper = shallow(<UpVoteButton comment={comment} upVote={upVote} />);
|
46
|
+
expect(wrapper.find(VoteButton)).to.have.prop("disabled").equal(true);
|
47
|
+
});
|
48
|
+
});
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { PropTypes } from 'react';
|
2
|
+
import Icon from '../application/icon.component';
|
3
|
+
|
4
|
+
const VoteButton = ({ buttonClassName, iconName, votes, voteAction, disabled }) => (
|
5
|
+
<button className={buttonClassName} onClick={() => voteAction()} disabled={disabled}>
|
6
|
+
<Icon name={iconName} iconExtraClassName="icon--small" />
|
7
|
+
{ ` ${votes}` }
|
8
|
+
</button>
|
9
|
+
);
|
10
|
+
|
11
|
+
VoteButton.propTypes = {
|
12
|
+
buttonClassName: PropTypes.string.isRequired,
|
13
|
+
iconName: PropTypes.string.isRequired,
|
14
|
+
votes: PropTypes.number.isRequired,
|
15
|
+
voteAction: PropTypes.func.isRequired,
|
16
|
+
disabled: PropTypes.bool
|
17
|
+
};
|
18
|
+
|
19
|
+
export default VoteButton;
|