diff --git a/app/common/__tests__/cookies.test.js b/app/common/__tests__/cookies.test.js index e4a859667a..e1ca984dc6 100644 --- a/app/common/__tests__/cookies.test.js +++ b/app/common/__tests__/cookies.test.js @@ -18,6 +18,11 @@ describe('jarFromCookies()', () => { done(); }); }); + + it('handles malformed JSON', () => { + const jar = cookieUtils.jarFromCookies("not a jar"); + expect(jar.constructor.name).toBe('CookieJar'); + }) }); describe('cookiesFromJar()', () => { @@ -28,9 +33,12 @@ describe('cookiesFromJar()', () => { value: 'baz', domain: 'insomnia.rest', expires: d + }, { + // This one will fail to parse, and be skipped + bad: 'cookie' }]; - const jar= CookieJar.fromJSON({cookies: initialCookies}); + const jar = CookieJar.fromJSON({cookies: initialCookies}); const cookies = await cookieUtils.cookiesFromJar(jar); @@ -40,4 +48,93 @@ describe('cookiesFromJar()', () => { expect(cookies[0].creation instanceof Date).toEqual(true); expect(cookies[0].expires).toEqual(d); }); + + it('handles bad jar', async () => { + const jar = CookieJar.fromJSON({cookies: []}); + + // MemoryStore never actually throws errors, so lets mock the + // function to force it to this time. + jar.store.getAllCookies = cb => cb(new Error('Dummy Error')); + const cookies = await cookieUtils.cookiesFromJar(jar); + + // Cookies failed to p + expect(cookies.length).toBe(0); + }) +}); + +describe('cookieHeaderValueForUri()', () => { + it('gets cookies for valid case', async () => { + const jar = cookieUtils.jarFromCookies([{ + key: 'foo', + value: 'bar', + path: '/', + domain: 'google.com' + }, { + key: 'foo', + value: 'inner', + path: '/inner', + domain: 'google.com' + }]); + + expect(await cookieUtils.cookieHeaderValueForUri(jar, 'https://google.com/foo/bar')) + .toBe('foo=bar'); + + expect(await cookieUtils.cookieHeaderValueForUri(jar, 'https://insomnia.rest/')) + .toBe(''); + + expect(await cookieUtils.cookieHeaderValueForUri(jar, 'https://google.com/inner')) + .toBe('foo=inner; foo=bar'); + }); + + it('handles errors properly', async () => { + const jar = cookieUtils.jarFromCookies([]); + jar.getCookies = (uri, cb) => cb(new Error('Dummy error')); + + expect( + await cookieUtils.cookieHeaderValueForUri(jar, 'https://google.com') + ).toBe(''); + }); + + describe('cookieToString()', () => { + it('does it\'s thing', async () => { + const jar = cookieUtils.jarFromCookies([{ + key: 'foo', + value: 'bar', + path: '/', + domain: 'google.com' + }, { + key: 'foo1', + value: 'bar', + path: '/', + domain: 'google.com', + hostOnly: true + }, { + key: 'foo2', + value: 'bar', + path: '/', + domain: 'google.com', + hostOnly: false + }, { + key: 'foo3', + value: 'bar', + path: '/somepath' + }]); + + const cookies = await cookieUtils.cookiesFromJar(jar); + + expect(cookies.length).toBe(4); + + expect(cookieUtils.cookieToString(cookies[0])) + .toBe('foo=bar; Domain=google.com; Path=/'); + + expect(cookieUtils.cookieToString(cookies[1])) + .toBe('foo1=bar; Path=/; Domain=google.com'); + + expect(cookieUtils.cookieToString(cookies[2])) + .toBe('foo2=bar; Domain=google.com; Path=/'); + + expect(cookieUtils.cookieToString(cookies[3])) + .toBe('foo3=bar; Path=/somepath'); + }) + }) }); diff --git a/app/common/__tests__/database.test.js b/app/common/__tests__/database.test.js index 4aa6fd20b5..c9bcd9b98d 100644 --- a/app/common/__tests__/database.test.js +++ b/app/common/__tests__/database.test.js @@ -12,6 +12,77 @@ function loadFixture (name) { } } +describe('initDB()', () => { + it('handles being initialized twice', async () => { + await db.initDB(models.types(), {inMemoryOnly: true}); + await db.initDB(models.types(), {inMemoryOnly: true}); + expect((await db.all(models.request.type)).length).toBe(0); + }); +}); + +describe('onChange()', () => { + it('handles change listeners', async () => { + const doc = { + type: models.request.type, + name: 'foo' + }; + + const changesSeen = []; + const callback = change => { + changesSeen.push(change); + }; + db.onChange(callback); + + await db.insert(doc); + await db.insert(doc, true); + expect(changesSeen.length).toBe(2); + expect(changesSeen).toEqual([ + [[db.CHANGE_INSERT, doc, false]], + [[db.CHANGE_INSERT, doc, true]] + ]); + + db.offChange(callback); + await db.insert(doc); + expect(changesSeen.length).toBe(2); + }); +}); + +describe('bufferChanges()', () => { + it('properly buffers changes', async () => { + const doc = { + type: models.request.type, + name: 'foo' + }; + + const changesSeen = []; + const callback = change => { + changesSeen.push(change); + }; + db.onChange(callback); + + db.bufferChanges(); + await db.insert(doc); + await db.insert(doc, true); + + // Assert no change seen before flush + expect(changesSeen.length).toBe(0); + + // Assert changes seen after flush + db.flushChanges(); + expect(changesSeen).toEqual([[ + [db.CHANGE_INSERT, doc, false], + [db.CHANGE_INSERT, doc, true] + ]]); + + // Assert no more changes seen after flush again + db.flushChanges(); + expect(changesSeen).toEqual([[ + [db.CHANGE_INSERT, doc, false], + [db.CHANGE_INSERT, doc, true] + ]]); + }); +}); + describe('requestCreate()', () => { beforeEach(() => { return db.initDB(models.types(), {inMemoryOnly: true}, true); diff --git a/app/common/__tests__/localstorage.test.js b/app/common/__tests__/localstorage.test.js index 799e06f11d..5c90f59fce 100644 --- a/app/common/__tests__/localstorage.test.js +++ b/app/common/__tests__/localstorage.test.js @@ -10,6 +10,10 @@ describe('LocalStorage()', () => { setTimeout.mock.calls = []; }); + afterEach(() => { + jest.clearAllTimers(); + }) + it('create directory', () => { const basePath = `/tmp/insomnia-localstorage-${Math.random()}`; new LocalStorage(basePath); @@ -35,6 +39,32 @@ describe('LocalStorage()', () => { expect(localStorage.getItem('dne')).toEqual('default'); }); + it('does handles malformed files', () => { + const basePath = `/tmp/insomnia-localstorage-${Math.random()}`; + const localStorage = new LocalStorage(basePath); + + // Assert default is returned on bad JSON + fs.writeFileSync(path.join(basePath, 'key'), '{bad JSON'); + expect(localStorage.getItem('key', 'default')).toBe('default'); + + // Assert that writing our file actually works + fs.writeFileSync(path.join(basePath, 'key'), '{"good": "JSON"}'); + expect(localStorage.getItem('key', 'default')).toEqual({good: 'JSON'}); + }); + + it('does handles failing to write file', () => { + const basePath = `/tmp/insomnia-localstorage-${Math.random()}`; + const localStorage = new LocalStorage(basePath); + fs.rmdirSync(basePath); + localStorage.setItem('key', 'value'); + + jest.runAllTimers(); + + // Since the above operation failed to write, we should now get back + // the default value + expect(localStorage.getItem('key', 'different')).toBe('different'); + }); + it('stores a key', () => { const basePath = `/tmp/insomnia-localstorage-${Math.random()}`; const localStorage = new LocalStorage(basePath); diff --git a/app/common/__tests__/misc.test.js b/app/common/__tests__/misc.test.js index fd2594f8ec..da63798769 100644 --- a/app/common/__tests__/misc.test.js +++ b/app/common/__tests__/misc.test.js @@ -129,3 +129,16 @@ describe('prepareUrlForSending()', () => { expect(url).toBe('https://google.com/?s=foo&s=foo%20%20100%25'); }); }); + +describe('filterHeaders()', () => { + it('handles bad headers', () => { + expect(util.filterHeaders(null, null)).toEqual([]); + expect(util.filterHeaders([], null)).toEqual([]); + expect(util.filterHeaders(['bad'], null)).toEqual([]); + expect(util.filterHeaders(['bad'], 'good')).toEqual([]); + expect(util.filterHeaders(null, 'good')).toEqual([]); + expect(util.filterHeaders([{name: 'good', value: 'valid'}], null)).toEqual([]); + expect(util.filterHeaders([{name: 'good', value: 'valid'}], 'good')) + .toEqual([{name: 'good', value: 'valid'}]); + }) +}); diff --git a/app/common/cookies.js b/app/common/cookies.js index 20cb9ef6f7..c0967e967a 100644 --- a/app/common/cookies.js +++ b/app/common/cookies.js @@ -25,13 +25,10 @@ export function cookiesFromJar (jar) { * @returns {Promise} */ export function cookieHeaderValueForUri (jar, uri) { - return new Promise((resolve, reject) => { + return new Promise(resolve => { jar.getCookies(uri, (err, cookies) => { - if (err) { - reject(err) - } else { - resolve(cookies.map(c => c.cookieString()).join('; ')); - } + cookies = err ? [] : cookies; + resolve(cookies.map(c => c.cookieString()).join('; ')); }) }) } diff --git a/app/common/database.js b/app/common/database.js index e260e01979..accf854890 100644 --- a/app/common/database.js +++ b/app/common/database.js @@ -93,10 +93,7 @@ export function flushChanges () { return; } - // Notify async so we don't block - process.nextTick(() => { - changeListeners.map(fn => fn(changes)); - }) + changeListeners.map(fn => fn(changes)); } function notifyOfChange (event, doc, fromSync) { diff --git a/app/common/localstorage.js b/app/common/localstorage.js index ac549aa498..296a3ae91f 100644 --- a/app/common/localstorage.js +++ b/app/common/localstorage.js @@ -38,7 +38,8 @@ class LocalStorage { try { return JSON.parse(contents) } catch (e) { - console.error(`[localstorage] Failed to get from LocalStorage: ${e}`) + console.error(`[localstorage] Failed to parse item from LocalStorage: ${e}`) + return defaultObj; } } diff --git a/app/common/misc.js b/app/common/misc.js index 899a8086f6..ecdabbd3c1 100644 --- a/app/common/misc.js +++ b/app/common/misc.js @@ -16,7 +16,7 @@ export function filterHeaders (headers, name) { } return headers.filter( - h => h.name.toLowerCase() === name.toLowerCase() + h => (h.name || '').toLowerCase() === name.toLowerCase() ); } diff --git a/app/common/render.js b/app/common/render.js index c5ed734cd9..4a2ac742c6 100644 --- a/app/common/render.js +++ b/app/common/render.js @@ -17,14 +17,14 @@ class NoArgsExtension { } } -class ArgsExtension { - parse (parser, nodes, lexer) { - const tok = parser.nextToken(); - const args = parser.parseSignature(null, true); - parser.advanceAfterBlockEnd(tok.value); - return new nodes.CallExtension(this, 'run', args); - } -} +// class ArgsExtension { +// parse (parser, nodes, lexer) { +// const tok = parser.nextToken(); +// const args = parser.parseSignature(null, true); +// parser.advanceAfterBlockEnd(tok.value); +// return new nodes.CallExtension(this, 'run', args); +// } +// } class TimestampExtension extends NoArgsExtension { constructor () { diff --git a/package.json b/package.json index 1789cd18be..b5566bbfdd 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ }, "scripts": { "test:noisy": "jest", - "test:watch": "jest --watch", + "test:coverage": "jest --coverage --silent && open ./coverage/lcov-report/index.html", "test": "jest --silent", "start-hot": "cross-env HOT=1 INSOMNIA_ENV=development electron -r babel-register ./app/main.development.js", "hot-server": "babel-node ./webpack/server.js", @@ -36,7 +36,17 @@ "jest": { "rootDir": "app", "verbose": false, - "bail": true + "collectCoverage": false, + "collectCoverageFrom": [ + "**/*.js", + "!**/main.development.js", + "!**/static/**", + "!**/ui/**", + "!**/__fixtures__/**", + "!**/__tests__/**", + "!**/__mocks__/**", + "!**/node_modules/**" + ] }, "build": { "appId": "com.insomnia.app",