mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-09-23 00:36:50 +08:00
574 lines
14 KiB
JavaScript
574 lines
14 KiB
JavaScript
const React = require('react');
|
|
const ReactDOM = require('react-dom');
|
|
const ReactTestUtils = require('react-dom/test-utils');
|
|
|
|
const {
|
|
Thread,
|
|
Contact,
|
|
Folder,
|
|
Message,
|
|
MessageStore,
|
|
MailspringTestUtils,
|
|
} = require('mailspring-exports');
|
|
|
|
const MessageParticipants = require('../lib/message-participants').default;
|
|
const MessageItemContainer = require('../lib/message-item-container').default;
|
|
const MessageList = require('../lib/message-list').default;
|
|
|
|
// User_1 needs to be "me" so that when we calculate who we should reply
|
|
// to, it properly matches the AccountStore
|
|
const user_1 = new Contact({
|
|
accountId: TEST_ACCOUNT_ID,
|
|
name: TEST_ACCOUNT_NAME,
|
|
email: TEST_ACCOUNT_EMAIL,
|
|
});
|
|
const user_2 = new Contact({
|
|
accountId: TEST_ACCOUNT_ID,
|
|
name: 'User Two',
|
|
email: 'user2@nylas.com',
|
|
});
|
|
const user_3 = new Contact({
|
|
accountId: TEST_ACCOUNT_ID,
|
|
name: 'User Three',
|
|
email: 'user3@nylas.com',
|
|
});
|
|
const user_4 = new Contact({
|
|
accountId: TEST_ACCOUNT_ID,
|
|
name: 'User Four',
|
|
email: 'user4@nylas.com',
|
|
});
|
|
const user_5 = new Contact({
|
|
accountId: TEST_ACCOUNT_ID,
|
|
name: 'User Five',
|
|
email: 'user5@nylas.com',
|
|
});
|
|
|
|
const m1 = new Message({
|
|
id: '111',
|
|
from: [user_1],
|
|
to: [user_2],
|
|
cc: [user_3, user_4],
|
|
bcc: null,
|
|
body: 'Body One',
|
|
date: new Date(1415814587),
|
|
draft: false,
|
|
files: [],
|
|
unread: false,
|
|
snippet: 'snippet one...',
|
|
subject: 'Subject One',
|
|
threadId: 'thread_12345',
|
|
accountId: TEST_ACCOUNT_ID,
|
|
folder: new Folder({ role: 'all', name: 'All Mail' }),
|
|
});
|
|
const m2 = new Message({
|
|
id: '222',
|
|
from: [user_2],
|
|
to: [user_1],
|
|
cc: [user_3, user_4],
|
|
bcc: null,
|
|
body: 'Body Two',
|
|
date: new Date(1415814587),
|
|
draft: false,
|
|
files: [],
|
|
unread: false,
|
|
snippet: 'snippet Two...',
|
|
subject: 'Subject Two',
|
|
threadId: 'thread_12345',
|
|
accountId: TEST_ACCOUNT_ID,
|
|
folder: new Folder({ role: 'all', name: 'All Mail' }),
|
|
});
|
|
const m3 = new Message({
|
|
id: '333',
|
|
from: [user_3],
|
|
to: [user_1],
|
|
cc: [user_2, user_4],
|
|
bcc: [],
|
|
body: 'Body Three',
|
|
date: new Date(1415814587),
|
|
draft: false,
|
|
files: [],
|
|
unread: false,
|
|
snippet: 'snippet Three...',
|
|
subject: 'Subject Three',
|
|
threadId: 'thread_12345',
|
|
accountId: TEST_ACCOUNT_ID,
|
|
folder: new Folder({ role: 'all', name: 'All Mail' }),
|
|
});
|
|
const m4 = new Message({
|
|
id: '444',
|
|
from: [user_4],
|
|
to: [user_1],
|
|
cc: [],
|
|
bcc: [user_5],
|
|
body: 'Body Four',
|
|
date: new Date(1415814587),
|
|
draft: false,
|
|
files: [],
|
|
unread: false,
|
|
snippet: 'snippet Four...',
|
|
subject: 'Subject Four',
|
|
threadId: 'thread_12345',
|
|
accountId: TEST_ACCOUNT_ID,
|
|
folder: new Folder({ role: 'all', name: 'All Mail' }),
|
|
});
|
|
const m5 = new Message({
|
|
id: '555',
|
|
from: [user_1],
|
|
to: [user_4],
|
|
cc: [],
|
|
bcc: [],
|
|
body: 'Body Five',
|
|
date: new Date(1415814587),
|
|
draft: false,
|
|
files: [],
|
|
unread: false,
|
|
snippet: 'snippet Five...',
|
|
subject: 'Subject Five',
|
|
threadId: 'thread_12345',
|
|
accountId: TEST_ACCOUNT_ID,
|
|
folder: new Folder({ role: 'all', name: 'All Mail' }),
|
|
});
|
|
const testMessages = [m1, m2, m3, m4, m5];
|
|
const draftMessages = [
|
|
new Message({
|
|
id: '666',
|
|
headerMessageId: 'asdasd-asd@mbbp.local',
|
|
from: [user_1],
|
|
to: [],
|
|
cc: [],
|
|
bcc: null,
|
|
body: 'Body One',
|
|
date: new Date(1415814587),
|
|
draft: true,
|
|
files: [],
|
|
unread: false,
|
|
snippet: 'draft snippet one...',
|
|
subject: 'Draft One',
|
|
threadId: 'thread_12345',
|
|
accountId: TEST_ACCOUNT_ID,
|
|
folder: new Folder({ role: 'all', name: 'All Mail' }),
|
|
}),
|
|
];
|
|
|
|
const testThread = new Thread({
|
|
id: 'thread_12345',
|
|
subject: 'Subject 12345',
|
|
accountId: TEST_ACCOUNT_ID,
|
|
});
|
|
|
|
describe('MessageList', function() {
|
|
beforeEach(function() {
|
|
MessageStore._items = [];
|
|
MessageStore._threadId = null;
|
|
spyOn(MessageStore, 'itemsLoading').andCallFake(() => false);
|
|
|
|
this.messageList = ReactTestUtils.renderIntoDocument(<MessageList />);
|
|
this.messageList_node = ReactDOM.findDOMNode(this.messageList);
|
|
});
|
|
|
|
it('renders into the document', function() {
|
|
expect(ReactTestUtils.isCompositeComponentWithType(this.messageList, MessageList)).toBe(true);
|
|
});
|
|
|
|
it('by default has zero children', function() {
|
|
const items = ReactTestUtils.scryRenderedComponentsWithType(
|
|
this.messageList,
|
|
MessageItemContainer
|
|
);
|
|
|
|
expect(items.length).toBe(0);
|
|
});
|
|
|
|
describe('Populated Message list', function() {
|
|
beforeEach(function() {
|
|
MessageStore._items = testMessages;
|
|
MessageStore._expandItemsToDefault();
|
|
MessageStore.trigger(MessageStore);
|
|
this.messageList.setState({ currentThread: testThread });
|
|
MailspringTestUtils.loadKeymap('keymaps/base');
|
|
});
|
|
|
|
it('renders all the correct number of messages', function() {
|
|
const items = ReactTestUtils.scryRenderedComponentsWithType(
|
|
this.messageList,
|
|
MessageItemContainer
|
|
);
|
|
expect(items.length).toBe(5);
|
|
});
|
|
|
|
it('renders the correct number of expanded messages', function() {
|
|
const msgs = ReactTestUtils.scryRenderedDOMComponentsWithClass(
|
|
this.messageList,
|
|
'collapsed message-item-wrap'
|
|
);
|
|
expect(msgs.length).toBe(4);
|
|
});
|
|
|
|
it('displays lists of participants on the page', function() {
|
|
const items = ReactTestUtils.scryRenderedComponentsWithType(
|
|
this.messageList,
|
|
MessageParticipants
|
|
);
|
|
expect(items.length).toBe(2);
|
|
});
|
|
|
|
it('includes drafts as message item containers', function() {
|
|
const msgs = this.messageList.state.messages;
|
|
this.messageList.setState({
|
|
messages: msgs.concat(draftMessages),
|
|
});
|
|
const items = ReactTestUtils.scryRenderedComponentsWithType(
|
|
this.messageList,
|
|
MessageItemContainer
|
|
);
|
|
expect(items.length).toBe(6);
|
|
});
|
|
});
|
|
|
|
describe('reply type', function() {
|
|
it("prompts for a reply when there's only one participant", function() {
|
|
MessageStore._items = [m3, m5];
|
|
MessageStore._thread = testThread;
|
|
MessageStore.trigger();
|
|
expect(this.messageList._replyType()).toBe('reply');
|
|
const cs = ReactTestUtils.scryRenderedDOMComponentsWithClass(
|
|
this.messageList,
|
|
'footer-reply-area'
|
|
);
|
|
expect(cs.length).toBe(1);
|
|
});
|
|
|
|
it("prompts for a reply-all when there's more than one participant and the default is reply-all", function() {
|
|
spyOn(AppEnv.config, 'get').andReturn('reply-all');
|
|
MessageStore._items = [m5, m3];
|
|
MessageStore._thread = testThread;
|
|
MessageStore.trigger();
|
|
expect(this.messageList._replyType()).toBe('reply-all');
|
|
const cs = ReactTestUtils.scryRenderedDOMComponentsWithClass(
|
|
this.messageList,
|
|
'footer-reply-area'
|
|
);
|
|
expect(cs.length).toBe(1);
|
|
});
|
|
|
|
it("prompts for a reply-all when there's more than one participant and the default is reply", function() {
|
|
spyOn(AppEnv.config, 'get').andReturn('reply');
|
|
MessageStore._items = [m5, m3];
|
|
MessageStore._thread = testThread;
|
|
MessageStore.trigger();
|
|
expect(this.messageList._replyType()).toBe('reply');
|
|
const cs = ReactTestUtils.scryRenderedDOMComponentsWithClass(
|
|
this.messageList,
|
|
'footer-reply-area'
|
|
);
|
|
expect(cs.length).toBe(1);
|
|
});
|
|
|
|
it('hides the reply type if the last message is a draft', function() {
|
|
MessageStore._items = [m5, m3, draftMessages[0]];
|
|
MessageStore._thread = testThread;
|
|
MessageStore.trigger();
|
|
const cs = ReactTestUtils.scryRenderedDOMComponentsWithClass(
|
|
this.messageList,
|
|
'footer-reply-area'
|
|
);
|
|
expect(cs.length).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe('Message minification', function() {
|
|
beforeEach(function() {
|
|
this.messageList.MINIFY_THRESHOLD = 3;
|
|
this.messageList.setState({ minified: true });
|
|
this.messages = [
|
|
{ id: 'a' },
|
|
{ id: 'b' },
|
|
{ id: 'c' },
|
|
{ id: 'd' },
|
|
{ id: 'e' },
|
|
{ id: 'f' },
|
|
{ id: 'g' },
|
|
];
|
|
});
|
|
|
|
it("ignores the first message if it's collapsed", function() {
|
|
this.messageList.setState({
|
|
messagesExpandedState: {
|
|
a: false,
|
|
b: false,
|
|
c: false,
|
|
d: false,
|
|
e: false,
|
|
f: false,
|
|
g: 'default',
|
|
},
|
|
});
|
|
|
|
const out = this.messageList._messagesWithMinification(this.messages);
|
|
expect(out).toEqual([
|
|
{ id: 'a' },
|
|
{
|
|
type: 'minifiedBundle',
|
|
messages: [{ id: 'b' }, { id: 'c' }, { id: 'd' }, { id: 'e' }],
|
|
},
|
|
{ id: 'f' },
|
|
{ id: 'g' },
|
|
]);
|
|
});
|
|
|
|
it("ignores the first message if it's expanded", function() {
|
|
this.messageList.setState({
|
|
messagesExpandedState: {
|
|
a: 'default',
|
|
b: false,
|
|
c: false,
|
|
d: false,
|
|
e: false,
|
|
f: false,
|
|
g: 'default',
|
|
},
|
|
});
|
|
|
|
const out = this.messageList._messagesWithMinification(this.messages);
|
|
expect(out).toEqual([
|
|
{ id: 'a' },
|
|
{
|
|
type: 'minifiedBundle',
|
|
messages: [{ id: 'b' }, { id: 'c' }, { id: 'd' }, { id: 'e' }],
|
|
},
|
|
{ id: 'f' },
|
|
{ id: 'g' },
|
|
]);
|
|
});
|
|
|
|
it("doesn't minify the last collapsed message", function() {
|
|
this.messageList.setState({
|
|
messagesExpandedState: {
|
|
a: false,
|
|
b: false,
|
|
c: false,
|
|
d: false,
|
|
e: false,
|
|
f: 'default',
|
|
g: 'default',
|
|
},
|
|
});
|
|
|
|
const out = this.messageList._messagesWithMinification(this.messages);
|
|
expect(out).toEqual([
|
|
{ id: 'a' },
|
|
{
|
|
type: 'minifiedBundle',
|
|
messages: [{ id: 'b' }, { id: 'c' }, { id: 'd' }],
|
|
},
|
|
{ id: 'e' },
|
|
{ id: 'f' },
|
|
{ id: 'g' },
|
|
]);
|
|
});
|
|
|
|
it('allows explicitly expanded messages', function() {
|
|
this.messageList.setState({
|
|
messagesExpandedState: {
|
|
a: false,
|
|
b: false,
|
|
c: false,
|
|
d: false,
|
|
e: false,
|
|
f: 'explicit',
|
|
g: 'default',
|
|
},
|
|
});
|
|
|
|
const out = this.messageList._messagesWithMinification(this.messages);
|
|
expect(out).toEqual([
|
|
{ id: 'a' },
|
|
{
|
|
type: 'minifiedBundle',
|
|
messages: [{ id: 'b' }, { id: 'c' }, { id: 'd' }, { id: 'e' }],
|
|
},
|
|
{ id: 'f' },
|
|
{ id: 'g' },
|
|
]);
|
|
});
|
|
|
|
it("doesn't minify if the threshold isn't reached", function() {
|
|
this.messageList.setState({
|
|
messagesExpandedState: {
|
|
a: false,
|
|
b: 'default',
|
|
c: false,
|
|
d: 'default',
|
|
e: false,
|
|
f: 'default',
|
|
g: 'default',
|
|
},
|
|
});
|
|
|
|
const out = this.messageList._messagesWithMinification(this.messages);
|
|
expect(out).toEqual([
|
|
{ id: 'a' },
|
|
{ id: 'b' },
|
|
{ id: 'c' },
|
|
{ id: 'd' },
|
|
{ id: 'e' },
|
|
{ id: 'f' },
|
|
{ id: 'g' },
|
|
]);
|
|
});
|
|
|
|
it("doesn't minify if the threshold isn't reached due to the rule about not minifying the last collapsed messages", function() {
|
|
this.messageList.setState({
|
|
messagesExpandedState: {
|
|
a: false,
|
|
b: false,
|
|
c: false,
|
|
d: false,
|
|
e: 'default',
|
|
f: 'default',
|
|
g: 'default',
|
|
},
|
|
});
|
|
|
|
const out = this.messageList._messagesWithMinification(this.messages);
|
|
expect(out).toEqual([
|
|
{ id: 'a' },
|
|
{ id: 'b' },
|
|
{ id: 'c' },
|
|
{ id: 'd' },
|
|
{ id: 'e' },
|
|
{ id: 'f' },
|
|
{ id: 'g' },
|
|
]);
|
|
});
|
|
|
|
it('minifies at the threshold if the message is explicitly expanded', function() {
|
|
this.messageList.setState({
|
|
messagesExpandedState: {
|
|
a: false,
|
|
b: false,
|
|
c: false,
|
|
d: false,
|
|
e: 'explicit',
|
|
f: 'default',
|
|
g: 'default',
|
|
},
|
|
});
|
|
|
|
const out = this.messageList._messagesWithMinification(this.messages);
|
|
expect(out).toEqual([
|
|
{ id: 'a' },
|
|
{
|
|
type: 'minifiedBundle',
|
|
messages: [{ id: 'b' }, { id: 'c' }, { id: 'd' }],
|
|
},
|
|
{ id: 'e' },
|
|
{ id: 'f' },
|
|
{ id: 'g' },
|
|
]);
|
|
});
|
|
|
|
it('can have multiple minification blocks', function() {
|
|
const messages = [
|
|
{ id: 'a' },
|
|
{ id: 'b' },
|
|
{ id: 'c' },
|
|
{ id: 'd' },
|
|
{ id: 'e' },
|
|
{ id: 'f' },
|
|
{ id: 'g' },
|
|
{ id: 'h' },
|
|
{ id: 'i' },
|
|
{ id: 'j' },
|
|
{ id: 'k' },
|
|
{ id: 'l' },
|
|
];
|
|
|
|
this.messageList.setState({
|
|
messagesExpandedState: {
|
|
a: false,
|
|
b: false,
|
|
c: false,
|
|
d: false,
|
|
e: false,
|
|
f: 'default',
|
|
g: false,
|
|
h: false,
|
|
i: false,
|
|
j: false,
|
|
k: false,
|
|
l: 'default',
|
|
},
|
|
});
|
|
|
|
const out = this.messageList._messagesWithMinification(messages);
|
|
expect(out).toEqual([
|
|
{ id: 'a' },
|
|
{
|
|
type: 'minifiedBundle',
|
|
messages: [{ id: 'b' }, { id: 'c' }, { id: 'd' }],
|
|
},
|
|
{ id: 'e' },
|
|
{ id: 'f' },
|
|
{
|
|
type: 'minifiedBundle',
|
|
messages: [{ id: 'g' }, { id: 'h' }, { id: 'i' }, { id: 'j' }],
|
|
},
|
|
{ id: 'k' },
|
|
{ id: 'l' },
|
|
]);
|
|
});
|
|
|
|
it('can have multiple minification blocks next to explicitly expanded messages', function() {
|
|
const messages = [
|
|
{ id: 'a' },
|
|
{ id: 'b' },
|
|
{ id: 'c' },
|
|
{ id: 'd' },
|
|
{ id: 'e' },
|
|
{ id: 'f' },
|
|
{ id: 'g' },
|
|
{ id: 'h' },
|
|
{ id: 'i' },
|
|
{ id: 'j' },
|
|
{ id: 'k' },
|
|
{ id: 'l' },
|
|
];
|
|
|
|
this.messageList.setState({
|
|
messagesExpandedState: {
|
|
a: false,
|
|
b: false,
|
|
c: false,
|
|
d: false,
|
|
e: 'explicit',
|
|
f: 'default',
|
|
g: false,
|
|
h: false,
|
|
i: false,
|
|
j: false,
|
|
k: 'explicit',
|
|
l: 'default',
|
|
},
|
|
});
|
|
|
|
const out = this.messageList._messagesWithMinification(messages);
|
|
expect(out).toEqual([
|
|
{ id: 'a' },
|
|
{
|
|
type: 'minifiedBundle',
|
|
messages: [{ id: 'b' }, { id: 'c' }, { id: 'd' }],
|
|
},
|
|
{ id: 'e' },
|
|
{ id: 'f' },
|
|
{
|
|
type: 'minifiedBundle',
|
|
messages: [{ id: 'g' }, { id: 'h' }, { id: 'i' }, { id: 'j' }],
|
|
},
|
|
{ id: 'k' },
|
|
{ id: 'l' },
|
|
]);
|
|
});
|
|
});
|
|
});
|