Mailspring/app/spec/components/participants-text-field-spec.tsx
Ben Gotow 149b389508
Replace Babel with TypeScript compiler, switch entire app to TypeScript 🎉 (#1404)
* Switch to using Typescript instead of Babel

* Switch all es6 / jsx file extensions to ts / tsx

* Convert Utils to a TS module from module.exports style module

* Move everything from module.exports to typescript exports

* Define .d.ts files for mailspring-exports and component kit… Yes it seems this is the best option :(

* Load up on those @types

* Synthesize TS types from PropTypes for standard components

* Add types to Model classes and move constructor constants to instance vars

* 9800 => 7700 TS errors

* 7700 => 5600 TS errors

* 5600 => 5330 TS errors

* 5330 => 4866 TS errors

* 4866 => 4426 TS errors

* 4426 => 2411 TS errors

* 2411 > 1598 TS errors

* 1598 > 769 TS errors

* 769 > 129 TS errors

* 129 > 22 TS errors

* Fix runtime errors

* More runtime error fixes

* Remove support for custom .es6 file extension

* Remove a few odd remaining references to Nylas

* Don’t ship Typescript support in the compiled app for now

* Fix issues in compiled app - module resolution in TS is case sensitive?

* README updates

* Fix a few more TS errors

* Make “No Signature” option clickable + selectable

* Remove flicker when saving file and reloading keymaps

* Fix mail rule item height in preferences

* Fix missing spacing in thread sharing popover

* Fix scrollbar ticks being nested incorrectly

* Add Japanese as a manually reviewed language

* Prevent the thread list from “sticking”

* Re-use Sheet when switching root tabs, prevent sidebar from resetting

* Ensure specs run

* Update package configuration to avoid shpping types

* Turn eslint back on - we will opt-in to the TS rules one by one
2019-03-04 11:03:12 -08:00

210 lines
6.8 KiB
TypeScript

import React from 'react';
import { mount } from 'enzyme';
import { ContactStore, Contact } from 'mailspring-exports';
import { ParticipantsTextField } from 'mailspring-component-kit';
const participant1 = new Contact({
id: 'local-1',
email: 'ben@mailspring.com',
});
const participant2 = new Contact({
id: 'local-2',
email: 'ben@example.com',
name: 'Ben Gotow',
});
const participant3 = new Contact({
id: 'local-3',
email: 'evan@mailspring.com',
name: 'Evan Morikawa',
});
xdescribe('ParticipantsTextField', function ParticipantsTextFieldSpecs() {
beforeEach(() => {
spyOn(AppEnv, 'isMainWindow').andReturn(true);
this.propChange = jasmine.createSpy('change');
this.fieldName = 'to';
this.participants = {
to: [participant1, participant2],
cc: [participant3],
bcc: [],
};
this.renderedField = mount(
<ParticipantsTextField
field={this.fieldName}
menuPrompt={this.fieldName}
visible
participants={this.participants}
draft={{ id: 'draft-1' }}
session={{}}
change={this.propChange}
/>
);
this.renderedInput = this.renderedField.find('input');
this.expectInputToYield = (input, expected) => {
const reviver = function reviver(k, v) {
if (k === 'id' || k === 'client_id' || k === 'server_id' || k === 'object') {
return undefined;
}
return v;
};
runs(() => {
this.renderedInput.simulate('change', { target: { value: input } });
advanceClock(100);
return this.renderedInput.simulate('keyDown', { key: 'Enter', keyCode: 9 });
});
waitsFor(() => {
return this.propChange.calls.length > 0;
});
runs(() => {
let found = this.propChange.mostRecentCall.args[0];
found = JSON.parse(JSON.stringify(found), reviver);
expect(found).toEqual(JSON.parse(JSON.stringify(expected), reviver));
// This advance clock needs to be here because our waitsFor latch
// catches the first time that propChange gets called. More stuff
// may happen after this and we need to advance the clock to
// "clear" all of that. If we don't do this it throws errors about
// `setState` being called on unmounted components :(
return advanceClock(100);
});
};
});
it('renders into the document', () => {
expect(this.renderedField.find(ParticipantsTextField).length).toBe(1);
});
describe('inserting participant text', () => {
it('should fire onChange with an updated participants hash', () => {
this.expectInputToYield('abc@abc.com', {
to: [
participant1,
participant2,
new Contact({ name: 'abc@abc.com', email: 'abc@abc.com' }),
],
cc: [participant3],
bcc: [],
});
});
it('should remove added participants from other fields', () => {
this.expectInputToYield(participant3.email, {
to: [
participant1,
participant2,
new Contact({ name: participant3.email, email: participant3.email }),
],
cc: [],
bcc: [],
});
});
it('should use the name of an existing contact in the ContactStore if possible', () => {
spyOn(ContactStore, 'searchContacts').andCallFake(val => {
if (val === participant3.name) {
return Promise.resolve([participant3]);
}
return Promise.resolve([]);
});
this.expectInputToYield(participant3.name, {
to: [participant1, participant2, participant3],
cc: [],
bcc: [],
});
});
it("should use the plain email if that's what's entered", () => {
spyOn(ContactStore, 'searchContacts').andCallFake(val => {
if (val === participant3.name) {
return Promise.resolve([participant3]);
}
return Promise.resolve([]);
});
this.expectInputToYield(participant3.email, {
to: [participant1, participant2, new Contact({ email: 'evan@mailspring.com' })],
cc: [],
bcc: [],
});
});
it('should not have the same contact auto-picked multiple times', () => {
spyOn(ContactStore, 'searchContacts').andCallFake(val => {
if (val === participant2.name) {
return Promise.resolve([participant2]);
}
return Promise.resolve([]);
});
this.expectInputToYield(participant2.name, {
to: [
participant1,
participant2,
new Contact({ email: participant2.name, name: participant2.name }),
],
cc: [participant3],
bcc: [],
});
});
describe('when text contains Name (Email) formatted data', () => {
it('should correctly parse it into named Contact objects', () => {
const newContact1 = new Contact({
id: 'b1',
name: 'Ben Imposter',
email: 'imposter@mailspring.com',
});
const newContact2 = new Contact({ name: 'Mailspring Team', email: 'feedback@mailspring.com' });
const inputs = [
'Ben Imposter <imposter@mailspring.com>, Mailspring Team <feedback@mailspring.com>',
'\n\nbla\nBen Imposter (imposter@mailspring.com), Mailspring Team (feedback@mailspring.com)',
'Hello world! I like cheese. \rBen Imposter (imposter@mailspring.com)\nMailspring Team (feedback@mailspring.com)',
'Ben Imposter<imposter@mailspring.com>Mailspring Team (feedback@mailspring.com)',
];
for (const input of inputs) {
this.expectInputToYield(input, {
to: [participant1, participant2, newContact1, newContact2],
cc: [participant3],
bcc: [],
});
}
});
});
describe('when text contains emails mixed with garbage text', () => {
it('should still parse out emails into Contact objects', () => {
const newContact1 = new Contact({
id: 'gm',
name: 'garbage-man@mailspring.com',
email: 'garbage-man@mailspring.com',
});
const newContact2 = new Contact({
id: 'rm',
name: 'recycling-guy@mailspring.com',
email: 'recycling-guy@mailspring.com',
});
const inputs = [
"Hello world I real. \n asd. garbage-man@mailspring.com—he's cool Also 'recycling-guy@mailspring.com'!",
'garbage-man@mailspring.com1WHOA I REALLY HATE DATA,recycling-guy@mailspring.com',
'nils.com garbage-man@mailspring.com @mailspring.com nope@.com nope! recycling-guy@mailspring.com HOLLA AT recycling-guy@mailspring.',
];
for (const input of inputs) {
this.expectInputToYield(input, {
to: [participant1, participant2, newContact1, newContact2],
cc: [participant3],
bcc: [],
});
}
});
});
});
});