UNPKG

mattermost-redux

Version:

Common code (API client, Redux stores, logic, utility functions) for building a Mattermost client

1,403 lines (1,234 loc) 89.2 kB
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import assert from 'assert'; import {Posts, Preferences} from '../../constants'; import * as Selectors from 'selectors/entities/posts'; import {makeGetProfilesForReactions} from 'selectors/entities/users'; import TestHelper from 'test/test_helper'; import deepFreezeAndThrowOnMutation from 'utils/deep_freeze'; describe('Selectors.Posts', () => { const user1 = TestHelper.fakeUserWithId(); user1.notify_props = {}; const profiles = {}; profiles[user1.id] = user1; const posts = { a: {id: 'a', channel_id: '1', create_at: 1, highlight: false, user_id: user1.id}, b: {id: 'b', channel_id: '1', create_at: 2, highlight: false, user_id: user1.id}, c: {id: 'c', root_id: 'a', channel_id: '1', create_at: 3, highlight: false, user_id: 'b'}, d: {id: 'd', root_id: 'b', channel_id: '1', create_at: 4, highlight: false, user_id: 'b'}, e: {id: 'e', root_id: 'a', channel_id: '1', create_at: 5, highlight: false, user_id: 'b'}, f: {id: 'f', channel_id: '2', create_at: 6, highlight: false, user_id: 'b'}, }; const reaction1 = {user_id: user1.id, emoji_name: '+1'}; const reactionA = {[reaction1.user_id + '-' + reaction1.emoji_name]: reaction1}; const reactions = { a: reactionA, }; const testState = deepFreezeAndThrowOnMutation({ entities: { users: { currentUserId: user1.id, profiles, }, posts: { posts, postsInChannel: { 1: [ {order: ['e', 'd', 'c', 'b', 'a'], recent: true}, ], 2: [ {order: ['f'], recent: true}, ], }, postsInThread: { a: ['c', 'e'], b: ['d'], }, reactions, }, preferences: { myPreferences: {}, }, }, }); it('should return the most recent post for each channel', () => { const lastPosts = Selectors.getLastPostPerChannel(testState); assert.deepEqual(lastPosts, {1: posts.e, 2: posts.f}); }); it('should return single post with no children', () => { const getPostsForThread = Selectors.makeGetPostsForThread(); assert.deepEqual(getPostsForThread(testState, {channelId: '2', rootId: 'f'}), [posts.f]); }); it('should return post with children', () => { const getPostsForThread = Selectors.makeGetPostsForThread(); assert.deepEqual(getPostsForThread(testState, {channelId: '1', rootId: 'a'}), [posts.e, posts.c, posts.a]); }); it('should return memoized result for identical props', () => { const getPostsForThread = Selectors.makeGetPostsForThread(); const props = {channelId: '1', rootId: 'a'}; const result = getPostsForThread(testState, props); assert.equal(result, getPostsForThread(testState, props)); }); it('should return memoized result for multiple selectors with different props', () => { const getPostsForThread1 = Selectors.makeGetPostsForThread(); const getPostsForThread2 = Selectors.makeGetPostsForThread(); const props1 = {channelId: '1', rootId: 'a'}; const result1 = getPostsForThread1(testState, props1); const props2 = {channelId: '1', rootId: 'b'}; const result2 = getPostsForThread2(testState, props2); assert.equal(result1, getPostsForThread1(testState, props1)); assert.equal(result2, getPostsForThread2(testState, props2)); }); it('should return reactions for post', () => { const getReactionsForPost = Selectors.makeGetReactionsForPost(); assert.deepEqual(getReactionsForPost(testState, posts.a.id), reactionA); }); it('should return profiles for reactions', () => { const getProfilesForReactions = makeGetProfilesForReactions(); assert.deepEqual(getProfilesForReactions(testState, [reaction1]), [user1]); }); it('get posts in channel', () => { const post1 = { ...posts.a, isFirstReply: false, isLastReply: false, previousPostIsComment: false, commentedOnPost: undefined, consecutivePostByUser: false, replyCount: 2, isCommentMention: false, }; const post2 = { ...posts.b, isFirstReply: false, isLastReply: false, previousPostIsComment: false, commentedOnPost: undefined, consecutivePostByUser: true, replyCount: 1, isCommentMention: false, }; const post3 = { ...posts.c, isFirstReply: true, isLastReply: true, previousPostIsComment: false, commentedOnPost: posts.a, consecutivePostByUser: false, replyCount: 2, isCommentMention: false, }; const post4 = { ...posts.d, isFirstReply: true, isLastReply: true, previousPostIsComment: true, commentedOnPost: posts.b, consecutivePostByUser: true, replyCount: 1, isCommentMention: false, }; const post5 = { ...posts.e, isFirstReply: true, isLastReply: true, previousPostIsComment: true, commentedOnPost: posts.a, consecutivePostByUser: true, replyCount: 2, isCommentMention: false, }; const getPostsInChannel = Selectors.makeGetPostsInChannel(); assert.deepEqual(getPostsInChannel(testState, '1', 30), [post5, post4, post3, post2, post1]); }); it('get posts around post in channel', () => { const post1 = { ...posts.a, isFirstReply: false, isLastReply: false, previousPostIsComment: false, commentedOnPost: undefined, consecutivePostByUser: false, replyCount: 2, isCommentMention: false, }; const post2 = { ...posts.b, isFirstReply: false, isLastReply: false, previousPostIsComment: false, commentedOnPost: undefined, consecutivePostByUser: true, replyCount: 1, isCommentMention: false, }; const post3 = { ...posts.c, isFirstReply: true, isLastReply: true, previousPostIsComment: false, commentedOnPost: posts.a, consecutivePostByUser: false, replyCount: 2, isCommentMention: false, highlight: true, }; const post4 = { ...posts.d, isFirstReply: true, isLastReply: true, previousPostIsComment: true, commentedOnPost: posts.b, consecutivePostByUser: true, replyCount: 1, isCommentMention: false, }; const post5 = { ...posts.e, isFirstReply: true, isLastReply: true, previousPostIsComment: true, commentedOnPost: posts.a, consecutivePostByUser: true, replyCount: 2, isCommentMention: false, }; const getPostsAroundPost = Selectors.makeGetPostsAroundPost(); assert.deepEqual(getPostsAroundPost(testState, post3.id, '1'), [post5, post4, post3, post2, post1]); }); it('get posts in channel with notify comments as any', () => { const userAny = TestHelper.fakeUserWithId(); userAny.notify_props = {comments: 'any'}; const profilesAny = {}; profilesAny[userAny.id] = userAny; const postsAny = { a: {id: 'a', channel_id: '1', create_at: 1, highlight: false, user_id: userAny.id}, b: {id: 'b', channel_id: '1', create_at: 2, highlight: false, user_id: 'b'}, c: {id: 'c', root_id: 'a', channel_id: '1', create_at: 3, highlight: false, user_id: 'b'}, d: {id: 'd', root_id: 'b', channel_id: '1', create_at: 4, highlight: false, user_id: userAny.id}, e: {id: 'e', root_id: 'a', channel_id: '1', create_at: 5, highlight: false, user_id: 'b'}, f: {id: 'f', root_id: 'b', channel_id: '1', create_at: 6, highlight: false, user_id: 'b'}, g: {id: 'g', channel_id: '2', create_at: 7, highlight: false, user_id: 'b'}, }; const testStateAny = deepFreezeAndThrowOnMutation({ entities: { users: { currentUserId: userAny.id, profiles: profilesAny, }, posts: { posts: postsAny, postsInChannel: { 1: [ {order: ['f', 'e', 'd', 'c', 'b', 'a'], recent: true}, ], 2: [ {order: ['g'], recent: true}, ], }, postsInThread: { a: ['c', 'e'], b: ['d', 'f'], }, }, preferences: { myPreferences: {}, }, }, }); const post1 = { ...postsAny.a, isFirstReply: false, isLastReply: false, previousPostIsComment: false, commentedOnPost: undefined, consecutivePostByUser: false, replyCount: 2, isCommentMention: false, }; const post2 = { ...postsAny.b, isFirstReply: false, isLastReply: false, previousPostIsComment: false, commentedOnPost: undefined, consecutivePostByUser: false, replyCount: 2, isCommentMention: true, }; const post3 = { ...postsAny.c, isFirstReply: true, isLastReply: true, previousPostIsComment: false, commentedOnPost: postsAny.a, consecutivePostByUser: true, replyCount: 2, isCommentMention: true, }; const post4 = { ...postsAny.d, isFirstReply: true, isLastReply: true, previousPostIsComment: true, commentedOnPost: postsAny.b, consecutivePostByUser: false, replyCount: 2, isCommentMention: false, }; const post5 = { ...postsAny.e, isFirstReply: true, isLastReply: true, previousPostIsComment: true, commentedOnPost: postsAny.a, consecutivePostByUser: false, replyCount: 2, isCommentMention: true, }; const post6 = { ...postsAny.f, isFirstReply: true, isLastReply: true, previousPostIsComment: true, commentedOnPost: postsAny.b, consecutivePostByUser: true, replyCount: 2, isCommentMention: true, }; const getPostsInChannel = Selectors.makeGetPostsInChannel(); assert.deepEqual(getPostsInChannel(testStateAny, '1'), [post6, post5, post4, post3, post2, post1]); }); it('get posts in channel with notify comments as root', () => { const userRoot = TestHelper.fakeUserWithId(); userRoot.notify_props = {comments: 'root'}; const profilesRoot = {}; profilesRoot[userRoot.id] = userRoot; const postsRoot = { a: {id: 'a', channel_id: '1', create_at: 1, highlight: false, user_id: userRoot.id}, b: {id: 'b', channel_id: '1', create_at: 2, highlight: false, user_id: 'b'}, c: {id: 'c', root_id: 'a', channel_id: '1', create_at: 3, highlight: false, user_id: 'b'}, d: {id: 'd', root_id: 'b', channel_id: '1', create_at: 4, highlight: false, user_id: userRoot.id}, e: {id: 'e', root_id: 'a', channel_id: '1', create_at: 5, highlight: false, user_id: 'b'}, f: {id: 'f', root_id: 'b', channel_id: '1', create_at: 6, highlight: false, user_id: 'b'}, g: {id: 'g', channel_id: '2', create_at: 7, highlight: false, user_id: 'b'}, }; const testStateRoot = deepFreezeAndThrowOnMutation({ entities: { users: { currentUserId: userRoot.id, profiles: profilesRoot, }, posts: { posts: postsRoot, postsInChannel: { 1: [ {order: ['f', 'e', 'd', 'c', 'b', 'a'], recent: true}, ], 2: [ {order: ['g'], recent: true}, ], }, postsInThread: { a: ['c', 'e'], b: ['d', 'f'], }, }, preferences: { myPreferences: {}, }, }, }); const post1 = { ...postsRoot.a, isFirstReply: false, isLastReply: false, previousPostIsComment: false, commentedOnPost: undefined, consecutivePostByUser: false, replyCount: 2, isCommentMention: false, }; const post2 = { ...postsRoot.b, isFirstReply: false, isLastReply: false, previousPostIsComment: false, commentedOnPost: undefined, consecutivePostByUser: false, replyCount: 2, isCommentMention: false, }; const post3 = { ...postsRoot.c, isFirstReply: true, isLastReply: true, previousPostIsComment: false, commentedOnPost: postsRoot.a, consecutivePostByUser: true, replyCount: 2, isCommentMention: true, }; const post4 = { ...postsRoot.d, isFirstReply: true, isLastReply: true, previousPostIsComment: true, commentedOnPost: postsRoot.b, consecutivePostByUser: false, replyCount: 2, isCommentMention: false, }; const post5 = { ...postsRoot.e, isFirstReply: true, isLastReply: true, previousPostIsComment: true, commentedOnPost: postsRoot.a, consecutivePostByUser: false, replyCount: 2, isCommentMention: true, }; const post6 = { ...postsRoot.f, isFirstReply: true, isLastReply: true, previousPostIsComment: true, commentedOnPost: postsRoot.b, consecutivePostByUser: true, replyCount: 2, isCommentMention: false, }; const getPostsInChannel = Selectors.makeGetPostsInChannel(); assert.deepEqual(getPostsInChannel(testStateRoot, '1'), [post6, post5, post4, post3, post2, post1]); }); it('get posts in channel with notify comments as never', () => { const userNever = TestHelper.fakeUserWithId(); userNever.notify_props = {comments: 'never'}; const profilesNever = {}; profilesNever[userNever.id] = userNever; const postsNever = { a: {id: 'a', channel_id: '1', create_at: 1, highlight: false, user_id: userNever.id}, b: {id: 'b', channel_id: '1', create_at: 2, highlight: false, user_id: 'b'}, c: {id: 'c', root_id: 'a', channel_id: '1', create_at: 3, highlight: false, user_id: 'b'}, d: {id: 'd', root_id: 'b', channel_id: '1', create_at: 4, highlight: false, user_id: userNever.id}, e: {id: 'e', root_id: 'a', channel_id: '1', create_at: 5, highlight: false, user_id: 'b'}, f: {id: 'f', root_id: 'b', channel_id: '1', create_at: 6, highlight: false, user_id: 'b'}, g: {id: 'g', channel_id: '2', create_at: 7, highlight: false, user_id: 'b'}, }; const testStateNever = deepFreezeAndThrowOnMutation({ entities: { users: { currentUserId: userNever.id, profiles: profilesNever, }, posts: { posts: postsNever, postsInChannel: { 1: [ {order: ['f', 'e', 'd', 'c', 'b', 'a'], recent: true}, ], 2: [ {order: ['g'], recent: true}, ], }, postsInThread: { a: ['c', 'e'], b: ['d', 'f'], }, }, preferences: { myPreferences: {}, }, }, }); const post1 = { ...postsNever.a, isFirstReply: false, isLastReply: false, previousPostIsComment: false, commentedOnPost: undefined, consecutivePostByUser: false, replyCount: 2, isCommentMention: false, }; const post2 = { ...postsNever.b, isFirstReply: false, isLastReply: false, previousPostIsComment: false, commentedOnPost: undefined, consecutivePostByUser: false, replyCount: 2, isCommentMention: false, }; const post3 = { ...postsNever.c, isFirstReply: true, isLastReply: true, previousPostIsComment: false, commentedOnPost: postsNever.a, consecutivePostByUser: true, replyCount: 2, isCommentMention: false, }; const post4 = { ...postsNever.d, isFirstReply: true, isLastReply: true, previousPostIsComment: true, commentedOnPost: postsNever.b, consecutivePostByUser: false, replyCount: 2, isCommentMention: false, }; const post5 = { ...postsNever.e, isFirstReply: true, isLastReply: true, previousPostIsComment: true, commentedOnPost: postsNever.a, consecutivePostByUser: false, replyCount: 2, isCommentMention: false, }; const post6 = { ...postsNever.f, isFirstReply: true, isLastReply: true, previousPostIsComment: true, commentedOnPost: postsNever.b, consecutivePostByUser: true, replyCount: 2, isCommentMention: false, }; const getPostsInChannel = Selectors.makeGetPostsInChannel(); assert.deepEqual(getPostsInChannel(testStateNever, '1'), [post6, post5, post4, post3, post2, post1]); }); it('gets posts around post in channel not adding ephemeral post to replyCount', () => { const userAny = TestHelper.fakeUserWithId(); userAny.notify_props = {comments: 'any'}; const profilesAny = {}; profilesAny[userAny.id] = userAny; const postsAny = { a: {id: 'a', channel_id: '1', create_at: 1, highlight: false, user_id: userAny.id}, b: {id: 'b', root_id: 'a', channel_id: '1', create_at: 2, highlight: false, user_id: 'b'}, c: {id: 'c', root_id: 'a', channel_id: '1', create_at: 3, highlight: false, user_id: 'b', type: Posts.POST_TYPES.EPHEMERAL}, d: {id: 'd', channel_id: '2', create_at: 4, highlight: false, user_id: 'b'}, }; const testStateAny = deepFreezeAndThrowOnMutation({ entities: { users: { currentUserId: userAny.id, profiles: profilesAny, }, posts: { posts: postsAny, postsInChannel: { 1: [ {order: ['c', 'b', 'a'], recent: true}, ], 2: [ {order: ['d'], recent: true}, ], }, postsInThread: { a: ['b', 'c'], }, }, preferences: { myPreferences: {}, }, }, }); const post1 = { ...postsAny.a, isFirstReply: false, isLastReply: false, previousPostIsComment: false, commentedOnPost: undefined, consecutivePostByUser: false, replyCount: 1, isCommentMention: false, highlight: true, }; const post2 = { ...postsAny.b, isFirstReply: true, isLastReply: false, previousPostIsComment: false, commentedOnPost: undefined, consecutivePostByUser: false, replyCount: 1, isCommentMention: true, }; const post3 = { ...postsAny.c, isFirstReply: false, isLastReply: true, previousPostIsComment: true, commentedOnPost: undefined, consecutivePostByUser: false, replyCount: 1, isCommentMention: true, }; const getPostsAroundPost = Selectors.makeGetPostsAroundPost(); assert.deepEqual(getPostsAroundPost(testStateAny, post1.id, '1'), [post3, post2, post1]); }); it('gets posts in channel not adding ephemeral post to replyCount', () => { const userAny = TestHelper.fakeUserWithId(); userAny.notify_props = {comments: 'any'}; const profilesAny = {}; profilesAny[userAny.id] = userAny; const postsAny = { a: {id: 'a', channel_id: '1', create_at: 1, highlight: false, user_id: userAny.id}, b: {id: 'b', root_id: 'a', channel_id: '1', create_at: 2, highlight: false, user_id: 'b', type: Posts.POST_TYPES.EPHEMERAL}, c: {id: 'c', root_id: 'a', channel_id: '1', create_at: 3, highlight: false, user_id: 'b', state: Posts.POST_DELETED}, d: {id: 'd', channel_id: '2', create_at: 4, highlight: false, user_id: 'b'}, }; const testStateAny = deepFreezeAndThrowOnMutation({ entities: { users: { currentUserId: userAny.id, profiles: profilesAny, }, posts: { posts: postsAny, postsInChannel: { 1: [ {order: ['c', 'b', 'a'], recent: true}, ], 2: [ {order: ['d'], recent: true}, ], }, postsInThread: { a: ['b', 'c'], }, }, preferences: { myPreferences: {}, }, }, }); const post1 = { ...postsAny.a, isFirstReply: false, isLastReply: false, previousPostIsComment: false, commentedOnPost: undefined, consecutivePostByUser: false, replyCount: 0, isCommentMention: false, }; const post2 = { ...postsAny.b, isFirstReply: true, isLastReply: false, previousPostIsComment: false, commentedOnPost: undefined, consecutivePostByUser: false, replyCount: 0, isCommentMention: true, }; const post3 = { ...postsAny.c, isFirstReply: false, isLastReply: true, previousPostIsComment: true, commentedOnPost: undefined, consecutivePostByUser: false, replyCount: 0, isCommentMention: true, }; const getPostsInChannel = Selectors.makeGetPostsInChannel(); assert.deepEqual(getPostsInChannel(testStateAny, '1'), [post3, post2, post1]); }); it('get current history item', () => { const testState1 = deepFreezeAndThrowOnMutation({ entities: { posts: { messagesHistory: { messages: ['test1', 'test2', 'test3'], index: { post: 1, comment: 2, }, }, }, }, }); const testState2 = deepFreezeAndThrowOnMutation({ entities: { posts: { messagesHistory: { messages: ['test1', 'test2', 'test3'], index: { post: 0, comment: 0, }, }, }, }, }); const testState3 = deepFreezeAndThrowOnMutation({ entities: { posts: { messagesHistory: { messages: [], index: { post: -1, comment: -1, }, }, }, }, }); const getHistoryMessagePost = Selectors.makeGetMessageInHistoryItem(Posts.MESSAGE_TYPES.POST); const getHistoryMessageComment = Selectors.makeGetMessageInHistoryItem(Posts.MESSAGE_TYPES.COMMENT); assert.equal(getHistoryMessagePost(testState1), 'test2'); assert.equal(getHistoryMessageComment(testState1), 'test3'); assert.equal(getHistoryMessagePost(testState2), 'test1'); assert.equal(getHistoryMessageComment(testState2), 'test1'); assert.equal(getHistoryMessagePost(testState3), ''); assert.equal(getHistoryMessageComment(testState3), ''); }); describe('getPostIdsForThread', () => { it('single post', () => { const getPostIdsForThread = Selectors.makeGetPostIdsForThread(); const state = { entities: { posts: { posts: { 1001: {id: '1001', create_at: 1001}, 1002: {id: '1002', create_at: 1002, root_id: '1001'}, 1003: {id: '1003', create_at: 1003}, 1004: {id: '1004', create_at: 1004, root_id: '1001'}, 1005: {id: '1005', create_at: 1005}, }, postsInThread: { 1001: ['1002', '1004'], }, }, }, }; const expected = ['1005']; assert.deepEqual(getPostIdsForThread(state, '1005'), expected); }); it('thread', () => { const getPostIdsForThread = Selectors.makeGetPostIdsForThread(); const state = { entities: { posts: { posts: { 1001: {id: '1001', create_at: 1001}, 1002: {id: '1002', create_at: 1002, root_id: '1001'}, 1003: {id: '1003', create_at: 1003}, 1004: {id: '1004', create_at: 1004, root_id: '1001'}, 1005: {id: '1005', create_at: 1005}, }, postsInThread: { 1001: ['1002', '1004'], }, }, }, }; const expected = ['1004', '1002', '1001']; assert.deepEqual(getPostIdsForThread(state, '1001'), expected); }); it('memoization', () => { const getPostIdsForThread = Selectors.makeGetPostIdsForThread(); let state = { entities: { posts: { posts: { 1001: {id: '1001', create_at: 1001}, 1002: {id: '1002', create_at: 1002, root_id: '1001'}, 1003: {id: '1003', create_at: 1003}, 1004: {id: '1004', create_at: 1004, root_id: '1001'}, 1005: {id: '1005', create_at: 1005}, }, postsInThread: { 1001: ['1002', '1004'], }, }, }, }; // One post, no changes let previous = getPostIdsForThread(state, '1005'); let now = getPostIdsForThread(state, '1005'); assert.deepEqual(now, ['1005']); assert.equal(now, previous); // One post, unrelated changes state = { ...state, entities: { ...state.entities, posts: { ...state.entities.posts, posts: { ...state.entities.posts.posts, 1006: {id: '1006', create_at: 1006, root_id: '1003'}, }, postsInThread: { ...state.entities.posts.postsInThread, 1003: ['1006'], }, }, }, }; previous = now; now = getPostIdsForThread(state, '1005'); assert.deepEqual(now, ['1005']); assert.equal(now, previous); // One post, changes to post state = { ...state, entities: { ...state.entities, posts: { ...state.entities.posts, posts: { ...state.entities.posts.posts, 1005: {id: '1005', create_at: 1005, update_at: 1006}, }, postsInThread: state.entities.posts.postsInThread, }, }, }; previous = now; now = getPostIdsForThread(state, '1005'); assert.deepEqual(now, ['1005']); assert.equal(now, previous); // Change of thread previous = now; now = getPostIdsForThread(state, '1001'); assert.deepEqual(now, ['1004', '1002', '1001']); assert.notEqual(now, previous); previous = now; now = getPostIdsForThread(state, '1001'); assert.equal(now, previous); // New post in thread state = { ...state, entities: { ...state.entities, posts: { ...state.entities.posts, posts: { ...state.entities.posts.posts, 1007: {id: '1007', create_at: 1007, root_id: '1001'}, }, postsInThread: { ...state.entities.posts.postsInThread, 1001: [...state.entities.posts.postsInThread['1001'], '1007'], }, }, }, }; previous = now; now = getPostIdsForThread(state, '1001'); assert.deepEqual(now, ['1007', '1004', '1002', '1001']); assert.notEqual(now, previous); previous = now; now = getPostIdsForThread(state, '1001'); assert.deepEqual(now, ['1007', '1004', '1002', '1001']); assert.equal(now, previous); }); it('memoization with multiple selectors', () => { const getPostIdsForThread1 = Selectors.makeGetPostIdsForThread(); const getPostIdsForThread2 = Selectors.makeGetPostIdsForThread(); const state = { entities: { posts: { posts: { 1001: {id: '1001', create_at: 1001}, 1002: {id: '1002', create_at: 1002, root_id: '1001'}, 1003: {id: '1003', create_at: 1003}, 1004: {id: '1004', create_at: 1004, root_id: '1001'}, 1005: {id: '1005', create_at: 1005}, }, postsInThread: { 1001: ['1002', '1004'], }, }, }, }; let now1 = getPostIdsForThread1(state, '1001'); let now2 = getPostIdsForThread2(state, '1001'); assert.notEqual(now1, now2); assert.deepEqual(now1, now2); let previous1 = now1; now1 = getPostIdsForThread1(state, '1001'); assert.equal(now1, previous1); const previous2 = now2; now2 = getPostIdsForThread2(state, '1003'); assert.notEqual(now2, previous2); assert.notDeepEqual(now1, now2); previous1 = now1; now1 = getPostIdsForThread1(state, '1001'); assert.equal(now1, previous1); }); }); describe('getPostIdsAroundPost', () => { it('no posts around', () => { const getPostIdsAroundPost = Selectors.makeGetPostIdsAroundPost(); const state = { entities: { posts: { postsInChannel: { 1234: [ {order: ['a'], recent: true}, ], }, }, }, }; assert.deepEqual(getPostIdsAroundPost(state, 'a', '1234'), ['a']); }); it('posts around', () => { const getPostIdsAroundPost = Selectors.makeGetPostIdsAroundPost(); const state = { entities: { posts: { postsInChannel: { 1234: [ {order: ['a', 'b', 'c', 'd', 'e'], recent: true}, ], }, }, }, }; assert.deepEqual(getPostIdsAroundPost(state, 'c', '1234'), ['a', 'b', 'c', 'd', 'e']); }); it('posts before limit', () => { const getPostIdsAroundPost = Selectors.makeGetPostIdsAroundPost(); const state = { entities: { posts: { postsInChannel: { 1234: [ {order: ['a', 'b', 'c', 'd', 'e'], recent: true}, ], }, }, }, }; assert.deepEqual(getPostIdsAroundPost(state, 'a', '1234', {postsBeforeCount: 2}), ['a', 'b', 'c']); }); it('posts after limit', () => { const getPostIdsAroundPost = Selectors.makeGetPostIdsAroundPost(); const state = { entities: { posts: { postsInChannel: { 1234: [ {order: ['a', 'b', 'c', 'd', 'e'], recent: true}, ], }, }, }, }; assert.deepEqual(getPostIdsAroundPost(state, 'e', '1234', {postsAfterCount: 3}), ['b', 'c', 'd', 'e']); }); it('posts before/after limit', () => { const getPostIdsAroundPost = Selectors.makeGetPostIdsAroundPost(); const state = { entities: { posts: { postsInChannel: { 1234: [ {order: ['a', 'b', 'c', 'd', 'e', 'f'], recent: true}, ], }, }, }, }; assert.deepEqual(getPostIdsAroundPost(state, 'c', '1234', {postsBeforeCount: 2, postsAfterCount: 1}), ['b', 'c', 'd', 'e']); }); it('memoization', () => { const getPostIdsAroundPost = Selectors.makeGetPostIdsAroundPost(); let state = { entities: { posts: { postsInChannel: { 1234: [ {order: ['a', 'b', 'c', 'd', 'e'], recent: true}, ], }, }, }, }; // No limit, no changes let previous = getPostIdsAroundPost(state, 'c', '1234'); let now = getPostIdsAroundPost(state, 'c', '1234'); assert.deepEqual(now, ['a', 'b', 'c', 'd', 'e']); assert.equal(now, previous); // Changes to posts in another channel state = { ...state, entities: { ...state.entities, posts: { ...state.entities.posts, postsInChannel: { ...state.entities.posts.postsInChannel, abcd: [ {order: ['g', 'h', 'i', 'j', 'k', 'l'], recent: true}, ], }, }, }, }; previous = now; now = getPostIdsAroundPost(state, 'c', '1234'); assert.deepEqual(now, ['a', 'b', 'c', 'd', 'e']); assert.equal(now, previous); // Changes to posts in this channel state = { ...state, entities: { ...state.entities, posts: { ...state.entities.posts, postsInChannel: { ...state.entities.posts.postsInChannel, 1234: [ {order: ['a', 'b', 'c', 'd', 'e', 'f'], recent: true}, ], }, }, }, }; previous = now; now = getPostIdsAroundPost(state, 'c', '1234'); assert.deepEqual(now, ['a', 'b', 'c', 'd', 'e', 'f']); assert.notEqual(now, previous); previous = now; now = getPostIdsAroundPost(state, 'c', '1234'); assert.deepEqual(now, ['a', 'b', 'c', 'd', 'e', 'f']); assert.equal(now, previous); // Change of channel previous = now; now = getPostIdsAroundPost(state, 'i', 'abcd'); assert.deepEqual(now, ['g', 'h', 'i', 'j', 'k', 'l']); assert.notEqual(now, previous); previous = now; now = getPostIdsAroundPost(state, 'i', 'abcd'); assert.deepEqual(now, ['g', 'h', 'i', 'j', 'k', 'l']); assert.equal(now, previous); // With limits previous = now; now = getPostIdsAroundPost(state, 'i', 'abcd', {postsBeforeCount: 2, postsAfterCount: 1}); assert.deepEqual(now, ['h', 'i', 'j', 'k']); assert.notEqual(now, previous); previous = now; now = getPostIdsAroundPost(state, 'i', 'abcd', {postsBeforeCount: 2, postsAfterCount: 1}); // Note that the options object is a new object each time assert.deepEqual(now, ['h', 'i', 'j', 'k']); assert.equal(now, previous); // Change of limits previous = now; now = getPostIdsAroundPost(state, 'i', 'abcd', {postsBeforeCount: 1, postsAfterCount: 2}); assert.deepEqual(now, ['g', 'h', 'i', 'j']); assert.notEqual(now, previous); previous = now; now = getPostIdsAroundPost(state, 'i', 'abcd', {postsBeforeCount: 1, postsAfterCount: 2}); assert.deepEqual(now, ['g', 'h', 'i', 'j']); assert.equal(now, previous); // Change of post previous = now; now = getPostIdsAroundPost(state, 'j', 'abcd', {postsBeforeCount: 1, postsAfterCount: 2}); assert.deepEqual(now, ['h', 'i', 'j', 'k']); assert.notEqual(now, previous); previous = now; now = getPostIdsAroundPost(state, 'j', 'abcd', {postsBeforeCount: 1, postsAfterCount: 2}); assert.deepEqual(now, ['h', 'i', 'j', 'k']); assert.equal(now, previous); // Change of posts past limit state = { ...state, entities: { ...state.entities, posts: { ...state.entities.posts, postsInChannel: { ...state.entities.posts.postsInChannel, abcd: [ {order: ['y', 'g', 'h', 'i', 'j', 'k', 'l', 'f', 'z'], recent: true}, ], }, }, }, }; previous = now; now = getPostIdsAroundPost(state, 'j', 'abcd', {postsBeforeCount: 1, postsAfterCount: 2}); assert.deepEqual(now, ['h', 'i', 'j', 'k']); assert.equal(now, previous); // Change of post order state = { ...state, entities: { ...state.entities, posts: { ...state.entities.posts, postsInChannel: { ...state.entities.posts.postsInChannel, abcd: [ {order: ['y', 'g', 'i', 'h', 'j', 'l', 'k', 'z'], recent: true}, ], }, }, }, }; previous = now; now = getPostIdsAroundPost(state, 'j', 'abcd', {postsBeforeCount: 1, postsAfterCount: 2}); assert.deepEqual(now, ['i', 'h', 'j', 'l']); assert.notEqual(now, previous); previous = now; now = getPostIdsAroundPost(state, 'j', 'abcd', {postsBeforeCount: 1, postsAfterCount: 2}); assert.deepEqual(now, ['i', 'h', 'j', 'l']); assert.equal(now, previous); }); it('memoization with multiple selectors', () => { const getPostIdsAroundPost1 = Selectors.makeGetPostIdsAroundPost(); const getPostIdsAroundPost2 = Selectors.makeGetPostIdsAroundPost(); const state = { entities: { posts: { postsInChannel: { 1234: [ {order: ['a', 'b', 'c', 'd', 'e', 'f'], recent: true}, ], abcd: [ {order: ['g', 'h', 'i'], recent: true}, ], }, }, }, }; const previous1 = getPostIdsAroundPost1(state, 'c', '1234'); const previous2 = getPostIdsAroundPost2(state, 'h', 'abcd', {postsBeforeCount: 1, postsAfterCount: 0}); assert.notEqual(previous1, previous2); const now1 = getPostIdsAroundPost1(state, 'c', '1234'); const now2 = getPostIdsAroundPost2(state, 'i', 'abcd', {postsBeforeCount: 1, postsAfterCount: 0}); assert.equal(now1, previous1); assert.notEqual(now2, previous2); assert.notEqual(now1, now2); }); }); describe('makeGetPostsChunkAroundPost', () => { it('no posts around', () => { const getPostsChunkAroundPost = Selectors.makeGetPostsChunkAroundPost(); const state = { entities: { posts: { postsInChannel: { 1234: [ {order: ['a'], recent: true}, ], }, }, }, }; assert.deepEqual(getPostsChunkAroundPost(state, 'a', '1234'), {order: ['a'], recent: true}); }); it('posts around', () => { const getPostsChunkAroundPost = Selectors.makeGetPostsChunkAroundPost(); const state = { entities: { posts: { postsInChannel: { 1234: [ {order: ['a', 'b', 'c', 'd', 'e'], recent: true}, ], }, }, }, }; assert.deepEqual(getPostsChunkAroundPost(state, 'c', '1234'), {order: ['a', 'b', 'c', 'd', 'e'], recent: true}); }); it('no matching posts', () => { const getPostsChunkAroundPost = Selectors.makeGetPostsChunkAroundPost(); const state = { entities: { posts: { postsInChannel: { 1234: [ {order: ['a', 'b', 'c', 'd', 'e', 'f'], recent: true}, ], }, }, }, }; assert.deepEqual(getPostsChunkAroundPost(state, 'noChunk', '1234'), null); }); it('memoization', () => { const getPostsChunkAroundPost = Selectors.makeGetPostsChunkAroundPost(); let state = { entities: { posts: { postsInChannel: { 1234: [ {order: ['a', 'b', 'c', 'd', 'e'], recent: true}, ], }, }, }, }; // No limit, no changes let previous = getPostsChunkAroundPost(state, 'c', '1234'); // Changes to posts in another channel state = { ...state, entities: { ...state.entities, posts: { ...state.entities.posts, postsInChannel: { ...state.entities.posts.postsInChannel, abcd: [ {order: ['g', 'h', 'i', 'j', 'k', 'l'], recent: true}, ], }, }, }, }; let now = getPostsChunkAroundPost(state, 'c', '1234'); assert.deepEqual(now, {order: ['a', 'b', 'c', 'd', 'e'], recent: true}); assert.equal(now, previous); // Changes to posts in this channel state = { ...state, entities: { ...state.entities, posts: { ...state.entities.posts, postsInChannel: { ...state.entities.posts.postsInChannel, 1234: [ {order: ['a', 'b', 'c', 'd', 'e', 'f'], recent: true}, ], }, }, }, }; previous = now; now = getPostsChunkAroundPost(state, 'c', '1234'); assert.deepEqual(now, {order: ['a', 'b', 'c', 'd', 'e', 'f'], recent: true}); assert.notEqual(now, previous); previous = now; now = getPostsChunkAroundPost(state, 'c', '1234'); assert.deepEqual(now, {order: ['a', 'b', 'c', 'd', 'e', 'f'], recent: true}); assert.equal(now, previous); // Change of channel previous = now; now = getPostsChunkAroundPost(state, 'i', 'abcd'); assert.deepEqual(now, {order: ['g', 'h', 'i', 'j', 'k', 'l'], recent: true}); assert.notEqual(now, previous); previous = now; now = getPostsChunkAroundPost(state, 'i', 'abcd'); assert.deepEqual(now, {order: ['g', 'h', 'i', 'j', 'k', 'l'], recent: true}); assert.equal(now, previous); // Change of post in the chunk previous = now; now = getPostsChunkAroundPost(s