cards.methods.tests.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /* eslint-env mocha */
  2. import { expect } from 'chai';
  3. import sinon from 'sinon';
  4. import { Meteor } from 'meteor/meteor';
  5. import '/models/cards';
  6. // Helpers to access method handlers
  7. const voteHandler = () => Meteor.server.method_handlers['cards.vote'];
  8. const pokerVoteHandler = () => Meteor.server.method_handlers['cards.pokerVote'];
  9. // Preserve originals to restore after stubbing
  10. const origGetCard = ReactiveCache.getCard;
  11. const origGetBoard = ReactiveCache.getBoard;
  12. describe('cards methods security', function() {
  13. let updateStub;
  14. beforeEach(function() {
  15. // Stub collection update to capture modifiers
  16. updateStub = sinon.stub(Cards, 'update').returns(1);
  17. });
  18. afterEach(function() {
  19. if (updateStub) updateStub.restore();
  20. ReactiveCache.getCard = origGetCard;
  21. ReactiveCache.getBoard = origGetBoard;
  22. });
  23. describe('cards.vote', function() {
  24. it('denies non-member when allowNonBoardMembers=false', function() {
  25. const cardId = 'card1';
  26. const callerId = 'user-nonmember';
  27. const board = { hasMember: id => id === 'someone-else' };
  28. const card = { _id: cardId, boardId: 'board1', vote: { allowNonBoardMembers: false } };
  29. ReactiveCache.getCard = () => card;
  30. ReactiveCache.getBoard = () => board;
  31. const callMethod = () => voteHandler().call({ userId: callerId }, cardId, true);
  32. expect(callMethod).to.throw();
  33. expect(updateStub.called).to.equal(false);
  34. });
  35. it('allows non-member only for own userId when allowNonBoardMembers=true', function() {
  36. const cardId = 'card2';
  37. const callerId = 'user-guest';
  38. const board = { hasMember: id => id === 'someone-else' };
  39. const card = { _id: cardId, boardId: 'board2', vote: { allowNonBoardMembers: true } };
  40. ReactiveCache.getCard = () => card;
  41. ReactiveCache.getBoard = () => board;
  42. voteHandler().call({ userId: callerId }, cardId, true);
  43. expect(updateStub.calledOnce).to.equal(true);
  44. const [, modifier] = updateStub.getCall(0).args;
  45. expect(modifier.$addToSet['vote.positive']).to.equal(callerId);
  46. expect(modifier.$pull['vote.negative']).to.equal(callerId);
  47. expect(modifier.$set.modifiedAt).to.be.instanceOf(Date);
  48. expect(modifier.$set.dateLastActivity).to.be.instanceOf(Date);
  49. });
  50. it('ensures member votes only affect caller userId', function() {
  51. const cardId = 'card3';
  52. const callerId = 'member1';
  53. const otherId = 'member2';
  54. const board = { hasMember: id => (id === callerId || id === otherId) };
  55. const card = { _id: cardId, boardId: 'board3', vote: { allowNonBoardMembers: false } };
  56. ReactiveCache.getCard = () => card;
  57. ReactiveCache.getBoard = () => board;
  58. voteHandler().call({ userId: callerId }, cardId, true);
  59. expect(updateStub.calledOnce).to.equal(true);
  60. const [, modifier] = updateStub.getCall(0).args;
  61. // Only callerId present in modifier
  62. expect(modifier.$addToSet['vote.positive']).to.equal(callerId);
  63. expect(modifier.$pull['vote.negative']).to.equal(callerId);
  64. });
  65. });
  66. describe('cards.pokerVote', function() {
  67. it('denies non-member when allowNonBoardMembers=false', function() {
  68. const cardId = 'card4';
  69. const callerId = 'nm';
  70. const board = { hasMember: id => id === 'someone-else' };
  71. const card = { _id: cardId, boardId: 'board4', poker: { allowNonBoardMembers: false } };
  72. ReactiveCache.getCard = () => card;
  73. ReactiveCache.getBoard = () => board;
  74. const callMethod = () => pokerVoteHandler().call({ userId: callerId }, cardId, 'five');
  75. expect(callMethod).to.throw();
  76. expect(updateStub.called).to.equal(false);
  77. });
  78. it('allows non-member only for own userId when allowNonBoardMembers=true', function() {
  79. const cardId = 'card5';
  80. const callerId = 'guest';
  81. const board = { hasMember: id => id === 'someone-else' };
  82. const card = { _id: cardId, boardId: 'board5', poker: { allowNonBoardMembers: true } };
  83. ReactiveCache.getCard = () => card;
  84. ReactiveCache.getBoard = () => board;
  85. pokerVoteHandler().call({ userId: callerId }, cardId, 'eight');
  86. expect(updateStub.calledOnce).to.equal(true);
  87. const [, modifier] = updateStub.getCall(0).args;
  88. expect(modifier.$addToSet['poker.eight']).to.equal(callerId);
  89. // Ensure removal from other buckets includes callerId
  90. expect(modifier.$pull['poker.one']).to.equal(callerId);
  91. expect(modifier.$set.modifiedAt).to.be.instanceOf(Date);
  92. expect(modifier.$set.dateLastActivity).to.be.instanceOf(Date);
  93. });
  94. });
  95. });