mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-02-28 10:05:03 +08:00
[local-sync] fix(specs): run npm test
in local-sync dir
This commit is contained in:
parent
017e22c88d
commit
30c8bedd7a
17 changed files with 117 additions and 296 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -19,3 +19,4 @@ newrelic_agent.log
|
|||
.elasticbeanstalk/*
|
||||
!.elasticbeanstalk/*.cfg.yml
|
||||
!.elasticbeanstalk/*.global.yml
|
||||
/packages/local-sync/spec-saved-state.json
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
"utf7": "^1.0.2",
|
||||
"vision": "4.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "../../../../node_modules/.bin/electron ../../../../ --test --spec-directory=$(pwd)/spec"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/nylas/K2.git"
|
||||
|
|
5
packages/local-sync/spec/fixtures/MessageFactory/parseFromImap/base-case.json
vendored
Normal file
5
packages/local-sync/spec/fixtures/MessageFactory/parseFromImap/base-case.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"imapMessage": {},
|
||||
"desiredParts": {},
|
||||
"result": {}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
const {PromiseUtils} = require('isomorphic-core');
|
||||
const mockDatabase = require('./mock-database');
|
||||
const FetchFolderList = require('../../src/local-sync-worker/imap/fetch-folder-list')
|
||||
|
||||
const testCategoryRoles = (db, mailboxes) => {
|
||||
const mockLogger = {
|
||||
info: () => {},
|
||||
debug: () => {},
|
||||
error: () => {},
|
||||
}
|
||||
const mockImap = {
|
||||
getBoxes: () => {
|
||||
return Promise.resolve(mailboxes)
|
||||
},
|
||||
}
|
||||
return new FetchFolderList('fakeProvider', mockLogger).run(db, mockImap).then(() => {
|
||||
const {Folder, Label} = db;
|
||||
return PromiseUtils.props({
|
||||
folders: Folder.findAll(),
|
||||
labels: Label.findAll(),
|
||||
}).then(({folders, labels}) => {
|
||||
const all = [].concat(folders, labels);
|
||||
for (const category of all) {
|
||||
expect(category.role).toEqual(mailboxes[category.name].role);
|
||||
}
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
describe("FetchFolderList", () => {
|
||||
beforeEach((done) => {
|
||||
mockDatabase().then((db) => {
|
||||
this.db = db;
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it("assigns roles when given a role attribute/flag", (done) => {
|
||||
const mailboxes = {
|
||||
'Sent': {attribs: ['\\Sent'], role: 'sent'},
|
||||
'Drafts': {attribs: ['\\Drafts'], role: 'drafts'},
|
||||
'Spam': {attribs: ['\\Spam'], role: 'spam'},
|
||||
'Trash': {attribs: ['\\Trash'], role: 'trash'},
|
||||
'All Mail': {attribs: ['\\All'], role: 'all'},
|
||||
'Important': {attribs: ['\\Important'], role: 'important'},
|
||||
'Flagged': {attribs: ['\\Flagged'], role: 'flagged'},
|
||||
'Inbox': {attribs: ['\\Inbox'], role: 'inbox'},
|
||||
'TestFolder': {attribs: [], role: null},
|
||||
'Receipts': {attribs: [], role: null},
|
||||
}
|
||||
|
||||
testCategoryRoles(this.db, mailboxes).then(done, done.fail);
|
||||
})
|
||||
|
||||
it("assigns missing roles by localized display names", (done) => {
|
||||
const mailboxes = {
|
||||
'Sent': {attribs: [], role: 'sent'},
|
||||
'Drafts': {attribs: ['\\Drafts'], role: 'drafts'},
|
||||
'Spam': {attribs: ['\\Spam'], role: 'spam'},
|
||||
'Trash': {attribs: ['\\Trash'], role: 'trash'},
|
||||
'All Mail': {attribs: ['\\All'], role: 'all'},
|
||||
'Important': {attribs: ['\\Important'], role: 'important'},
|
||||
'Flagged': {attribs: ['\\Flagged'], role: 'flagged'},
|
||||
'Inbox': {attribs: [], role: 'inbox'},
|
||||
}
|
||||
|
||||
testCategoryRoles(this.db, mailboxes).then(done, done.fail);
|
||||
})
|
||||
|
||||
it("doesn't assign a role more than once", (done) => {
|
||||
const mailboxes = {
|
||||
'Sent': {attribs: [], role: null},
|
||||
'Sent Items': {attribs: [], role: null},
|
||||
'Drafts': {attribs: ['\\Drafts'], role: 'drafts'},
|
||||
'Spam': {attribs: ['\\Spam'], role: 'spam'},
|
||||
'Trash': {attribs: ['\\Trash'], role: 'trash'},
|
||||
'All Mail': {attribs: ['\\All'], role: 'all'},
|
||||
'Important': {attribs: ['\\Important'], role: 'important'},
|
||||
'Flagged': {attribs: ['\\Flagged'], role: 'flagged'},
|
||||
'Mail': {attribs: ['\\Inbox'], role: 'inbox'},
|
||||
'inbox': {attribs: [], role: null},
|
||||
}
|
||||
|
||||
testCategoryRoles(this.db, mailboxes).then(done, done.fail);
|
||||
})
|
||||
|
||||
it("updates role assignments if an assigned category is deleted", (done) => {
|
||||
let mailboxes = {
|
||||
'Sent': {attribs: [], role: null},
|
||||
'Sent Items': {attribs: [], role: null},
|
||||
'Drafts': {attribs: ['\\Drafts'], role: 'drafts'},
|
||||
'Spam': {attribs: ['\\Spam'], role: 'spam'},
|
||||
'Trash': {attribs: ['\\Trash'], role: 'trash'},
|
||||
'All Mail': {attribs: ['\\All'], role: 'all'},
|
||||
'Important': {attribs: ['\\Important'], role: 'important'},
|
||||
'Flagged': {attribs: ['\\Flagged'], role: 'flagged'},
|
||||
'Mail': {attribs: ['\\Inbox'], role: 'inbox'},
|
||||
}
|
||||
|
||||
testCategoryRoles(this.db, mailboxes).then(() => {
|
||||
mailboxes = {
|
||||
'Sent Items': {attribs: [], role: 'sent'},
|
||||
'Drafts': {attribs: ['\\Drafts'], role: 'drafts'},
|
||||
'Spam': {attribs: ['\\Spam'], role: 'spam'},
|
||||
'Trash': {attribs: ['\\Trash'], role: 'trash'},
|
||||
'All Mail': {attribs: ['\\All'], role: 'all'},
|
||||
'Important': {attribs: ['\\Important'], role: 'important'},
|
||||
'Flagged': {attribs: ['\\Flagged'], role: 'flagged'},
|
||||
'Mail': {attribs: ['\\Inbox'], role: 'inbox'},
|
||||
}
|
||||
|
||||
return testCategoryRoles(this.db, mailboxes).then(done, done.fail);
|
||||
}, done.fail);
|
||||
})
|
||||
});
|
|
@ -1,55 +0,0 @@
|
|||
const LocalDatabaseConnector = require('../../src/shared/local-database-connector');
|
||||
|
||||
/*
|
||||
* Mocks out various Model and Instance methods to prevent actually saving data
|
||||
* to the sequelize database. Note that with the current implementation, only
|
||||
* instances created with Model.build() are mocked out.
|
||||
*
|
||||
* Currently mocks out the following:
|
||||
* Model
|
||||
* .build()
|
||||
* .findAll()
|
||||
* Instance
|
||||
* .destroy()
|
||||
* .save()
|
||||
*
|
||||
*/
|
||||
function mockDatabase() {
|
||||
return LocalDatabaseConnector.forAccount(-1).then((db) => {
|
||||
const data = {};
|
||||
for (const modelName of Object.keys(db.sequelize.models)) {
|
||||
const model = db.sequelize.models[modelName];
|
||||
data[modelName] = {};
|
||||
|
||||
spyOn(model, 'findAll').and.callFake(() => {
|
||||
return Promise.resolve(
|
||||
Object.keys(data[modelName]).map(key => data[modelName][key])
|
||||
);
|
||||
});
|
||||
|
||||
const origBuild = model.build;
|
||||
spyOn(model, 'build').and.callFake((...args) => {
|
||||
const instance = origBuild.apply(model, args);
|
||||
|
||||
spyOn(instance, 'save').and.callFake(() => {
|
||||
if (instance.id == null) {
|
||||
const sortedIds = Object.keys(data[modelName]).sort();
|
||||
const len = sortedIds.length;
|
||||
instance.id = len ? +sortedIds[len - 1] + 1 : 0;
|
||||
}
|
||||
data[modelName][instance.id] = instance;
|
||||
});
|
||||
|
||||
spyOn(instance, 'destroy').and.callFake(() => {
|
||||
delete data[modelName][instance.id]
|
||||
});
|
||||
|
||||
return instance;
|
||||
})
|
||||
}
|
||||
|
||||
return Promise.resolve(db);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = mockDatabase;
|
41
packages/local-sync/spec/message-factory-spec.js
Normal file
41
packages/local-sync/spec/message-factory-spec.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const LocalDatabaseConnector = require('../src/shared/local-database-connector');
|
||||
const {parseFromImap} = require('../src/shared/message-factory');
|
||||
|
||||
const FIXTURES_PATH = path.join(__dirname, 'fixtures')
|
||||
|
||||
describe('MessageFactory', function MessageFactorySpecs() {
|
||||
beforeEach(() => {
|
||||
waitsForPromise(async () => {
|
||||
const accountId = 'test-account-id';
|
||||
await LocalDatabaseConnector.ensureAccountDatabase(accountId);
|
||||
const db = await LocalDatabaseConnector.forAccount(accountId);
|
||||
const folder = await db.Folder.create({
|
||||
id: 'test-folder-id',
|
||||
accountId: accountId,
|
||||
version: 1,
|
||||
name: 'Test Folder',
|
||||
role: null,
|
||||
});
|
||||
this.options = { accountId, db, folder };
|
||||
})
|
||||
})
|
||||
|
||||
describe("parseFromImap", () => {
|
||||
const fixturesDir = path.join(FIXTURES_PATH, 'MessageFactory', 'parseFromImap');
|
||||
const filenames = fs.readdirSync(fixturesDir).filter(f => f.endsWith('.json'));
|
||||
|
||||
filenames.forEach((filename) => {
|
||||
it(`should correctly build message properties for ${filename}`, () => {
|
||||
const inJSON = JSON.parse(fs.readFileSync(path.join(fixturesDir, filename)));
|
||||
const {imapMessage, desiredParts, result} = inJSON;
|
||||
|
||||
waitsForPromise(async () => {
|
||||
const actual = await parseFromImap(imapMessage, desiredParts, this.options);
|
||||
expect(actual).toEqual(result)
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
55
packages/local-sync/spec/threading-spec.js
Normal file
55
packages/local-sync/spec/threading-spec.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
/* eslint global-require: 0 */
|
||||
/* eslint import/no-dynamic-require: 0 */
|
||||
// const path = require('path')
|
||||
// const BASE_PATH = path.join(__dirname, 'fixtures')
|
||||
|
||||
xdescribe('threading', function threadingSpecs() {
|
||||
// it('adds the message to the thread', (done) => {
|
||||
// const {message, reply} = require(`${BASE_PATH}/thread`)
|
||||
// const accountId = 'a-1'
|
||||
// const mockDb = {
|
||||
// Thread: {
|
||||
// findAll: () => {
|
||||
// return Promise.resolve([{
|
||||
// id: 1,
|
||||
// subject: "Loved your work and interests",
|
||||
// messages: [message],
|
||||
// }])
|
||||
// },
|
||||
// find: () => {
|
||||
// return Promise.resolve(null)
|
||||
// },
|
||||
// create: (thread) => {
|
||||
// thread.id = 1
|
||||
// thread.addMessage = (newMessage) => {
|
||||
// if (thread.messages) {
|
||||
// thread.messages.push(newMessage.id)
|
||||
// } else {
|
||||
// thread.messages = [newMessage.id]
|
||||
// }
|
||||
// }
|
||||
// return Promise.resolve(thread)
|
||||
// },
|
||||
// },
|
||||
// Message: {
|
||||
// findAll: () => {
|
||||
// return Promise.resolve([message, reply])
|
||||
// },
|
||||
// find: () => {
|
||||
// return Promise.resolve(reply)
|
||||
// },
|
||||
// create: () => {
|
||||
// message.setThread = (thread) => {
|
||||
// message.thread = thread.id
|
||||
// };
|
||||
// return Promise.resolve(message);
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// processMessage({db: mockDb, message: reply, accountId}).then((processed) => {
|
||||
// expect(processed.thread).toBe(1)
|
||||
// done()
|
||||
// })
|
||||
// });
|
||||
});
|
|
@ -239,8 +239,8 @@ class FetchMessagesInFolder {
|
|||
try {
|
||||
const messageValues = await MessageFactory.parseFromImap(imapMessage, desiredParts, {
|
||||
db: this._db,
|
||||
folder: this._folder,
|
||||
accountId: this._db.accountId,
|
||||
folderId: this._folder.id,
|
||||
});
|
||||
const existingMessage = await Message.find({where: {id: messageValues.id}});
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
const {processMessage} = require('../processors/parsing')
|
||||
|
||||
const BASE_PATH = path.join(__dirname, 'fixtures')
|
||||
|
||||
|
||||
it('parses the message correctly', (done) => {
|
||||
const bodyPath = path.join(BASE_PATH, '1-99174-body.txt')
|
||||
const headersPath = path.join(BASE_PATH, '1-99174-headers.txt')
|
||||
const rawBody = fs.readFileSync(bodyPath, 'utf8')
|
||||
const rawHeaders = fs.readFileSync(headersPath, 'utf8')
|
||||
const message = { rawHeaders, rawBody }
|
||||
const bodyPart = `<p>In <a href="https://github.com/electron/electron.atom.io/pull/352#discussion_r67715160">_data/apps.yml</a>:</p>`
|
||||
|
||||
processMessage({message}).then((processed) => {
|
||||
expect(processed.headers['in-reply-to']).toEqual('<electron/electron.atom.io/pull/352@github.com>')
|
||||
expect(processed.headerMessageId).toEqual('<electron/electron.atom.io/pull/352/r67715160@github.com>')
|
||||
expect(processed.subject).toEqual('Re: [electron/electron.atom.io] Add Jasper app (#352)')
|
||||
expect(processed.body.includes(bodyPart)).toBe(true)
|
||||
done()
|
||||
})
|
||||
})
|
|
@ -1,5 +0,0 @@
|
|||
import Jasmine from 'jasmine'
|
||||
|
||||
const jasmine = new Jasmine()
|
||||
jasmine.loadConfigFile('spec/support/jasmine.json')
|
||||
jasmine.execute()
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"spec_dir": "spec",
|
||||
"spec_files": [
|
||||
"**/*-spec.js"
|
||||
],
|
||||
"helpers": [ ]
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/* eslint global-require: 0 */
|
||||
/* eslint import/no-dynamic-require: 0 */
|
||||
const path = require('path')
|
||||
const {processMessage} = require('../processors/threading')
|
||||
|
||||
const BASE_PATH = path.join(__dirname, 'fixtures')
|
||||
|
||||
it('adds the message to the thread', (done) => {
|
||||
const {message, reply} = require(`${BASE_PATH}/thread`)
|
||||
const accountId = 'a-1'
|
||||
const mockDb = {
|
||||
Thread: {
|
||||
findAll: () => {
|
||||
return Promise.resolve([{
|
||||
id: 1,
|
||||
subject: "Loved your work and interests",
|
||||
messages: [message],
|
||||
}])
|
||||
},
|
||||
find: () => {
|
||||
return Promise.resolve(null)
|
||||
},
|
||||
create: (thread) => {
|
||||
thread.id = 1
|
||||
thread.addMessage = (newMessage) => {
|
||||
if (thread.messages) {
|
||||
thread.messages.push(newMessage.id)
|
||||
} else {
|
||||
thread.messages = [newMessage.id]
|
||||
}
|
||||
}
|
||||
return Promise.resolve(thread)
|
||||
},
|
||||
},
|
||||
Message: {
|
||||
findAll: () => {
|
||||
return Promise.resolve([message, reply])
|
||||
},
|
||||
find: () => {
|
||||
return Promise.resolve(reply)
|
||||
},
|
||||
create: () => {
|
||||
message.setThread = (thread) => {
|
||||
message.thread = thread.id
|
||||
};
|
||||
return Promise.resolve(message);
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
processMessage({db: mockDb, message: reply, accountId}).then((processed) => {
|
||||
expect(processed.thread).toBe(1)
|
||||
done()
|
||||
})
|
||||
})
|
|
@ -12,8 +12,9 @@ class LocalDatabaseConnector {
|
|||
}
|
||||
|
||||
_sequelizePoolForDatabase(dbname) {
|
||||
const storage = NylasEnv.inSpecMode() ? ':memory:' : path.join(process.env.NYLAS_HOME, `${dbname}.sqlite`);
|
||||
return new Sequelize(dbname, '', '', {
|
||||
storage: path.join(process.env.NYLAS_HOME, `${dbname}.sqlite`),
|
||||
storage: storage,
|
||||
dialect: "sqlite",
|
||||
logging: false,
|
||||
})
|
||||
|
|
|
@ -12,8 +12,8 @@ function extractContacts(values = []) {
|
|||
})
|
||||
}
|
||||
|
||||
function parseFromImap(imapMessage, desiredParts, {db, accountId, folderId}) {
|
||||
const {Message, Label, Folder} = db
|
||||
async function parseFromImap(imapMessage, desiredParts, {db, accountId, folder}) {
|
||||
const {Message, Label} = db
|
||||
const body = {}
|
||||
const {headers, attributes} = imapMessage
|
||||
const xGmLabels = attributes['x-gm-labels']
|
||||
|
@ -51,7 +51,7 @@ function parseFromImap(imapMessage, desiredParts, {db, accountId, folderId}) {
|
|||
starred: attributes.flags.includes('\\Flagged'),
|
||||
date: attributes.date,
|
||||
folderImapUID: attributes.uid,
|
||||
folderId: folderId,
|
||||
folderId: folder.id,
|
||||
folder: null,
|
||||
labels: [],
|
||||
headers: parsedHeaders,
|
||||
|
@ -72,40 +72,15 @@ function parseFromImap(imapMessage, desiredParts, {db, accountId, folderId}) {
|
|||
values.snippet = values.body.substr(0, Math.min(values.body.length, SNIPPET_SIZE));
|
||||
}
|
||||
|
||||
return Folder.findById(folderId)
|
||||
.then((folder) => {
|
||||
values.folder = folder
|
||||
values.folder = folder
|
||||
if (xGmLabels) {
|
||||
values.folderImapXGMLabels = JSON.stringify(xGmLabels)
|
||||
values.labels = await Label.findXGMLabels(xGmLabels)
|
||||
}
|
||||
|
||||
if (xGmLabels) {
|
||||
values.folderImapXGMLabels = JSON.stringify(xGmLabels)
|
||||
return Label.findXGMLabels(xGmLabels)
|
||||
.then((labels) => {
|
||||
values.labels = labels
|
||||
return values
|
||||
})
|
||||
}
|
||||
return Promise.resolve(values)
|
||||
})
|
||||
}
|
||||
|
||||
function buildFromImap(imapMessage, desiredParts, {db, accountId, folderId}) {
|
||||
return parseFromImap(imapMessage, desiredParts, {db, accountId, folderId})
|
||||
.then((messageValues) => db.Message.build(messageValues))
|
||||
}
|
||||
|
||||
function createFromImap(imapMessage, desiredParts, {db, accountId, folderId}) {
|
||||
return parseFromImap(imapMessage, desiredParts, {db, accountId, folderId})
|
||||
.then((messageValues) => db.Message.create(messageValues))
|
||||
}
|
||||
|
||||
function upsertFromImap(imapMessage, desiredParts, {db, accountId, folderId}) {
|
||||
return parseFromImap(imapMessage, desiredParts, {db, accountId, folderId})
|
||||
.then((messageValues) => db.Message.upsert(messageValues))
|
||||
return values;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
parseFromImap,
|
||||
buildFromImap,
|
||||
createFromImap,
|
||||
upsertFromImap,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue