follow-button.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import assert from 'assert';
  2. import React from 'react'; // jshint ignore:line
  3. import FollowButton from 'misago/components/profile/follow-button'; // jshint ignore:line
  4. import reducer, { patchProfile } from 'misago/reducers/profile';
  5. import snackbar from 'misago/services/snackbar';
  6. import store from 'misago/services/store';
  7. import * as testUtils from 'misago/utils/test-utils';
  8. let snackbarStore = null;
  9. let profileMock = {
  10. is_followed: false,
  11. followers: 0,
  12. api_url: {
  13. follow: '/test-api/users/123/follow/'
  14. }
  15. };
  16. describe("Follow Button", function() {
  17. beforeEach(function() {
  18. snackbarStore = testUtils.snackbarStoreMock();
  19. snackbar.init(snackbarStore);
  20. store.constructor();
  21. store.addReducer('profile', reducer, profileMock);
  22. store.addReducer('auth', function(state, action) {
  23. if (action || true) {
  24. return {};
  25. }
  26. }, {});
  27. store.addReducer('tick', function(state, action) {
  28. if (action || true) {
  29. return {'tick': 123};
  30. }
  31. }, {});
  32. store.init();
  33. });
  34. afterEach(function() {
  35. testUtils.unmountComponents();
  36. testUtils.snackbarClear(snackbar);
  37. $.mockjax.clear();
  38. });
  39. it("renders unfollowed", function() {
  40. /* jshint ignore:start */
  41. testUtils.render(<FollowButton profile={profileMock} />);
  42. /* jshint ignore:end */
  43. let element = $('#test-mount .btn-follow');
  44. assert.ok(element.length, "component renders");
  45. assert.equal(element.find('.material-icon').text(), 'favorite_border',
  46. "button has valid icon");
  47. assert.ok(element.text().indexOf("Follow") > 0,
  48. "button has valid label");
  49. });
  50. it("renders followed", function() {
  51. /* jshint ignore:start */
  52. let followedProfile = Object.assign({}, profileMock, {is_followed: true});
  53. testUtils.render(<FollowButton profile={followedProfile} />);
  54. /* jshint ignore:end */
  55. let element = $('#test-mount .btn-following');
  56. assert.ok(element.length, "component renders");
  57. assert.equal(element.find('.material-icon').text(), 'favorite',
  58. "button has valid icon");
  59. assert.ok(element.text().indexOf("Following") > 0,
  60. "button has valid label");
  61. });
  62. it("handles backend error", function(done) {
  63. $.mockjax({
  64. url: profileMock.api_url.follow,
  65. status: 500
  66. });
  67. /* jshint ignore:start */
  68. testUtils.render(<FollowButton profile={profileMock} />);
  69. /* jshint ignore:end */
  70. testUtils.simulateClick('#test-mount .btn-follow');
  71. snackbarStore.callback(function(message) {
  72. assert.deepEqual(message, {
  73. message: "Unknown error has occured.",
  74. type: 'error'
  75. }, "error message was shown");
  76. done();
  77. });
  78. });
  79. it("handles backend rejection", function(done) {
  80. $.mockjax({
  81. url: profileMock.api_url.follow,
  82. status: 400,
  83. responseText: {
  84. detail: "You can't follow yourself!"
  85. }
  86. });
  87. /* jshint ignore:start */
  88. testUtils.render(<FollowButton profile={profileMock} />);
  89. /* jshint ignore:end */
  90. testUtils.simulateClick('#test-mount .btn-follow');
  91. snackbarStore.callback(function(message) {
  92. assert.deepEqual(message, {
  93. message: "You can't follow yourself!",
  94. type: 'error'
  95. }, "error message was shown");
  96. done();
  97. });
  98. });
  99. it("handles follow", function(done) {
  100. $.mockjax({
  101. url: profileMock.api_url.follow,
  102. status: 200,
  103. responseText: {
  104. detail: 'ok'
  105. }
  106. });
  107. /* jshint ignore:start */
  108. testUtils.render(<FollowButton profile={profileMock} />);
  109. /* jshint ignore:end */
  110. testUtils.simulateClick('#test-mount .btn-follow');
  111. window.setTimeout(function() {
  112. let state = store.getState().profile;
  113. assert.ok(state.is_followed, "followed flag was set");
  114. assert.equal(state.followers, 1, "followers count was increased");
  115. assert.equal(state.detail, 'ok', "profile was synced with backend state");
  116. done();
  117. }, 200);
  118. });
  119. it("handles unfollow", function(done) {
  120. $.mockjax({
  121. url: profileMock.api_url.follow,
  122. status: 200,
  123. responseText: {
  124. detail: 'ok'
  125. }
  126. });
  127. store.dispatch(patchProfile({
  128. is_followed: true,
  129. followers: 1
  130. }));
  131. /* jshint ignore:start */
  132. let followedProfile = Object.assign({}, profileMock, {
  133. is_followed: true,
  134. followers: 1
  135. });
  136. testUtils.render(<FollowButton profile={followedProfile} />);
  137. /* jshint ignore:end */
  138. testUtils.simulateClick('#test-mount .btn-following');
  139. window.setTimeout(function() {
  140. let state = store.getState().profile;
  141. assert.ok(!state.is_followed, "followed flag was unset");
  142. assert.equal(state.followers, 0, "followers count was decreased");
  143. assert.equal(state.detail, 'ok', "profile was synced with backend state");
  144. done();
  145. }, 200);
  146. });
  147. });