MM-11198: avoid duplicate date line keys (#1901)
* MM-11198: avoid duplicate keys in date lines Ensure each dateline rendered as part of search, recent mentions, or flagged post list has a unique key, even if the same date itself appears multiple times. * update post_list.test.js to actually test date boundaries, relying on TZ=utc export in package.json * unit test makePreparePostIdsForSearchPosts * fix eslint issues * try TZ=GMT * encode date lines using timestamps instead This requires a few extra changes to the post list proper, but largely simplifies things anyway.
This commit is contained in:
parent
ca4d08fc7e
commit
36dd3f19e2
11 changed files with 1003 additions and 77 deletions
|
|
@ -0,0 +1,641 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`DateHeader component should match snapshot with suffix 1`] = `
|
||||
ShallowWrapper {
|
||||
"length": 1,
|
||||
Symbol(enzyme.__root__): [Circular],
|
||||
Symbol(enzyme.__unrendered__): <DateHeader
|
||||
dateLineString="date-1531152392-index-2"
|
||||
index={2}
|
||||
theme={
|
||||
Object {
|
||||
"centerChannelBg": "#aaa",
|
||||
"centerChannelColor": "#aaa",
|
||||
}
|
||||
}
|
||||
/>,
|
||||
Symbol(enzyme.__renderer__): Object {
|
||||
"batchedUpdates": [Function],
|
||||
"getNode": [Function],
|
||||
"render": [Function],
|
||||
"simulateEvent": [Function],
|
||||
"unmount": [Function],
|
||||
},
|
||||
Symbol(enzyme.__node__): Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"children": Array [
|
||||
<Component
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
}
|
||||
}
|
||||
/>,
|
||||
<Component
|
||||
style={
|
||||
Object {
|
||||
"marginHorizontal": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<InjectIntl(FormattedDate)
|
||||
day="2-digit"
|
||||
month="short"
|
||||
style={
|
||||
Object {
|
||||
"color": "#aaa",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
}
|
||||
}
|
||||
value={1970-01-18T17:19:12.392Z}
|
||||
weekday="short"
|
||||
year="numeric"
|
||||
/>
|
||||
</Component>,
|
||||
<Component
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
}
|
||||
}
|
||||
/>,
|
||||
],
|
||||
"style": Array [
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"flexDirection": "row",
|
||||
"height": 28,
|
||||
},
|
||||
undefined,
|
||||
],
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": Array [
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"style": Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"children": <InjectIntl(FormattedDate)
|
||||
day="2-digit"
|
||||
month="short"
|
||||
style={
|
||||
Object {
|
||||
"color": "#aaa",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
}
|
||||
}
|
||||
value={1970-01-18T17:19:12.392Z}
|
||||
weekday="short"
|
||||
year="numeric"
|
||||
/>,
|
||||
"style": Object {
|
||||
"marginHorizontal": 15,
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"day": "2-digit",
|
||||
"month": "short",
|
||||
"style": Object {
|
||||
"color": "#aaa",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
},
|
||||
"value": 1970-01-18T17:19:12.392Z,
|
||||
"weekday": "short",
|
||||
"year": "numeric",
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
"type": [Function],
|
||||
},
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"style": Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
],
|
||||
"type": [Function],
|
||||
},
|
||||
Symbol(enzyme.__nodes__): Array [
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"children": Array [
|
||||
<Component
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
}
|
||||
}
|
||||
/>,
|
||||
<Component
|
||||
style={
|
||||
Object {
|
||||
"marginHorizontal": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<InjectIntl(FormattedDate)
|
||||
day="2-digit"
|
||||
month="short"
|
||||
style={
|
||||
Object {
|
||||
"color": "#aaa",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
}
|
||||
}
|
||||
value={1970-01-18T17:19:12.392Z}
|
||||
weekday="short"
|
||||
year="numeric"
|
||||
/>
|
||||
</Component>,
|
||||
<Component
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
}
|
||||
}
|
||||
/>,
|
||||
],
|
||||
"style": Array [
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"flexDirection": "row",
|
||||
"height": 28,
|
||||
},
|
||||
undefined,
|
||||
],
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": Array [
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"style": Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"children": <InjectIntl(FormattedDate)
|
||||
day="2-digit"
|
||||
month="short"
|
||||
style={
|
||||
Object {
|
||||
"color": "#aaa",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
}
|
||||
}
|
||||
value={1970-01-18T17:19:12.392Z}
|
||||
weekday="short"
|
||||
year="numeric"
|
||||
/>,
|
||||
"style": Object {
|
||||
"marginHorizontal": 15,
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"day": "2-digit",
|
||||
"month": "short",
|
||||
"style": Object {
|
||||
"color": "#aaa",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
},
|
||||
"value": 1970-01-18T17:19:12.392Z,
|
||||
"weekday": "short",
|
||||
"year": "numeric",
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
"type": [Function],
|
||||
},
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"style": Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
],
|
||||
"type": [Function],
|
||||
},
|
||||
],
|
||||
Symbol(enzyme.__options__): Object {
|
||||
"adapter": ReactSixteenAdapter {
|
||||
"options": Object {
|
||||
"enableComponentDidUpdateOnSetState": true,
|
||||
},
|
||||
},
|
||||
"context": Object {
|
||||
"intl": Object {
|
||||
"formatMessage": [MockFunction],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`DateHeader component should match snapshot without suffix 1`] = `
|
||||
ShallowWrapper {
|
||||
"length": 1,
|
||||
Symbol(enzyme.__root__): [Circular],
|
||||
Symbol(enzyme.__unrendered__): <DateHeader
|
||||
dateLineString="date-1531152392"
|
||||
index={0}
|
||||
theme={
|
||||
Object {
|
||||
"centerChannelBg": "#aaa",
|
||||
"centerChannelColor": "#aaa",
|
||||
}
|
||||
}
|
||||
/>,
|
||||
Symbol(enzyme.__renderer__): Object {
|
||||
"batchedUpdates": [Function],
|
||||
"getNode": [Function],
|
||||
"render": [Function],
|
||||
"simulateEvent": [Function],
|
||||
"unmount": [Function],
|
||||
},
|
||||
Symbol(enzyme.__node__): Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"children": Array [
|
||||
<Component
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
}
|
||||
}
|
||||
/>,
|
||||
<Component
|
||||
style={
|
||||
Object {
|
||||
"marginHorizontal": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<InjectIntl(FormattedDate)
|
||||
day="2-digit"
|
||||
month="short"
|
||||
style={
|
||||
Object {
|
||||
"color": "#aaa",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
}
|
||||
}
|
||||
value={1970-01-18T17:19:12.392Z}
|
||||
weekday="short"
|
||||
year="numeric"
|
||||
/>
|
||||
</Component>,
|
||||
<Component
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
}
|
||||
}
|
||||
/>,
|
||||
],
|
||||
"style": Array [
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"flexDirection": "row",
|
||||
"height": 28,
|
||||
},
|
||||
undefined,
|
||||
],
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": Array [
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"style": Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"children": <InjectIntl(FormattedDate)
|
||||
day="2-digit"
|
||||
month="short"
|
||||
style={
|
||||
Object {
|
||||
"color": "#aaa",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
}
|
||||
}
|
||||
value={1970-01-18T17:19:12.392Z}
|
||||
weekday="short"
|
||||
year="numeric"
|
||||
/>,
|
||||
"style": Object {
|
||||
"marginHorizontal": 15,
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"day": "2-digit",
|
||||
"month": "short",
|
||||
"style": Object {
|
||||
"color": "#aaa",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
},
|
||||
"value": 1970-01-18T17:19:12.392Z,
|
||||
"weekday": "short",
|
||||
"year": "numeric",
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
"type": [Function],
|
||||
},
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"style": Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
],
|
||||
"type": [Function],
|
||||
},
|
||||
Symbol(enzyme.__nodes__): Array [
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"children": Array [
|
||||
<Component
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
}
|
||||
}
|
||||
/>,
|
||||
<Component
|
||||
style={
|
||||
Object {
|
||||
"marginHorizontal": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<InjectIntl(FormattedDate)
|
||||
day="2-digit"
|
||||
month="short"
|
||||
style={
|
||||
Object {
|
||||
"color": "#aaa",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
}
|
||||
}
|
||||
value={1970-01-18T17:19:12.392Z}
|
||||
weekday="short"
|
||||
year="numeric"
|
||||
/>
|
||||
</Component>,
|
||||
<Component
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
}
|
||||
}
|
||||
/>,
|
||||
],
|
||||
"style": Array [
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"flexDirection": "row",
|
||||
"height": 28,
|
||||
},
|
||||
undefined,
|
||||
],
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": Array [
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"style": Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"children": <InjectIntl(FormattedDate)
|
||||
day="2-digit"
|
||||
month="short"
|
||||
style={
|
||||
Object {
|
||||
"color": "#aaa",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
}
|
||||
}
|
||||
value={1970-01-18T17:19:12.392Z}
|
||||
weekday="short"
|
||||
year="numeric"
|
||||
/>,
|
||||
"style": Object {
|
||||
"marginHorizontal": 15,
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"day": "2-digit",
|
||||
"month": "short",
|
||||
"style": Object {
|
||||
"color": "#aaa",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "600",
|
||||
},
|
||||
"value": 1970-01-18T17:19:12.392Z,
|
||||
"weekday": "short",
|
||||
"year": "numeric",
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
"type": [Function],
|
||||
},
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"style": Object {
|
||||
"backgroundColor": "#aaa",
|
||||
"flex": 1,
|
||||
"height": 1,
|
||||
"opacity": 0.2,
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
],
|
||||
"type": [Function],
|
||||
},
|
||||
],
|
||||
Symbol(enzyme.__options__): Object {
|
||||
"adapter": ReactSixteenAdapter {
|
||||
"options": Object {
|
||||
"enableComponentDidUpdateOnSetState": true,
|
||||
},
|
||||
},
|
||||
"context": Object {
|
||||
"intl": Object {
|
||||
"formatMessage": [MockFunction],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
|
@ -10,17 +10,27 @@ import {
|
|||
|
||||
import FormattedDate from 'app/components/formatted_date';
|
||||
import {makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
import {DATE_LINE, DATE_LINE_SUFFIX} from 'app/selectors/post_list';
|
||||
|
||||
// DateHeader accepts as a timestamp encoded as a string for rendering as part of a post list.
|
||||
export default class DateHeader extends PureComponent {
|
||||
static propTypes = {
|
||||
date: PropTypes.object.isRequired,
|
||||
dateLineString: PropTypes.string.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
style: ViewPropTypes.style,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {date, theme} = this.props;
|
||||
const {theme, dateLineString} = this.props;
|
||||
const style = getStyleSheet(theme);
|
||||
const indexSuffix = dateLineString.indexOf(DATE_LINE_SUFFIX);
|
||||
|
||||
let date;
|
||||
if (indexSuffix >= 0) {
|
||||
date = new Date(parseInt(dateLineString.substring(DATE_LINE.length, indexSuffix), 10));
|
||||
} else {
|
||||
date = new Date(parseInt(dateLineString.substring(DATE_LINE.length), 10));
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[style.container, this.props.style]}>
|
||||
|
|
|
|||
47
app/components/post_list/date_header/date_header.test.js
Normal file
47
app/components/post_list/date_header/date_header.test.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/* eslint-disable max-nested-callbacks */
|
||||
|
||||
import React from 'react';
|
||||
import {configure, shallow} from 'enzyme';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
configure({adapter: new Adapter()});
|
||||
|
||||
import DateHeader from './date_header.js';
|
||||
|
||||
describe('DateHeader', () => {
|
||||
const baseProps = {
|
||||
theme: {centerChannelBg: '#aaa', centerChannelColor: '#aaa'},
|
||||
};
|
||||
|
||||
describe('component should match snapshot', () => {
|
||||
it('without suffix', () => {
|
||||
const props = {
|
||||
...baseProps,
|
||||
dateLineString: 'date-1531152392',
|
||||
index: 0,
|
||||
};
|
||||
const wrapper = shallow(
|
||||
<DateHeader {...props}/>,
|
||||
{context: {intl: {formatMessage: jest.fn()}}},
|
||||
);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('with suffix', () => {
|
||||
const props = {
|
||||
...baseProps,
|
||||
dateLineString: 'date-1531152392-index-2',
|
||||
index: 2,
|
||||
};
|
||||
const wrapper = shallow(
|
||||
<DateHeader {...props}/>,
|
||||
{context: {intl: {formatMessage: jest.fn()}}},
|
||||
);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
6
app/components/post_list/date_header/utils.js
Normal file
6
app/components/post_list/date_header/utils.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {DATE_LINE} from 'app/selectors/post_list';
|
||||
|
||||
export const isDateLine = (dateString) => dateString.indexOf(DATE_LINE) === 0;
|
||||
17
app/components/post_list/date_header/utils.test.js
Normal file
17
app/components/post_list/date_header/utils.test.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import assert from 'assert';
|
||||
|
||||
import {isDateLine} from './utils.js';
|
||||
|
||||
describe('DateHeader', () => {
|
||||
it('isDateLine', () => {
|
||||
assert.equal(isDateLine(''), false);
|
||||
assert.equal(isDateLine('date'), false);
|
||||
assert.equal(isDateLine('date-'), true);
|
||||
assert.equal(isDateLine('date-0'), true);
|
||||
assert.equal(isDateLine('date-1531152392'), true);
|
||||
assert.equal(isDateLine('date-1531152392-index'), true);
|
||||
});
|
||||
});
|
||||
|
|
@ -13,12 +13,13 @@ import {
|
|||
import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
||||
|
||||
import Post from 'app/components/post';
|
||||
import {DATE_LINE, START_OF_NEW_MESSAGES} from 'app/selectors/post_list';
|
||||
import {START_OF_NEW_MESSAGES} from 'app/selectors/post_list';
|
||||
import mattermostManaged from 'app/mattermost_managed';
|
||||
import {makeExtraData} from 'app/utils/list_view';
|
||||
import {changeOpacity} from 'app/utils/theme';
|
||||
|
||||
import DateHeader from './date_header';
|
||||
import {isDateLine} from './date_header/utils';
|
||||
import NewMessagesDivider from './new_messages_divider';
|
||||
import withLayout from './with_layout';
|
||||
|
||||
|
|
@ -264,9 +265,14 @@ export default class PostList extends PureComponent {
|
|||
moreMessages={this.moreNewMessages}
|
||||
/>
|
||||
);
|
||||
} else if (item.indexOf(DATE_LINE) === 0) {
|
||||
const date = item.substring(DATE_LINE.length);
|
||||
return this.renderDateHeader(new Date(date), index);
|
||||
} else if (isDateLine(item)) {
|
||||
this.itemMeasurements[index] = DATE_HEADER_HEIGHT;
|
||||
return (
|
||||
<DateHeader
|
||||
dateLineString={item}
|
||||
index={index}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const postId = item;
|
||||
|
|
@ -279,16 +285,6 @@ export default class PostList extends PureComponent {
|
|||
return this.renderPost(postId, previousPostId, nextPostId, index);
|
||||
};
|
||||
|
||||
renderDateHeader = (date, index) => {
|
||||
this.itemMeasurements[index] = DATE_HEADER_HEIGHT;
|
||||
return (
|
||||
<DateHeader
|
||||
date={date}
|
||||
index={index}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
renderPost = (postId, previousPostId, nextPostId, index) => {
|
||||
const {
|
||||
highlightPostId,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
|
||||
import ChannelLoader from 'app/components/channel_loader';
|
||||
import DateHeader from 'app/components/post_list/date_header';
|
||||
import {isDateLine} from 'app/components/post_list/date_header/utils';
|
||||
import FailedNetworkAction from 'app/components/failed_network_action';
|
||||
import NoResults from 'app/components/no_results';
|
||||
import PostSeparator from 'app/components/post_separator';
|
||||
|
|
@ -21,7 +22,6 @@ import StatusBar from 'app/components/status_bar';
|
|||
import mattermostManaged from 'app/mattermost_managed';
|
||||
import SearchResultPost from 'app/screens/search/search_result_post';
|
||||
import ChannelDisplayName from 'app/screens/search/channel_display_name';
|
||||
import {DATE_LINE} from 'app/selectors/post_list';
|
||||
import {changeOpacity} from 'app/utils/theme';
|
||||
|
||||
export default class FlaggedPosts extends PureComponent {
|
||||
|
|
@ -150,13 +150,10 @@ export default class FlaggedPosts extends PureComponent {
|
|||
renderPost = ({item, index}) => {
|
||||
const {postIds, theme} = this.props;
|
||||
const {managedConfig} = this.state;
|
||||
if (item.indexOf(DATE_LINE) === 0) {
|
||||
const date = new Date(item.substring(DATE_LINE.length));
|
||||
|
||||
if (isDateLine(item)) {
|
||||
return (
|
||||
<DateHeader
|
||||
key={`${date}-${index}`}
|
||||
date={date}
|
||||
dateLineString={item}
|
||||
index={index}
|
||||
/>
|
||||
);
|
||||
|
|
@ -164,7 +161,7 @@ export default class FlaggedPosts extends PureComponent {
|
|||
|
||||
let separator;
|
||||
const nextPost = postIds[index + 1];
|
||||
if (nextPost && nextPost.indexOf(DATE_LINE) === -1) {
|
||||
if (nextPost && !isDateLine(nextPost)) {
|
||||
separator = <PostSeparator theme={theme}/>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
|
||||
import ChannelLoader from 'app/components/channel_loader';
|
||||
import DateHeader from 'app/components/post_list/date_header';
|
||||
import {isDateLine} from 'app/components/post_list/date_header/utils';
|
||||
import FailedNetworkAction from 'app/components/failed_network_action';
|
||||
import NoResults from 'app/components/no_results';
|
||||
import PostSeparator from 'app/components/post_separator';
|
||||
|
|
@ -21,7 +22,6 @@ import StatusBar from 'app/components/status_bar';
|
|||
import mattermostManaged from 'app/mattermost_managed';
|
||||
import SearchResultPost from 'app/screens/search/search_result_post';
|
||||
import ChannelDisplayName from 'app/screens/search/channel_display_name';
|
||||
import {DATE_LINE} from 'app/selectors/post_list';
|
||||
import {changeOpacity} from 'app/utils/theme';
|
||||
|
||||
export default class RecentMentions extends PureComponent {
|
||||
|
|
@ -150,13 +150,10 @@ export default class RecentMentions extends PureComponent {
|
|||
renderPost = ({item, index}) => {
|
||||
const {postIds, theme} = this.props;
|
||||
const {managedConfig} = this.state;
|
||||
if (item.indexOf(DATE_LINE) === 0) {
|
||||
const date = new Date(item.substring(DATE_LINE.length));
|
||||
|
||||
if (isDateLine(item)) {
|
||||
return (
|
||||
<DateHeader
|
||||
key={`${date}-${index}`}
|
||||
date={date}
|
||||
dateLineString={item}
|
||||
index={index}
|
||||
/>
|
||||
);
|
||||
|
|
@ -164,7 +161,7 @@ export default class RecentMentions extends PureComponent {
|
|||
|
||||
let separator;
|
||||
const nextPost = postIds[index + 1];
|
||||
if (nextPost && nextPost.indexOf(DATE_LINE) === -1) {
|
||||
if (nextPost && !isDateLine(nextPost)) {
|
||||
separator = <PostSeparator theme={theme}/>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import {RequestStatus} from 'mattermost-redux/constants';
|
|||
|
||||
import Autocomplete from 'app/components/autocomplete';
|
||||
import DateHeader from 'app/components/post_list/date_header';
|
||||
import {isDateLine} from 'app/components/post_list/date_header/utils';
|
||||
import FormattedText from 'app/components/formatted_text';
|
||||
import Loading from 'app/components/loading';
|
||||
import PostListRetry from 'app/components/post_list_retry';
|
||||
|
|
@ -29,7 +30,6 @@ import SafeAreaView from 'app/components/safe_area_view';
|
|||
import SearchBar from 'app/components/search_bar';
|
||||
import StatusBar from 'app/components/status_bar';
|
||||
import mattermostManaged from 'app/mattermost_managed';
|
||||
import {DATE_LINE} from 'app/selectors/post_list';
|
||||
import {preventDoubleTap} from 'app/utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
|
|
@ -260,16 +260,6 @@ export default class Search extends PureComponent {
|
|||
actions.removeSearchTerms(currentTeamId, item.terms);
|
||||
});
|
||||
|
||||
renderDateHeader = (date, index) => {
|
||||
return (
|
||||
<DateHeader
|
||||
key={`${date}-${index}`}
|
||||
date={date}
|
||||
index={index}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
renderModifiers = ({item}) => {
|
||||
const {theme} = this.props;
|
||||
const style = getStyleFromTheme(theme);
|
||||
|
|
@ -317,14 +307,18 @@ export default class Search extends PureComponent {
|
|||
);
|
||||
}
|
||||
|
||||
if (item.indexOf(DATE_LINE) === 0) {
|
||||
const date = item.substring(DATE_LINE.length);
|
||||
return this.renderDateHeader(new Date(date), index);
|
||||
if (isDateLine(item)) {
|
||||
return (
|
||||
<DateHeader
|
||||
dateLineString={item}
|
||||
index={index}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
let separator;
|
||||
const nextPost = postIds[index + 1];
|
||||
if (nextPost && nextPost.indexOf(DATE_LINE) === -1) {
|
||||
if (nextPost && !isDateLine(nextPost)) {
|
||||
separator = <PostSeparator theme={theme}/>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {createIdsSelector} from 'mattermost-redux/utils/helpers';
|
|||
import {shouldFilterJoinLeavePost} from 'mattermost-redux/utils/post_utils';
|
||||
|
||||
export const DATE_LINE = 'date-';
|
||||
export const DATE_LINE_SUFFIX = '-index-';
|
||||
export const START_OF_NEW_MESSAGES = 'start-of-new-messages';
|
||||
|
||||
function shouldShowJoinLeaveMessages(state) {
|
||||
|
|
@ -56,7 +57,7 @@ export function makePreparePostIdsForPostList() {
|
|||
const postDate = new Date(post.create_at);
|
||||
|
||||
if (!lastDate || lastDate.toDateString() !== postDate.toDateString()) {
|
||||
out.push(DATE_LINE + postDate.toString());
|
||||
out.push(DATE_LINE + post.create_at);
|
||||
|
||||
lastDate = postDate;
|
||||
}
|
||||
|
|
@ -105,9 +106,14 @@ export function makePreparePostIdsForSearchPosts() {
|
|||
continue;
|
||||
}
|
||||
|
||||
const postDate = new Date(post.create_at);
|
||||
// Render a date line for each post, even if displayed on the same date as the
|
||||
// previous post. Since we don't deduplicate here like in other views, we need to
|
||||
// ensure the resulting key is unique, even if the post timestamps (down to the
|
||||
// second) are identical. The screens know to parse out the index before trying
|
||||
// to consume the date value.
|
||||
out.push(DATE_LINE + post.create_at + DATE_LINE_SUFFIX + i);
|
||||
|
||||
out.push(DATE_LINE + postDate.toString(), post.id);
|
||||
out.push(post.id);
|
||||
}
|
||||
|
||||
return out;
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@
|
|||
import assert from 'assert';
|
||||
|
||||
import {
|
||||
DATE_LINE,
|
||||
makePreparePostIdsForPostList,
|
||||
makePreparePostIdsForSearchPosts,
|
||||
START_OF_NEW_MESSAGES,
|
||||
} from 'app/selectors/post_list';
|
||||
|
||||
import {Posts, Preferences} from 'mattermost-redux/constants';
|
||||
import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils';
|
||||
|
||||
/* eslint-disable max-nested-callbacks, no-console */
|
||||
/* eslint-disable max-nested-callbacks */
|
||||
|
||||
describe('Selectors.PostList', () => {
|
||||
describe('makePreparePostIdsForPostList', () => {
|
||||
|
|
@ -44,7 +44,11 @@ describe('Selectors.PostList', () => {
|
|||
|
||||
// Defaults to show post
|
||||
let now = preparePostIdsForPostList(state, {postIds, lastViewedAt, indicateNewMessages});
|
||||
assert.deepEqual(removeDateLines(now), ['1002', '1001']);
|
||||
assert.deepEqual(now, [
|
||||
'1002',
|
||||
'1001',
|
||||
'date-0',
|
||||
]);
|
||||
|
||||
// Show join/leave posts
|
||||
state = {
|
||||
|
|
@ -66,7 +70,11 @@ describe('Selectors.PostList', () => {
|
|||
};
|
||||
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt, indicateNewMessages});
|
||||
assert.deepEqual(removeDateLines(now), ['1002', '1001']);
|
||||
assert.deepEqual(now, [
|
||||
'1002',
|
||||
'1001',
|
||||
'date-0',
|
||||
]);
|
||||
|
||||
// Hide join/leave posts
|
||||
state = {
|
||||
|
|
@ -88,7 +96,10 @@ describe('Selectors.PostList', () => {
|
|||
};
|
||||
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt, indicateNewMessages});
|
||||
assert.deepEqual(removeDateLines(now), ['1001']);
|
||||
assert.deepEqual(now, [
|
||||
'1001',
|
||||
'date-0',
|
||||
]);
|
||||
|
||||
// always show join/leave posts for the current user
|
||||
state = {
|
||||
|
|
@ -107,7 +118,11 @@ describe('Selectors.PostList', () => {
|
|||
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt, indicateNewMessages});
|
||||
|
||||
assert.deepEqual(removeDateLines(now), ['1002', '1001']);
|
||||
assert.deepEqual(now, [
|
||||
'1002',
|
||||
'1001',
|
||||
'date-0',
|
||||
]);
|
||||
});
|
||||
|
||||
it('new messages indicator', () => {
|
||||
|
|
@ -138,28 +153,66 @@ describe('Selectors.PostList', () => {
|
|||
|
||||
// Do not show new messages indicator before all posts
|
||||
let now = preparePostIdsForPostList(state, {postIds, lastViewedAt: 0, indicateNewMessages: true});
|
||||
assert.deepEqual(removeDateLines(now), ['1010', '1005', '1000']);
|
||||
assert.deepEqual(now, [
|
||||
'1010',
|
||||
'1005',
|
||||
'1000',
|
||||
'date-1000',
|
||||
]);
|
||||
|
||||
now = preparePostIdsForPostList(state, {postIds, indicateNewMessages: true});
|
||||
assert.deepEqual(removeDateLines(now), ['1010', '1005', '1000']);
|
||||
assert.deepEqual(now, [
|
||||
'1010',
|
||||
'1005',
|
||||
'1000',
|
||||
'date-1000',
|
||||
]);
|
||||
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt: 999, indicateNewMessages: false});
|
||||
assert.deepEqual(removeDateLines(now), ['1010', '1005', '1000']);
|
||||
assert.deepEqual(now, [
|
||||
'1010',
|
||||
'1005',
|
||||
'1000',
|
||||
'date-1000',
|
||||
]);
|
||||
|
||||
// Show new messages indicator before all posts
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt: 999, indicateNewMessages: true});
|
||||
assert.deepEqual(removeDateLines(now), ['1010', '1005', '1000', START_OF_NEW_MESSAGES]);
|
||||
assert.deepEqual(now, [
|
||||
'1010',
|
||||
'1005',
|
||||
'1000',
|
||||
START_OF_NEW_MESSAGES,
|
||||
'date-1000',
|
||||
]);
|
||||
|
||||
// Show indicator between posts
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt: 1003, indicateNewMessages: true});
|
||||
assert.deepEqual(removeDateLines(now), ['1010', '1005', START_OF_NEW_MESSAGES, '1000']);
|
||||
assert.deepEqual(now, [
|
||||
'1010',
|
||||
'1005',
|
||||
START_OF_NEW_MESSAGES,
|
||||
'1000',
|
||||
'date-1000',
|
||||
]);
|
||||
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt: 1006, indicateNewMessages: true});
|
||||
assert.deepEqual(removeDateLines(now), ['1010', START_OF_NEW_MESSAGES, '1005', '1000']);
|
||||
assert.deepEqual(now, [
|
||||
'1010',
|
||||
START_OF_NEW_MESSAGES,
|
||||
'1005',
|
||||
'1000',
|
||||
'date-1000',
|
||||
]);
|
||||
|
||||
// Don't show indicator when all posts are read
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt: 1020});
|
||||
assert.deepEqual(removeDateLines(now), ['1010', '1005', '1000']);
|
||||
assert.deepEqual(now, [
|
||||
'1010',
|
||||
'1005',
|
||||
'1000',
|
||||
'date-1000',
|
||||
]);
|
||||
});
|
||||
|
||||
it('memoization', () => {
|
||||
|
|
@ -197,17 +250,38 @@ describe('Selectors.PostList', () => {
|
|||
},
|
||||
};
|
||||
|
||||
let postIds = ['1006', '1004', '1003', '1001'];
|
||||
let postIds = [
|
||||
'1006',
|
||||
'1004',
|
||||
'1003',
|
||||
'1001',
|
||||
];
|
||||
let lastViewedAt = initialPosts['1001'].create_at + 1;
|
||||
|
||||
let now = preparePostIdsForPostList(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
assert.deepEqual(removeDateLines(now), ['1006', '1004', '1003', START_OF_NEW_MESSAGES, '1001']);
|
||||
assert.deepEqual(now, [
|
||||
'1006',
|
||||
'1004',
|
||||
'date-90000000',
|
||||
'1003',
|
||||
START_OF_NEW_MESSAGES,
|
||||
'1001',
|
||||
'date-3600000',
|
||||
]);
|
||||
|
||||
// No changes
|
||||
let prev = now;
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
assert.equal(now, prev);
|
||||
assert.deepEqual(removeDateLines(now), ['1006', '1004', '1003', START_OF_NEW_MESSAGES, '1001']);
|
||||
assert.deepEqual(now, [
|
||||
'1006',
|
||||
'1004',
|
||||
'date-90000000',
|
||||
'1003',
|
||||
START_OF_NEW_MESSAGES,
|
||||
'1001',
|
||||
'date-3600000',
|
||||
]);
|
||||
|
||||
// lastViewedAt changed slightly
|
||||
lastViewedAt = initialPosts['1001'].create_at + 2;
|
||||
|
|
@ -215,7 +289,15 @@ describe('Selectors.PostList', () => {
|
|||
prev = now;
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
assert.equal(now, prev);
|
||||
assert.deepEqual(removeDateLines(now), ['1006', '1004', '1003', START_OF_NEW_MESSAGES, '1001']);
|
||||
assert.deepEqual(now, [
|
||||
'1006',
|
||||
'1004',
|
||||
'date-90000000',
|
||||
'1003',
|
||||
START_OF_NEW_MESSAGES,
|
||||
'1001',
|
||||
'date-3600000',
|
||||
]);
|
||||
|
||||
// lastViewedAt changed a lot
|
||||
lastViewedAt += initialPosts['1003'].create_at + 1;
|
||||
|
|
@ -223,12 +305,28 @@ describe('Selectors.PostList', () => {
|
|||
prev = now;
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
assert.notEqual(now, prev);
|
||||
assert.deepEqual(removeDateLines(now), ['1006', '1004', START_OF_NEW_MESSAGES, '1003', '1001']);
|
||||
assert.deepEqual(now, [
|
||||
'1006',
|
||||
'1004',
|
||||
START_OF_NEW_MESSAGES,
|
||||
'date-90000000',
|
||||
'1003',
|
||||
'1001',
|
||||
'date-3600000',
|
||||
]);
|
||||
|
||||
prev = now;
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
assert.equal(now, prev);
|
||||
assert.deepEqual(removeDateLines(now), ['1006', '1004', START_OF_NEW_MESSAGES, '1003', '1001']);
|
||||
assert.deepEqual(now, [
|
||||
'1006',
|
||||
'1004',
|
||||
START_OF_NEW_MESSAGES,
|
||||
'date-90000000',
|
||||
'1003',
|
||||
'1001',
|
||||
'date-3600000',
|
||||
]);
|
||||
|
||||
// postIds changed, but still shallowly equal
|
||||
postIds = [...postIds];
|
||||
|
|
@ -236,7 +334,15 @@ describe('Selectors.PostList', () => {
|
|||
prev = now;
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
assert.equal(now, prev);
|
||||
assert.deepEqual(removeDateLines(now), ['1006', '1004', START_OF_NEW_MESSAGES, '1003', '1001']);
|
||||
assert.deepEqual(now, [
|
||||
'1006',
|
||||
'1004',
|
||||
START_OF_NEW_MESSAGES,
|
||||
'date-90000000',
|
||||
'1003',
|
||||
'1001',
|
||||
'date-3600000',
|
||||
]);
|
||||
|
||||
// Post changed, not in postIds
|
||||
state = {
|
||||
|
|
@ -256,7 +362,15 @@ describe('Selectors.PostList', () => {
|
|||
prev = now;
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
assert.equal(now, prev);
|
||||
assert.deepEqual(removeDateLines(now), ['1006', '1004', START_OF_NEW_MESSAGES, '1003', '1001']);
|
||||
assert.deepEqual(now, [
|
||||
'1006',
|
||||
'1004',
|
||||
START_OF_NEW_MESSAGES,
|
||||
'date-90000000',
|
||||
'1003',
|
||||
'1001',
|
||||
'date-3600000',
|
||||
]);
|
||||
|
||||
// Post changed, in postIds
|
||||
state = {
|
||||
|
|
@ -276,7 +390,15 @@ describe('Selectors.PostList', () => {
|
|||
prev = now;
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
assert.equal(now, prev);
|
||||
assert.deepEqual(removeDateLines(now), ['1006', '1004', START_OF_NEW_MESSAGES, '1003', '1001']);
|
||||
assert.deepEqual(now, [
|
||||
'1006',
|
||||
'1004',
|
||||
START_OF_NEW_MESSAGES,
|
||||
'date-90000000',
|
||||
'1003',
|
||||
'1001',
|
||||
'date-3600000',
|
||||
]);
|
||||
|
||||
// Filter changed
|
||||
state = {
|
||||
|
|
@ -300,17 +422,110 @@ describe('Selectors.PostList', () => {
|
|||
prev = now;
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
assert.notEqual(now, prev);
|
||||
assert.deepEqual(removeDateLines(now), ['1004', START_OF_NEW_MESSAGES, '1003', '1001']);
|
||||
assert.deepEqual(now, [
|
||||
'1004',
|
||||
START_OF_NEW_MESSAGES,
|
||||
'date-90000000',
|
||||
'1003',
|
||||
'1001',
|
||||
'date-3600000',
|
||||
]);
|
||||
|
||||
prev = now;
|
||||
now = preparePostIdsForPostList(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
assert.equal(now, prev);
|
||||
assert.deepEqual(removeDateLines(now), ['1004', START_OF_NEW_MESSAGES, '1003', '1001']);
|
||||
assert.deepEqual(now, [
|
||||
'1004',
|
||||
START_OF_NEW_MESSAGES,
|
||||
'date-90000000',
|
||||
'1003',
|
||||
'1001',
|
||||
'date-3600000',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('makePreparePostIdsForSearchPosts', () => {
|
||||
it('should return an empty array if there are no posts specified', () => {
|
||||
const preparePostIdsForSearchPosts = makePreparePostIdsForSearchPosts();
|
||||
|
||||
const state = {
|
||||
entities: {
|
||||
posts: {
|
||||
posts: {
|
||||
1001: {id: '1001', create_at: 0, type: ''},
|
||||
1002: {id: '1002', create_at: 1, type: ''},
|
||||
},
|
||||
},
|
||||
users: {
|
||||
currentUserId: '1234',
|
||||
profiles: {
|
||||
1234: {id: '1234', username: 'user'},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const postIds = [];
|
||||
const actual = preparePostIdsForSearchPosts(state, postIds);
|
||||
assert.deepEqual(actual, []);
|
||||
});
|
||||
|
||||
it('should return an empty array if there are no matching posts', () => {
|
||||
const preparePostIdsForSearchPosts = makePreparePostIdsForSearchPosts();
|
||||
|
||||
const state = {
|
||||
entities: {
|
||||
posts: {
|
||||
posts: {},
|
||||
},
|
||||
users: {
|
||||
currentUserId: '1234',
|
||||
profiles: {
|
||||
1234: {id: '1234', username: 'user'},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const postIds = ['1002', '1001'];
|
||||
const actual = preparePostIdsForSearchPosts(state, postIds);
|
||||
assert.deepEqual(actual, []);
|
||||
});
|
||||
|
||||
it('should return results when there are posts', () => {
|
||||
const preparePostIdsForSearchPosts = makePreparePostIdsForSearchPosts();
|
||||
|
||||
const state = {
|
||||
entities: {
|
||||
posts: {
|
||||
posts: {
|
||||
1001: {id: '1001', create_at: 0, type: ''},
|
||||
1002: {id: '1002', create_at: 1000, type: ''},
|
||||
|
||||
// Same timestamp as 1002
|
||||
1003: {id: '1003', create_at: 1000, type: ''},
|
||||
},
|
||||
},
|
||||
users: {
|
||||
currentUserId: '1234',
|
||||
profiles: {
|
||||
1234: {id: '1234', username: 'user'},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const postIds = ['1003', '1002', '1001'];
|
||||
const actual = preparePostIdsForSearchPosts(state, postIds);
|
||||
assert.deepEqual(actual, [
|
||||
'date-1000-index-0',
|
||||
'1003',
|
||||
'date-1000-index-1',
|
||||
'1002',
|
||||
'date-0-index-2',
|
||||
'1001',
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Remove date lines when checking equality since those depend on time-zone of the computer running the tests
|
||||
function removeDateLines(list) {
|
||||
return list.filter((item) => !item.startsWith(DATE_LINE));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue