2015-11-12 04:49:48 +08:00
|
|
|
import fs from 'fs';
|
2016-04-13 09:09:13 +08:00
|
|
|
import { remote } from 'electron';
|
2015-11-12 04:49:48 +08:00
|
|
|
import {Message, DraftStore} from 'nylas-exports';
|
|
|
|
import TemplateStore from '../lib/template-store';
|
|
|
|
|
2016-04-13 09:09:13 +08:00
|
|
|
const { shell } = remote;
|
|
|
|
|
2015-11-12 04:49:48 +08:00
|
|
|
const stubTemplatesDir = '~/.nylas/templates';
|
|
|
|
|
|
|
|
const stubTemplateFiles = {
|
|
|
|
'template1.html': '<p>bla1</p>',
|
|
|
|
'template2.html': '<p>bla2</p>',
|
|
|
|
};
|
|
|
|
|
|
|
|
const stubTemplates = [
|
|
|
|
{id: 'template1.html', name: 'template1', path: `${stubTemplatesDir}/template1.html`},
|
|
|
|
{id: 'template2.html', name: 'template2', path: `${stubTemplatesDir}/template2.html`},
|
|
|
|
];
|
|
|
|
|
|
|
|
describe('TemplateStore', ()=> {
|
|
|
|
beforeEach(()=> {
|
|
|
|
spyOn(fs, 'mkdir');
|
|
|
|
spyOn(shell, 'showItemInFolder').andCallFake(()=> {});
|
|
|
|
spyOn(fs, 'writeFile').andCallFake((path, contents, callback)=> {
|
|
|
|
callback(null);
|
|
|
|
});
|
|
|
|
spyOn(fs, 'readFile').andCallFake((path, callback)=> {
|
|
|
|
const filename = path.split('/').pop();
|
|
|
|
callback(null, stubTemplateFiles[filename]);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should create the templates folder if it does not exist', ()=> {
|
|
|
|
spyOn(fs, 'exists').andCallFake((path, callback)=> callback(false) );
|
refactor(templates): major additions and refactoring for the Templates plugin.
Summary:
Adds several new features to the templates plugin, fixes some existing bugs, and
refactors existing code.
New Plugin Features/Fixes:
- Changes the templates editor in preferences to allow variables to be entered with
`{{brackets}}`. Handles many contenteditable complexities to implement.
- Better interaction for renaming and deleting of templates in the editor.
- Changes tabbing behavior when using templates. Tabbing between variables now wraps
around, and typing tab from outside a variable region highlights the closest region.
- Prevents "Enter" key in the composer when inside a variable region, and strips all
formatting/tags from within the region - this prevents major contenteditable issues
that can result in inline CSS in the style of our variable regions, which will not be
removed when sending.
- Shows a warning when choosing a template if it will replace existing text in a draft.
- Prevents invalid characters in template names (due to filenames, esp. on Windows),
and shows an error message. Strips these characters from draft titles when making a
template.
- Fixes a bug where TemplateStore's initialization code was being called multiple times.
New N1 code:
- Several new methods in `DOMUtils` useful for working with contenteditable.
- Implement some missing methods in `Editor`
Refactor:
- Major refactor/rewrite of template composer extension to use new DOMUtils methods
and simplify the logic (while adding new functionality).
Remaining issues:
- `preferences-tempaltes.cjsx` and `template-editor.coffee` should be rewritten in ES6
for consistency
- Need tests for new DOMUtils functions and for new Templates plugin code.
Test Plan: manual, need to update specs
Reviewers: evan, bengotow
Reviewed By: evan, bengotow
Subscribers: juan
Differential Revision: https://phab.nylas.com/D2382
2015-12-30 07:11:04 +08:00
|
|
|
TemplateStore._init(stubTemplatesDir);
|
2015-11-12 04:49:48 +08:00
|
|
|
expect(fs.mkdir).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should expose templates in the templates directory', ()=> {
|
|
|
|
let watchCallback;
|
|
|
|
spyOn(fs, 'exists').andCallFake((path, callback)=> { callback(true); });
|
|
|
|
spyOn(fs, 'watch').andCallFake((path, callback)=> watchCallback = callback);
|
|
|
|
spyOn(fs, 'readdir').andCallFake((path, callback)=> { callback(null, Object.keys(stubTemplateFiles)); });
|
refactor(templates): major additions and refactoring for the Templates plugin.
Summary:
Adds several new features to the templates plugin, fixes some existing bugs, and
refactors existing code.
New Plugin Features/Fixes:
- Changes the templates editor in preferences to allow variables to be entered with
`{{brackets}}`. Handles many contenteditable complexities to implement.
- Better interaction for renaming and deleting of templates in the editor.
- Changes tabbing behavior when using templates. Tabbing between variables now wraps
around, and typing tab from outside a variable region highlights the closest region.
- Prevents "Enter" key in the composer when inside a variable region, and strips all
formatting/tags from within the region - this prevents major contenteditable issues
that can result in inline CSS in the style of our variable regions, which will not be
removed when sending.
- Shows a warning when choosing a template if it will replace existing text in a draft.
- Prevents invalid characters in template names (due to filenames, esp. on Windows),
and shows an error message. Strips these characters from draft titles when making a
template.
- Fixes a bug where TemplateStore's initialization code was being called multiple times.
New N1 code:
- Several new methods in `DOMUtils` useful for working with contenteditable.
- Implement some missing methods in `Editor`
Refactor:
- Major refactor/rewrite of template composer extension to use new DOMUtils methods
and simplify the logic (while adding new functionality).
Remaining issues:
- `preferences-tempaltes.cjsx` and `template-editor.coffee` should be rewritten in ES6
for consistency
- Need tests for new DOMUtils functions and for new Templates plugin code.
Test Plan: manual, need to update specs
Reviewers: evan, bengotow
Reviewed By: evan, bengotow
Subscribers: juan
Differential Revision: https://phab.nylas.com/D2382
2015-12-30 07:11:04 +08:00
|
|
|
TemplateStore._init(stubTemplatesDir);
|
2015-11-12 04:49:48 +08:00
|
|
|
watchCallback();
|
|
|
|
expect(TemplateStore.items()).toEqual(stubTemplates);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should watch the templates directory and reflect changes', ()=> {
|
|
|
|
let watchCallback = null;
|
|
|
|
let watchFired = false;
|
|
|
|
|
|
|
|
spyOn(fs, 'exists').andCallFake((path, callback)=> callback(true));
|
|
|
|
spyOn(fs, 'watch').andCallFake((path, callback)=> watchCallback = callback);
|
|
|
|
spyOn(fs, 'readdir').andCallFake((path, callback)=> {
|
|
|
|
if (watchFired) {
|
|
|
|
callback(null, Object.keys(stubTemplateFiles));
|
|
|
|
} else {
|
|
|
|
callback(null, []);
|
|
|
|
}
|
|
|
|
});
|
refactor(templates): major additions and refactoring for the Templates plugin.
Summary:
Adds several new features to the templates plugin, fixes some existing bugs, and
refactors existing code.
New Plugin Features/Fixes:
- Changes the templates editor in preferences to allow variables to be entered with
`{{brackets}}`. Handles many contenteditable complexities to implement.
- Better interaction for renaming and deleting of templates in the editor.
- Changes tabbing behavior when using templates. Tabbing between variables now wraps
around, and typing tab from outside a variable region highlights the closest region.
- Prevents "Enter" key in the composer when inside a variable region, and strips all
formatting/tags from within the region - this prevents major contenteditable issues
that can result in inline CSS in the style of our variable regions, which will not be
removed when sending.
- Shows a warning when choosing a template if it will replace existing text in a draft.
- Prevents invalid characters in template names (due to filenames, esp. on Windows),
and shows an error message. Strips these characters from draft titles when making a
template.
- Fixes a bug where TemplateStore's initialization code was being called multiple times.
New N1 code:
- Several new methods in `DOMUtils` useful for working with contenteditable.
- Implement some missing methods in `Editor`
Refactor:
- Major refactor/rewrite of template composer extension to use new DOMUtils methods
and simplify the logic (while adding new functionality).
Remaining issues:
- `preferences-tempaltes.cjsx` and `template-editor.coffee` should be rewritten in ES6
for consistency
- Need tests for new DOMUtils functions and for new Templates plugin code.
Test Plan: manual, need to update specs
Reviewers: evan, bengotow
Reviewed By: evan, bengotow
Subscribers: juan
Differential Revision: https://phab.nylas.com/D2382
2015-12-30 07:11:04 +08:00
|
|
|
TemplateStore._init(stubTemplatesDir);
|
2015-11-12 04:49:48 +08:00
|
|
|
expect(TemplateStore.items()).toEqual([]);
|
|
|
|
|
|
|
|
watchFired = true;
|
|
|
|
watchCallback();
|
|
|
|
expect(TemplateStore.items()).toEqual(stubTemplates);
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('insertTemplateId', ()=> {
|
2016-01-08 13:13:07 +08:00
|
|
|
xit('should insert the template with the given id into the draft with the given id', ()=> {
|
2015-11-12 04:49:48 +08:00
|
|
|
let watchCallback;
|
|
|
|
spyOn(fs, 'exists').andCallFake((path, callback)=> { callback(true); });
|
|
|
|
spyOn(fs, 'watch').andCallFake((path, callback)=> watchCallback = callback);
|
|
|
|
spyOn(fs, 'readdir').andCallFake((path, callback)=> { callback(null, Object.keys(stubTemplateFiles)); });
|
refactor(templates): major additions and refactoring for the Templates plugin.
Summary:
Adds several new features to the templates plugin, fixes some existing bugs, and
refactors existing code.
New Plugin Features/Fixes:
- Changes the templates editor in preferences to allow variables to be entered with
`{{brackets}}`. Handles many contenteditable complexities to implement.
- Better interaction for renaming and deleting of templates in the editor.
- Changes tabbing behavior when using templates. Tabbing between variables now wraps
around, and typing tab from outside a variable region highlights the closest region.
- Prevents "Enter" key in the composer when inside a variable region, and strips all
formatting/tags from within the region - this prevents major contenteditable issues
that can result in inline CSS in the style of our variable regions, which will not be
removed when sending.
- Shows a warning when choosing a template if it will replace existing text in a draft.
- Prevents invalid characters in template names (due to filenames, esp. on Windows),
and shows an error message. Strips these characters from draft titles when making a
template.
- Fixes a bug where TemplateStore's initialization code was being called multiple times.
New N1 code:
- Several new methods in `DOMUtils` useful for working with contenteditable.
- Implement some missing methods in `Editor`
Refactor:
- Major refactor/rewrite of template composer extension to use new DOMUtils methods
and simplify the logic (while adding new functionality).
Remaining issues:
- `preferences-tempaltes.cjsx` and `template-editor.coffee` should be rewritten in ES6
for consistency
- Need tests for new DOMUtils functions and for new Templates plugin code.
Test Plan: manual, need to update specs
Reviewers: evan, bengotow
Reviewed By: evan, bengotow
Subscribers: juan
Differential Revision: https://phab.nylas.com/D2382
2015-12-30 07:11:04 +08:00
|
|
|
TemplateStore._init(stubTemplatesDir);
|
2015-11-12 04:49:48 +08:00
|
|
|
watchCallback();
|
|
|
|
const add = jasmine.createSpy('add');
|
|
|
|
spyOn(DraftStore, 'sessionForClientId').andCallFake(()=> {
|
|
|
|
return Promise.resolve({changes: {add}});
|
|
|
|
});
|
|
|
|
|
|
|
|
runs(()=> {
|
|
|
|
TemplateStore._onInsertTemplateId({
|
|
|
|
templateId: 'template1.html',
|
|
|
|
draftClientId: 'localid-draft',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
waitsFor(()=> add.calls.length > 0);
|
|
|
|
runs(()=> {
|
|
|
|
expect(add).toHaveBeenCalledWith({
|
|
|
|
body: stubTemplateFiles['template1.html'],
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('onCreateTemplate', ()=> {
|
|
|
|
beforeEach(()=> {
|
|
|
|
let d;
|
|
|
|
spyOn(DraftStore, 'sessionForClientId').andCallFake((draftClientId)=> {
|
|
|
|
if (draftClientId === 'localid-nosubject') {
|
|
|
|
d = new Message({subject: '', body: '<p>Body</p>'});
|
|
|
|
} else {
|
|
|
|
d = new Message({subject: 'Subject', body: '<p>Body</p>'});
|
|
|
|
}
|
|
|
|
const session = {draft() { return d; }};
|
|
|
|
return Promise.resolve(session);
|
|
|
|
});
|
refactor(templates): major additions and refactoring for the Templates plugin.
Summary:
Adds several new features to the templates plugin, fixes some existing bugs, and
refactors existing code.
New Plugin Features/Fixes:
- Changes the templates editor in preferences to allow variables to be entered with
`{{brackets}}`. Handles many contenteditable complexities to implement.
- Better interaction for renaming and deleting of templates in the editor.
- Changes tabbing behavior when using templates. Tabbing between variables now wraps
around, and typing tab from outside a variable region highlights the closest region.
- Prevents "Enter" key in the composer when inside a variable region, and strips all
formatting/tags from within the region - this prevents major contenteditable issues
that can result in inline CSS in the style of our variable regions, which will not be
removed when sending.
- Shows a warning when choosing a template if it will replace existing text in a draft.
- Prevents invalid characters in template names (due to filenames, esp. on Windows),
and shows an error message. Strips these characters from draft titles when making a
template.
- Fixes a bug where TemplateStore's initialization code was being called multiple times.
New N1 code:
- Several new methods in `DOMUtils` useful for working with contenteditable.
- Implement some missing methods in `Editor`
Refactor:
- Major refactor/rewrite of template composer extension to use new DOMUtils methods
and simplify the logic (while adding new functionality).
Remaining issues:
- `preferences-tempaltes.cjsx` and `template-editor.coffee` should be rewritten in ES6
for consistency
- Need tests for new DOMUtils functions and for new Templates plugin code.
Test Plan: manual, need to update specs
Reviewers: evan, bengotow
Reviewed By: evan, bengotow
Subscribers: juan
Differential Revision: https://phab.nylas.com/D2382
2015-12-30 07:11:04 +08:00
|
|
|
TemplateStore._init(stubTemplatesDir);
|
2015-11-12 04:49:48 +08:00
|
|
|
});
|
|
|
|
|
2016-01-08 13:13:07 +08:00
|
|
|
xit('should create a template with the given name and contents', ()=> {
|
2015-11-12 04:49:48 +08:00
|
|
|
const ref = TemplateStore.items();
|
|
|
|
TemplateStore._onCreateTemplate({name: '123', contents: 'bla'});
|
|
|
|
const item = (ref != null ? ref[0] : undefined);
|
|
|
|
expect(item.id).toBe('123.html');
|
|
|
|
expect(item.name).toBe('123');
|
|
|
|
expect(item.path.split('/').pop()).toBe('123.html');
|
|
|
|
});
|
|
|
|
|
2016-01-08 13:13:07 +08:00
|
|
|
xit('should display an error if no name is provided', ()=> {
|
2015-11-12 04:49:48 +08:00
|
|
|
spyOn(TemplateStore, '_displayError');
|
|
|
|
TemplateStore._onCreateTemplate({contents: 'bla'});
|
|
|
|
expect(TemplateStore._displayError).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
2016-01-08 13:13:07 +08:00
|
|
|
xit('should display an error if no content is provided', ()=> {
|
2015-11-12 04:49:48 +08:00
|
|
|
spyOn(TemplateStore, '_displayError');
|
|
|
|
TemplateStore._onCreateTemplate({name: 'bla'});
|
|
|
|
expect(TemplateStore._displayError).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
2016-01-08 13:13:07 +08:00
|
|
|
xit('should save the template file to the templates folder', ()=> {
|
2015-11-12 04:49:48 +08:00
|
|
|
TemplateStore._onCreateTemplate({name: '123', contents: 'bla'});
|
|
|
|
const path = `${stubTemplatesDir}/123.html`;
|
|
|
|
expect(fs.writeFile).toHaveBeenCalled();
|
|
|
|
expect(fs.writeFile.mostRecentCall.args[0]).toEqual(path);
|
|
|
|
expect(fs.writeFile.mostRecentCall.args[1]).toEqual('bla');
|
|
|
|
});
|
|
|
|
|
2016-01-08 13:13:07 +08:00
|
|
|
xit('should open the template so you can see it', ()=> {
|
2015-11-12 04:49:48 +08:00
|
|
|
TemplateStore._onCreateTemplate({name: '123', contents: 'bla'});
|
|
|
|
expect(shell.showItemInFolder).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('when given a draft id', ()=> {
|
2016-01-08 13:13:07 +08:00
|
|
|
xit('should create a template from the name and contents of the given draft', ()=> {
|
2015-11-12 04:49:48 +08:00
|
|
|
spyOn(TemplateStore, 'trigger');
|
|
|
|
spyOn(TemplateStore, '_populate');
|
|
|
|
runs(()=> {
|
|
|
|
TemplateStore._onCreateTemplate({draftClientId: 'localid-b'});
|
|
|
|
});
|
|
|
|
waitsFor(()=> TemplateStore.trigger.callCount > 0 );
|
|
|
|
runs(()=> {
|
|
|
|
expect(TemplateStore.items().length).toEqual(1);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should display an error if the draft has no subject', ()=> {
|
|
|
|
spyOn(TemplateStore, '_displayError');
|
2016-01-09 02:52:37 +08:00
|
|
|
spyOn(fs, 'watch');
|
2015-11-12 04:49:48 +08:00
|
|
|
runs(()=> {
|
|
|
|
TemplateStore._onCreateTemplate({draftClientId: 'localid-nosubject'});
|
|
|
|
});
|
|
|
|
waitsFor(()=> TemplateStore._displayError.callCount > 0 );
|
|
|
|
runs(()=> {
|
|
|
|
expect(TemplateStore._displayError).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('onShowTemplates', ()=> {
|
2016-01-08 13:13:07 +08:00
|
|
|
xit('should open the templates folder in the Finder', ()=> {
|
2015-11-12 04:49:48 +08:00
|
|
|
TemplateStore._onShowTemplates();
|
|
|
|
expect(shell.showItemInFolder).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|