[local-sync] fix(specs): run npm test in local-sync dir

This commit is contained in:
Ben Gotow 2016-12-05 12:16:53 -08:00
parent 017e22c88d
commit 30c8bedd7a
17 changed files with 117 additions and 296 deletions

1
.gitignore vendored
View file

@ -19,3 +19,4 @@ newrelic_agent.log
.elasticbeanstalk/*
!.elasticbeanstalk/*.cfg.yml
!.elasticbeanstalk/*.global.yml
/packages/local-sync/spec-saved-state.json

View file

@ -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"

View file

@ -0,0 +1,5 @@
{
"imapMessage": {},
"desiredParts": {},
"result": {}
}

View file

@ -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);
})
});

View file

@ -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;

View 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)
});
});
})
});
});

View 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()
// })
// });
});

View file

@ -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}});

View file

@ -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()
})
})

View file

@ -1,5 +0,0 @@
import Jasmine from 'jasmine'
const jasmine = new Jasmine()
jasmine.loadConfigFile('spec/support/jasmine.json')
jasmine.execute()

View file

@ -1,7 +0,0 @@
{
"spec_dir": "spec",
"spec_files": [
"**/*-spec.js"
],
"helpers": [ ]
}

View file

@ -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()
})
})

View file

@ -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,
})

View file

@ -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
if (xGmLabels) {
values.folderImapXGMLabels = JSON.stringify(xGmLabels)
return Label.findXGMLabels(xGmLabels)
.then((labels) => {
values.labels = labels
return values
})
values.labels = await Label.findXGMLabels(xGmLabels)
}
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,
}