diff --git a/.eslintignore b/.eslintignore index ff968ce0e..754d1a046 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,12 +3,6 @@ components/** coverage/** dist/** -# these aren't ready yet, pulling files in one-by-one -libtextsecure/test/*.js -test/*.js -test/models/*.js -test/views/*.js - # Generated files js/components.js js/libtextsecure.js diff --git a/libtextsecure/test/.eslintrc b/libtextsecure/test/.eslintrc new file mode 100644 index 000000000..d27f42a0b --- /dev/null +++ b/libtextsecure/test/.eslintrc @@ -0,0 +1,25 @@ +{ + "env": { + "browser": true, + "node": false, + "mocha": true, + }, + "parserOptions": { + "sourceType": "script" + }, + "rules": { + "strict": "off", + "more/no-then": "off", + }, + "globals": { + "assert": true, + "assertEqualArrayBuffers": true, + "dcodeIO": true, + "getString": true, + "hexToArrayBuffer": true, + "MockServer": true, + "MockSocket": true, + "PROTO_ROOT": true, + "stringToArrayBuffer": true, + } +} diff --git a/libtextsecure/test/_test.js b/libtextsecure/test/_test.js index 95125e419..7e02fef19 100644 --- a/libtextsecure/test/_test.js +++ b/libtextsecure/test/_test.js @@ -1,57 +1,59 @@ +/* global mocha, chai, assert */ + mocha.setup('bdd'); window.assert = chai.assert; window.PROTO_ROOT = '../../protos'; -(function() { - const OriginalReporter = mocha._reporter; +const OriginalReporter = mocha._reporter; - const SauceReporter = function(runner) { - const failedTests = []; +const SauceReporter = runner => { + const failedTests = []; - runner.on('end', () => { - window.mochaResults = runner.stats; - window.mochaResults.reports = failedTests; + runner.on('end', () => { + window.mochaResults = runner.stats; + window.mochaResults.reports = failedTests; + }); + + runner.on('fail', (test, err) => { + const flattenTitles = item => { + const titles = []; + while (item.parent.title) { + titles.push(item.parent.title); + // eslint-disable-next-line no-param-reassign + item = item.parent; + } + return titles.reverse(); + }; + failedTests.push({ + name: test.title, + result: false, + message: err.message, + stack: err.stack, + titles: flattenTitles(test), }); + }); - runner.on('fail', (test, err) => { - const flattenTitles = function(test) { - const titles = []; - while (test.parent.title) { - titles.push(test.parent.title); - test = test.parent; - } - return titles.reverse(); - }; - failedTests.push({ - name: test.title, - result: false, - message: err.message, - stack: err.stack, - titles: flattenTitles(test), - }); - }); + // eslint-disable-next-line no-new + new OriginalReporter(runner); +}; - new OriginalReporter(runner); - }; +SauceReporter.prototype = OriginalReporter.prototype; - SauceReporter.prototype = OriginalReporter.prototype; - - mocha.reporter(SauceReporter); -})(); +mocha.reporter(SauceReporter); /* * global helpers for tests */ -function assertEqualArrayBuffers(ab1, ab2) { +window.assertEqualArrayBuffers = (ab1, ab2) => { assert.deepEqual(new Uint8Array(ab1), new Uint8Array(ab2)); -} +}; -function hexToArrayBuffer(str) { +window.hexToArrayBuffer = str => { const ret = new ArrayBuffer(str.length / 2); const array = new Uint8Array(ret); - for (let i = 0; i < str.length / 2; i++) + for (let i = 0; i < str.length / 2; i += 1) array[i] = parseInt(str.substr(i * 2, 2), 16); return ret; -} +}; -window.MockSocket.prototype.addEventListener = function() {}; +window.MockSocket.prototype.addEventListener = () => null; diff --git a/libtextsecure/test/account_manager_test.js b/libtextsecure/test/account_manager_test.js index 6269fbc0a..12ffda788 100644 --- a/libtextsecure/test/account_manager_test.js +++ b/libtextsecure/test/account_manager_test.js @@ -46,7 +46,7 @@ describe('AccountManager', () => { return accountManager.cleanSignedPreKeys(); }); - it('eliminates confirmed keys over a week old, if more than three', () => { + it('eliminates confirmed keys over a week old, if more than three', async () => { const now = Date.now(); signedPreKeys = [ { @@ -77,20 +77,19 @@ describe('AccountManager', () => { ]; let count = 0; - window.textsecure.storage.protocol.removeSignedPreKey = function(keyId) { + window.textsecure.storage.protocol.removeSignedPreKey = keyId => { if (keyId !== 1 && keyId !== 4) { throw new Error(`Wrong keys were eliminated! ${keyId}`); } - count++; + count += 1; }; - return accountManager.cleanSignedPreKeys().then(() => { - assert.strictEqual(count, 2); - }); + await accountManager.cleanSignedPreKeys(); + assert.strictEqual(count, 2); }); - it('keeps at least three unconfirmed keys if no confirmed', () => { + it('keeps at least three unconfirmed keys if no confirmed', async () => { const now = Date.now(); signedPreKeys = [ { @@ -112,20 +111,19 @@ describe('AccountManager', () => { ]; let count = 0; - window.textsecure.storage.protocol.removeSignedPreKey = function(keyId) { + window.textsecure.storage.protocol.removeSignedPreKey = keyId => { if (keyId !== 2) { throw new Error(`Wrong keys were eliminated! ${keyId}`); } - count++; + count += 1; }; - return accountManager.cleanSignedPreKeys().then(() => { - assert.strictEqual(count, 1); - }); + await accountManager.cleanSignedPreKeys(); + assert.strictEqual(count, 1); }); - it('if some confirmed keys, keeps unconfirmed to addd up to three total', () => { + it('if some confirmed keys, keeps unconfirmed to addd up to three total', async () => { const now = Date.now(); signedPreKeys = [ { @@ -149,17 +147,16 @@ describe('AccountManager', () => { ]; let count = 0; - window.textsecure.storage.protocol.removeSignedPreKey = function(keyId) { + window.textsecure.storage.protocol.removeSignedPreKey = keyId => { if (keyId !== 3) { throw new Error(`Wrong keys were eliminated! ${keyId}`); } - count++; + count += 1; }; - return accountManager.cleanSignedPreKeys().then(() => { - assert.strictEqual(count, 1); - }); + await accountManager.cleanSignedPreKeys(); + assert.strictEqual(count, 1); }); }); }); diff --git a/libtextsecure/test/contacts_parser_test.js b/libtextsecure/test/contacts_parser_test.js index 9c1beef0e..be09e2bfd 100644 --- a/libtextsecure/test/contacts_parser_test.js +++ b/libtextsecure/test/contacts_parser_test.js @@ -1,9 +1,11 @@ +/* global ContactBuffer, GroupBuffer, textsecure */ + describe('ContactBuffer', () => { function getTestBuffer() { const buffer = new dcodeIO.ByteBuffer(); const avatarBuffer = new dcodeIO.ByteBuffer(); const avatarLen = 255; - for (var i = 0; i < avatarLen; ++i) { + for (let i = 0; i < avatarLen; i += 1) { avatarBuffer.writeUint8(i); } avatarBuffer.limit = avatarBuffer.offset; @@ -15,7 +17,7 @@ describe('ContactBuffer', () => { }); const contactInfoBuffer = contactInfo.encode().toArrayBuffer(); - for (var i = 0; i < 3; ++i) { + for (let i = 0; i < 3; i += 1) { buffer.writeVarint32(contactInfoBuffer.byteLength); buffer.append(contactInfoBuffer); buffer.append(avatarBuffer.clone()); @@ -32,14 +34,14 @@ describe('ContactBuffer', () => { let contact = contactBuffer.next(); let count = 0; while (contact !== undefined) { - count++; + count += 1; assert.strictEqual(contact.name, 'Zero Cool'); assert.strictEqual(contact.number, '+10000000000'); assert.strictEqual(contact.avatar.contentType, 'image/jpeg'); assert.strictEqual(contact.avatar.length, 255); assert.strictEqual(contact.avatar.data.byteLength, 255); const avatarBytes = new Uint8Array(contact.avatar.data); - for (let j = 0; j < 255; ++j) { + for (let j = 0; j < 255; j += 1) { assert.strictEqual(avatarBytes[j], j); } contact = contactBuffer.next(); @@ -53,7 +55,7 @@ describe('GroupBuffer', () => { const buffer = new dcodeIO.ByteBuffer(); const avatarBuffer = new dcodeIO.ByteBuffer(); const avatarLen = 255; - for (var i = 0; i < avatarLen; ++i) { + for (let i = 0; i < avatarLen; i += 1) { avatarBuffer.writeUint8(i); } avatarBuffer.limit = avatarBuffer.offset; @@ -66,7 +68,7 @@ describe('GroupBuffer', () => { }); const groupInfoBuffer = groupInfo.encode().toArrayBuffer(); - for (var i = 0; i < 3; ++i) { + for (let i = 0; i < 3; i += 1) { buffer.writeVarint32(groupInfoBuffer.byteLength); buffer.append(groupInfoBuffer); buffer.append(avatarBuffer.clone()); @@ -83,7 +85,7 @@ describe('GroupBuffer', () => { let group = groupBuffer.next(); let count = 0; while (group !== undefined) { - count++; + count += 1; assert.strictEqual(group.name, 'Hackers'); assertEqualArrayBuffers( group.id.toArrayBuffer(), @@ -94,7 +96,7 @@ describe('GroupBuffer', () => { assert.strictEqual(group.avatar.length, 255); assert.strictEqual(group.avatar.data.byteLength, 255); const avatarBytes = new Uint8Array(group.avatar.data); - for (let j = 0; j < 255; ++j) { + for (let j = 0; j < 255; j += 1) { assert.strictEqual(avatarBytes[j], j); } group = groupBuffer.next(); diff --git a/libtextsecure/test/crypto_test.js b/libtextsecure/test/crypto_test.js index 1dace2552..298a273b8 100644 --- a/libtextsecure/test/crypto_test.js +++ b/libtextsecure/test/crypto_test.js @@ -1,3 +1,5 @@ +/* global libsignal, textsecure */ + describe('encrypting and decrypting profile data', () => { const NAME_PADDED_LENGTH = 26; describe('encrypting and decrypting profile names', () => { @@ -61,12 +63,12 @@ describe('encrypting and decrypting profile data', () => { 'This is an avatar' ).toArrayBuffer(); const key = libsignal.crypto.getRandomBytes(32); - const bad_key = libsignal.crypto.getRandomBytes(32); + const badKey = libsignal.crypto.getRandomBytes(32); return textsecure.crypto.encryptProfile(buffer, key).then(encrypted => { assert(encrypted.byteLength === buffer.byteLength + 16 + 12); return textsecure.crypto - .decryptProfile(encrypted, bad_key) + .decryptProfile(encrypted, badKey) .catch(error => { assert.strictEqual(error.name, 'ProfileDecryptError'); }); diff --git a/libtextsecure/test/fake_web_api.js b/libtextsecure/test/fake_web_api.js index af5305b09..74959fe30 100644 --- a/libtextsecure/test/fake_web_api.js +++ b/libtextsecure/test/fake_web_api.js @@ -22,7 +22,7 @@ const fakeAPI = { // sendMessages: fakeCall, setSignedPreKey: fakeCall, - getKeysForNumber(number, deviceId) { + getKeysForNumber(number) { const res = getKeysForNumberMap[number]; if (res !== undefined) { delete getKeysForNumberMap[number]; @@ -32,14 +32,14 @@ const fakeAPI = { }, sendMessages(destination, messageArray) { - for (i in messageArray) { + for (let i = 0, max = messageArray.length; i < max; i += 1) { const msg = messageArray[i]; if ( - (msg.type != 1 && msg.type != 3) || + (msg.type !== 1 && msg.type !== 3) || msg.destinationDeviceId === undefined || msg.destinationRegistrationId === undefined || msg.body === undefined || - msg.timestamp == undefined || + msg.timestamp === undefined || msg.relay !== undefined || msg.destination !== undefined ) diff --git a/libtextsecure/test/generate_keys_test.js b/libtextsecure/test/generate_keys_test.js index 93a83be89..f32348fdf 100644 --- a/libtextsecure/test/generate_keys_test.js +++ b/libtextsecure/test/generate_keys_test.js @@ -1,4 +1,6 @@ -describe('Key generation', function() { +/* global libsignal, textsecure */ + +describe('Key generation', function thisNeeded() { const count = 10; this.timeout(count * 2000); @@ -60,7 +62,7 @@ describe('Key generation', function() { result = res; }); }); - for (let i = 1; i <= count; i++) { + for (let i = 1; i <= count; i += 1) { itStoresPreKey(i); } itStoresSignedPreKey(1); @@ -68,12 +70,12 @@ describe('Key generation', function() { it(`result contains ${count} preKeys`, () => { assert.isArray(result.preKeys); assert.lengthOf(result.preKeys, count); - for (let i = 0; i < count; i++) { + for (let i = 0; i < count; i += 1) { assert.isObject(result.preKeys[i]); } }); it('result contains the correct keyIds', () => { - for (let i = 0; i < count; i++) { + for (let i = 0; i < count; i += 1) { assert.strictEqual(result.preKeys[i].keyId, i + 1); } }); @@ -93,7 +95,7 @@ describe('Key generation', function() { result = res; }); }); - for (let i = 1; i <= 2 * count; i++) { + for (let i = 1; i <= 2 * count; i += 1) { itStoresPreKey(i); } itStoresSignedPreKey(1); @@ -101,12 +103,12 @@ describe('Key generation', function() { it(`result contains ${count} preKeys`, () => { assert.isArray(result.preKeys); assert.lengthOf(result.preKeys, count); - for (let i = 0; i < count; i++) { + for (let i = 0; i < count; i += 1) { assert.isObject(result.preKeys[i]); } }); it('result contains the correct keyIds', () => { - for (let i = 1; i <= count; i++) { + for (let i = 1; i <= count; i += 1) { assert.strictEqual(result.preKeys[i - 1].keyId, i + count); } }); @@ -126,7 +128,7 @@ describe('Key generation', function() { result = res; }); }); - for (let i = 1; i <= 3 * count; i++) { + for (let i = 1; i <= 3 * count; i += 1) { itStoresPreKey(i); } itStoresSignedPreKey(2); @@ -134,12 +136,12 @@ describe('Key generation', function() { it(`result contains ${count} preKeys`, () => { assert.isArray(result.preKeys); assert.lengthOf(result.preKeys, count); - for (let i = 0; i < count; i++) { + for (let i = 0; i < count; i += 1) { assert.isObject(result.preKeys[i]); } }); it('result contains the correct keyIds', () => { - for (let i = 1; i <= count; i++) { + for (let i = 1; i <= count; i += 1) { assert.strictEqual(result.preKeys[i - 1].keyId, i + 2 * count); } }); diff --git a/libtextsecure/test/helpers_test.js b/libtextsecure/test/helpers_test.js index b15ee28bb..66ecb83e7 100644 --- a/libtextsecure/test/helpers_test.js +++ b/libtextsecure/test/helpers_test.js @@ -12,7 +12,6 @@ describe('Helpers', () => { describe('stringToArrayBuffer', () => { it('returns ArrayBuffer when passed string', () => { - const StaticArrayBufferProto = new ArrayBuffer().__proto__; const anArrayBuffer = new ArrayBuffer(1); const typedArray = new Uint8Array(anArrayBuffer); typedArray[0] = 'a'.charCodeAt(0); diff --git a/libtextsecure/test/in_memory_signal_protocol_store.js b/libtextsecure/test/in_memory_signal_protocol_store.js index 50e98c419..9b8ce813a 100644 --- a/libtextsecure/test/in_memory_signal_protocol_store.js +++ b/libtextsecure/test/in_memory_signal_protocol_store.js @@ -36,10 +36,10 @@ SignalProtocolStore.prototype = { isTrustedIdentity(identifier, identityKey) { if (identifier === null || identifier === undefined) { - throw new error('tried to check identity key for undefined/null key'); + throw new Error('tried to check identity key for undefined/null key'); } if (!(identityKey instanceof ArrayBuffer)) { - throw new error('Expected identityKey to be an ArrayBuffer'); + throw new Error('Expected identityKey to be an ArrayBuffer'); } const trusted = this.get(`identityKey${identifier}`); if (trusted === undefined) { @@ -96,9 +96,11 @@ SignalProtocolStore.prototype = { loadSignedPreKeys() { return new Promise(resolve => { const res = []; - for (const i in this.store) { - if (i.startsWith('25519KeysignedKey')) { - res.push(this.store[i]); + const keys = Object.keys(this.store); + for (let i = 0, max = keys.length; i < max; i += 1) { + const key = keys[i]; + if (key.startsWith('25519KeysignedKey')) { + res.push(this.store[key]); } } resolve(res); @@ -127,7 +129,9 @@ SignalProtocolStore.prototype = { }, removeAllSessions(identifier) { return new Promise(resolve => { - for (key in this.store) { + const keys = Object.keys(this.store); + for (let i = 0, max = keys.length; i < max; i += 1) { + const key = keys[i]; if (key.match(RegExp(`^session${identifier.replace('+', '\\+')}.+`))) { delete this.store[key]; } @@ -138,9 +142,11 @@ SignalProtocolStore.prototype = { getDeviceIds(identifier) { return new Promise(resolve => { const deviceIds = []; - for (key in this.store) { + const keys = Object.keys(this.store); + for (let i = 0, max = keys.length; i < max; i += 1) { + const key = keys[i]; if (key.match(RegExp(`^session${identifier.replace('+', '\\+')}.+`))) { - deviceIds.push(parseInt(key.split('.')[1])); + deviceIds.push(parseInt(key.split('.')[1], 10)); } } resolve(deviceIds); diff --git a/libtextsecure/test/message_receiver_test.js b/libtextsecure/test/message_receiver_test.js index 88def8cd4..0715b173d 100644 --- a/libtextsecure/test/message_receiver_test.js +++ b/libtextsecure/test/message_receiver_test.js @@ -1,9 +1,12 @@ +/* global libsignal, textsecure, SignalProtocolStore */ + describe('MessageReceiver', () => { textsecure.storage.impl = new SignalProtocolStore(); - const WebSocket = window.WebSocket; + const { WebSocket } = window; const number = '+19999999999'; const deviceId = 1; const signalingKey = libsignal.crypto.getRandomBytes(32 + 20); + before(() => { window.WebSocket = MockSocket; textsecure.storage.user.setNumberAndDeviceId(number, deviceId, 'name'); @@ -15,7 +18,6 @@ describe('MessageReceiver', () => { }); describe('connecting', () => { - const blob = null; const attrs = { type: textsecure.protobuf.Envelope.Type.CIPHERTEXT, source: number, @@ -29,14 +31,12 @@ describe('MessageReceiver', () => { before(done => { const signal = new textsecure.protobuf.Envelope(attrs).toArrayBuffer(); - const data = new textsecure.protobuf.DataMessage({ body: 'hello' }); - const signaling_key = signalingKey; - const aes_key = signaling_key.slice(0, 32); - const mac_key = signaling_key.slice(32, 32 + 20); + const aesKey = signalingKey.slice(0, 32); + const macKey = signalingKey.slice(32, 32 + 20); window.crypto.subtle - .importKey('raw', aes_key, { name: 'AES-CBC' }, false, ['encrypt']) + .importKey('raw', aesKey, { name: 'AES-CBC' }, false, ['encrypt']) .then(key => { const iv = libsignal.crypto.getRandomBytes(16); window.crypto.subtle @@ -45,14 +45,14 @@ describe('MessageReceiver', () => { window.crypto.subtle .importKey( 'raw', - mac_key, + macKey, { name: 'HMAC', hash: { name: 'SHA-256' } }, false, ['sign'] ) - .then(key => { + .then(innerKey => { window.crypto.subtle - .sign({ name: 'HMAC', hash: 'SHA-256' }, key, signal) + .sign({ name: 'HMAC', hash: 'SHA-256' }, innerKey, signal) .then(mac => { const version = new Uint8Array([1]); const message = dcodeIO.ByteBuffer.concat([ @@ -82,14 +82,19 @@ describe('MessageReceiver', () => { window.addEventListener('textsecure:message', ev => { const signal = ev.proto; - for (const key in attrs) { + const keys = Object.keys(attrs); + + for (let i = 0, max = keys.length; i < max; i += 1) { + const key = keys[i]; assert.strictEqual(attrs[key], signal[key]); } assert.strictEqual(signal.message.body, 'hello'); - server.close(); + mockServer.close(); + done(); }); - const messageReceiver = new textsecure.MessageReceiver( + + window.messageReceiver = new textsecure.MessageReceiver( 'username', 'password', 'signalingKey' diff --git a/libtextsecure/test/protocol_test.js b/libtextsecure/test/protocol_test.js index 539731d07..aad806caf 100644 --- a/libtextsecure/test/protocol_test.js +++ b/libtextsecure/test/protocol_test.js @@ -1,32 +1,34 @@ +/* global textsecure */ + describe('Protocol', () => { describe('Unencrypted PushMessageProto "decrypt"', () => { // exclusive it('works', done => { localStorage.clear(); - const text_message = new textsecure.protobuf.DataMessage(); - text_message.body = 'Hi Mom'; - const server_message = { + const textMessage = new textsecure.protobuf.DataMessage(); + textMessage.body = 'Hi Mom'; + const serverMessage = { type: 4, // unencrypted source: '+19999999999', timestamp: 42, - message: text_message.encode(), + message: textMessage.encode(), }; return textsecure.protocol_wrapper .handleEncryptedMessage( - server_message.source, - server_message.source_device, - server_message.type, - server_message.message + serverMessage.source, + serverMessage.source_device, + serverMessage.type, + serverMessage.message ) .then(message => { - assert.equal(message.body, text_message.body); + assert.equal(message.body, textMessage.body); assert.equal( message.attachments.length, - text_message.attachments.length + textMessage.attachments.length ); - assert.equal(text_message.attachments.length, 0); + assert.equal(textMessage.attachments.length, 0); }) .then(done) .catch(done); diff --git a/libtextsecure/test/protocol_wrapper_test.js b/libtextsecure/test/protocol_wrapper_test.js index f43ee589b..8f2bffb43 100644 --- a/libtextsecure/test/protocol_wrapper_test.js +++ b/libtextsecure/test/protocol_wrapper_test.js @@ -1,19 +1,20 @@ -describe('Protocol Wrapper', function() { +/* global libsignal, textsecure */ + +describe('Protocol Wrapper', function thisNeeded() { const store = textsecure.storage.protocol; const identifier = '+5558675309'; - const another_identifier = '+5555590210'; - let prekeys, identityKey, testKey; + this.timeout(5000); + before(done => { localStorage.clear(); libsignal.KeyHelper.generateIdentityKeyPair() - .then(identityKey => - textsecure.storage.protocol.saveIdentity(identifier, identityKey) - ) + .then(key => textsecure.storage.protocol.saveIdentity(identifier, key)) .then(() => { done(); }); }); + describe('processPreKey', () => { it('rejects if the identity key changes', () => { const address = new libsignal.SignalProtocolAddress(identifier, 1); diff --git a/libtextsecure/test/storage_test.js b/libtextsecure/test/storage_test.js index 8dca19410..b2d615edd 100644 --- a/libtextsecure/test/storage_test.js +++ b/libtextsecure/test/storage_test.js @@ -1,10 +1,11 @@ +/* global libsignal, textsecure */ + describe('SignalProtocolStore', () => { before(() => { localStorage.clear(); }); const store = textsecure.storage.protocol; const identifier = '+5558675309'; - const another_identifier = '+5555590210'; const identityKey = { pubKey: libsignal.crypto.getRandomBytes(33), privKey: libsignal.crypto.getRandomBytes(32), @@ -13,176 +14,121 @@ describe('SignalProtocolStore', () => { pubKey: libsignal.crypto.getRandomBytes(33), privKey: libsignal.crypto.getRandomBytes(32), }; - it('retrieves my registration id', done => { + it('retrieves my registration id', async () => { store.put('registrationId', 1337); - store - .getLocalRegistrationId() - .then(reg => { - assert.strictEqual(reg, 1337); - }) - .then(done, done); + + const reg = await store.getLocalRegistrationId(); + assert.strictEqual(reg, 1337); }); - it('retrieves my identity key', done => { + it('retrieves my identity key', async () => { store.put('identityKey', identityKey); - store - .getIdentityKeyPair() - .then(key => { - assertEqualArrayBuffers(key.pubKey, identityKey.pubKey); - assertEqualArrayBuffers(key.privKey, identityKey.privKey); + const key = await store.getIdentityKeyPair(); + assertEqualArrayBuffers(key.pubKey, identityKey.pubKey); + assertEqualArrayBuffers(key.privKey, identityKey.privKey); + }); + it('stores identity keys', async () => { + await store.saveIdentity(identifier, testKey.pubKey); + const key = await store.loadIdentityKey(identifier); + assertEqualArrayBuffers(key, testKey.pubKey); + }); + it('returns whether a key is trusted', async () => { + const newIdentity = libsignal.crypto.getRandomBytes(33); + await store.saveIdentity(identifier, testKey.pubKey); + + const trusted = await store.isTrustedIdentity(identifier, newIdentity); + if (trusted) { + throw new Error('Allowed to overwrite identity key'); + } + }); + it('returns whether a key is untrusted', async () => { + await store.saveIdentity(identifier, testKey.pubKey); + const trusted = await store.isTrustedIdentity(identifier, testKey.pubKey); + + if (!trusted) { + throw new Error('Allowed to overwrite identity key'); + } + }); + it('stores prekeys', async () => { + await store.storePreKey(1, testKey); + + const key = await store.loadPreKey(1); + assertEqualArrayBuffers(key.pubKey, testKey.pubKey); + assertEqualArrayBuffers(key.privKey, testKey.privKey); + }); + it('deletes prekeys', async () => { + await store.storePreKey(2, testKey); + await store.removePreKey(2, testKey); + + const key = await store.loadPreKey(2); + assert.isUndefined(key); + }); + it('stores signed prekeys', async () => { + await store.storeSignedPreKey(3, testKey); + + const key = await store.loadSignedPreKey(3); + assertEqualArrayBuffers(key.pubKey, testKey.pubKey); + assertEqualArrayBuffers(key.privKey, testKey.privKey); + }); + it('deletes signed prekeys', async () => { + await store.storeSignedPreKey(4, testKey); + await store.removeSignedPreKey(4, testKey); + + const key = await store.loadSignedPreKey(4); + assert.isUndefined(key); + }); + it('stores sessions', async () => { + const testRecord = 'an opaque string'; + const devices = [1, 2, 3].map(deviceId => [identifier, deviceId].join('.')); + + await Promise.all( + devices.map(async encodedNumber => { + await store.storeSession(encodedNumber, testRecord + encodedNumber); }) - .then(done, done); + ); + + const records = await Promise.all( + devices.map(store.loadSession.bind(store)) + ); + + for (let i = 0, max = records.length; i < max; i += 1) { + assert.strictEqual(records[i], testRecord + devices[i]); + } }); - it('stores identity keys', done => { - store - .saveIdentity(identifier, testKey.pubKey) - .then(() => - store.loadIdentityKey(identifier).then(key => { - assertEqualArrayBuffers(key, testKey.pubKey); - }) - ) - .then(done, done); - }); - it('returns whether a key is trusted', done => { - const newIdentity = libsignal.crypto.getRandomBytes(33); - store.saveIdentity(identifier, testKey.pubKey).then(() => { - store - .isTrustedIdentity(identifier, newIdentity) - .then(trusted => { - if (trusted) { - done(new Error('Allowed to overwrite identity key')); - } else { - done(); - } - }) - .catch(done); - }); - }); - it('returns whether a key is untrusted', done => { - const newIdentity = libsignal.crypto.getRandomBytes(33); - store.saveIdentity(identifier, testKey.pubKey).then(() => { - store - .isTrustedIdentity(identifier, testKey.pubKey) - .then(trusted => { - if (trusted) { - done(); - } else { - done(new Error('Allowed to overwrite identity key')); - } - }) - .catch(done); - }); - }); - it('stores prekeys', done => { - store - .storePreKey(1, testKey) - .then(() => - store.loadPreKey(1).then(key => { - assertEqualArrayBuffers(key.pubKey, testKey.pubKey); - assertEqualArrayBuffers(key.privKey, testKey.privKey); - }) - ) - .then(done, done); - }); - it('deletes prekeys', done => { - before(done => { - store.storePreKey(2, testKey).then(done); - }); - store - .removePreKey(2, testKey) - .then(() => - store.loadPreKey(2).then(key => { - assert.isUndefined(key); - }) - ) - .then(done, done); - }); - it('stores signed prekeys', done => { - store - .storeSignedPreKey(3, testKey) - .then(() => - store.loadSignedPreKey(3).then(key => { - assertEqualArrayBuffers(key.pubKey, testKey.pubKey); - assertEqualArrayBuffers(key.privKey, testKey.privKey); - }) - ) - .then(done, done); - }); - it('deletes signed prekeys', done => { - before(done => { - store.storeSignedPreKey(4, testKey).then(done); - }); - store - .removeSignedPreKey(4, testKey) - .then(() => - store.loadSignedPreKey(4).then(key => { - assert.isUndefined(key); - }) - ) - .then(done, done); - }); - it('stores sessions', done => { + it('removes all sessions for a number', async () => { const testRecord = 'an opaque string'; const devices = [1, 2, 3].map(deviceId => [identifier, deviceId].join('.')); - let promise = Promise.resolve(); - devices.forEach(encodedNumber => { - promise = promise.then(() => - store.storeSession(encodedNumber, testRecord + encodedNumber) - ); - }); - promise - .then(() => - Promise.all(devices.map(store.loadSession.bind(store))).then( - records => { - for (const i in records) { - assert.strictEqual(records[i], testRecord + devices[i]); - } - } - ) - ) - .then(done, done); + + await Promise.all( + devices.map(async encodedNumber => { + await store.storeSession(encodedNumber, testRecord + encodedNumber); + }) + ); + + await store.removeAllSessions(identifier); + + const records = await Promise.all( + devices.map(store.loadSession.bind(store)) + ); + + for (let i = 0, max = records.length; i < max; i += 1) { + assert.isUndefined(records[i]); + } }); - it('removes all sessions for a number', done => { + it('returns deviceIds for a number', async () => { const testRecord = 'an opaque string'; const devices = [1, 2, 3].map(deviceId => [identifier, deviceId].join('.')); - let promise = Promise.resolve(); - devices.forEach(encodedNumber => { - promise = promise.then(() => - store.storeSession(encodedNumber, testRecord + encodedNumber) - ); - }); - promise - .then(() => - store.removeAllSessions(identifier).then(record => - Promise.all(devices.map(store.loadSession.bind(store))).then( - records => { - for (const i in records) { - assert.isUndefined(records[i]); - } - } - ) - ) - ) - .then(done, done); + + await Promise.all( + devices.map(async encodedNumber => { + await store.storeSession(encodedNumber, testRecord + encodedNumber); + }) + ); + + const deviceIds = await store.getDeviceIds(identifier); + assert.sameMembers(deviceIds, [1, 2, 3]); }); - it('returns deviceIds for a number', done => { - const testRecord = 'an opaque string'; - const devices = [1, 2, 3].map(deviceId => [identifier, deviceId].join('.')); - let promise = Promise.resolve(); - devices.forEach(encodedNumber => { - promise = promise.then(() => - store.storeSession(encodedNumber, testRecord + encodedNumber) - ); - }); - promise - .then(() => - store.getDeviceIds(identifier).then(deviceIds => { - assert.sameMembers(deviceIds, [1, 2, 3]); - }) - ) - .then(done, done); + it('returns empty array for a number with no device ids', async () => { + const deviceIds = await store.getDeviceIds('foo'); + assert.sameMembers(deviceIds, []); }); - it('returns empty array for a number with no device ids', () => - store.getDeviceIds('foo').then(deviceIds => { - assert.sameMembers(deviceIds, []); - })); }); diff --git a/libtextsecure/test/task_with_timeout_test.js b/libtextsecure/test/task_with_timeout_test.js index 81c12a9fd..54b8016c7 100644 --- a/libtextsecure/test/task_with_timeout_test.js +++ b/libtextsecure/test/task_with_timeout_test.js @@ -1,8 +1,8 @@ +/* global textsecure */ + describe('createTaskWithTimeout', () => { it('resolves when promise resolves', () => { - const task = function() { - return Promise.resolve('hi!'); - }; + const task = () => Promise.resolve('hi!'); const taskWithTimeout = textsecure.createTaskWithTimeout(task); return taskWithTimeout().then(result => { @@ -11,26 +11,22 @@ describe('createTaskWithTimeout', () => { }); it('flows error from promise back', () => { const error = new Error('original'); - const task = function() { - return Promise.reject(error); - }; + const task = () => Promise.reject(error); const taskWithTimeout = textsecure.createTaskWithTimeout(task); return taskWithTimeout().catch(flowedError => { assert.strictEqual(error, flowedError); }); }); - it('rejects if promise takes too long (this one logs error to console)', function() { - const error = new Error('original'); + it('rejects if promise takes too long (this one logs error to console)', () => { let complete = false; - const task = function() { - return new Promise(resolve => { + const task = () => + new Promise(resolve => { setTimeout(() => { complete = true; resolve(); }, 3000); }); - }; const taskWithTimeout = textsecure.createTaskWithTimeout(task, this.name, { timeout: 10, }); @@ -45,29 +41,27 @@ describe('createTaskWithTimeout', () => { ); }); it('resolves if task returns something falsey', () => { - const task = function() {}; + const task = () => {}; const taskWithTimeout = textsecure.createTaskWithTimeout(task); return taskWithTimeout(); }); it('resolves if task returns a non-promise', () => { - const task = function() { - return 'hi!'; - }; + const task = () => 'hi!'; const taskWithTimeout = textsecure.createTaskWithTimeout(task); return taskWithTimeout().then(result => { assert.strictEqual(result, 'hi!'); }); }); - it('rejects if task throws (and does not log about taking too long)', function() { + it('rejects if task throws (and does not log about taking too long)', () => { const error = new Error('Task is throwing!'); - const task = function() { + const task = () => { throw error; }; const taskWithTimeout = textsecure.createTaskWithTimeout(task, this.name, { timeout: 10, }); return taskWithTimeout().then( - result => { + () => { throw new Error('Overall task should reject!'); }, flowedError => { diff --git a/libtextsecure/test/websocket-resources_test.js b/libtextsecure/test/websocket-resources_test.js index 7ed4c91d5..4ce99ddd4 100644 --- a/libtextsecure/test/websocket-resources_test.js +++ b/libtextsecure/test/websocket-resources_test.js @@ -1,208 +1,214 @@ -(function() { - describe('WebSocket-Resource', () => { - describe('requests and responses', () => { - it('receives requests and sends responses', done => { - // mock socket - const request_id = '1'; - const socket = { - send(data) { - const message = textsecure.protobuf.WebSocketMessage.decode(data); - assert.strictEqual( - message.type, - textsecure.protobuf.WebSocketMessage.Type.RESPONSE - ); - assert.strictEqual(message.response.message, 'OK'); - assert.strictEqual(message.response.status, 200); - assert.strictEqual(message.response.id.toString(), request_id); - done(); - }, - addEventListener() {}, - }; +/* global textsecure, WebSocketResource */ - // actual test - const resource = new WebSocketResource(socket, { - handleRequest(request) { - assert.strictEqual(request.verb, 'PUT'); - assert.strictEqual(request.path, '/some/path'); - assertEqualArrayBuffers( - request.body.toArrayBuffer(), - new Uint8Array([1, 2, 3]).buffer - ); - request.respond(200, 'OK'); - }, - }); +describe('WebSocket-Resource', () => { + describe('requests and responses', () => { + it('receives requests and sends responses', done => { + // mock socket + const requestId = '1'; + const socket = { + send(data) { + const message = textsecure.protobuf.WebSocketMessage.decode(data); + assert.strictEqual( + message.type, + textsecure.protobuf.WebSocketMessage.Type.RESPONSE + ); + assert.strictEqual(message.response.message, 'OK'); + assert.strictEqual(message.response.status, 200); + assert.strictEqual(message.response.id.toString(), requestId); + done(); + }, + addEventListener() {}, + }; - // mock socket request - socket.onmessage({ - data: new Blob([ - new textsecure.protobuf.WebSocketMessage({ - type: textsecure.protobuf.WebSocketMessage.Type.REQUEST, - request: { - id: request_id, - verb: 'PUT', - path: '/some/path', - body: new Uint8Array([1, 2, 3]).buffer, - }, - }) - .encode() - .toArrayBuffer(), - ]), - }); + // actual test + this.resource = new WebSocketResource(socket, { + handleRequest(request) { + assert.strictEqual(request.verb, 'PUT'); + assert.strictEqual(request.path, '/some/path'); + assertEqualArrayBuffers( + request.body.toArrayBuffer(), + new Uint8Array([1, 2, 3]).buffer + ); + request.respond(200, 'OK'); + }, }); - it('sends requests and receives responses', done => { - // mock socket and request handler - let request_id; - const socket = { - send(data) { - const message = textsecure.protobuf.WebSocketMessage.decode(data); - assert.strictEqual( - message.type, - textsecure.protobuf.WebSocketMessage.Type.REQUEST - ); - assert.strictEqual(message.request.verb, 'PUT'); - assert.strictEqual(message.request.path, '/some/path'); - assertEqualArrayBuffers( - message.request.body.toArrayBuffer(), - new Uint8Array([1, 2, 3]).buffer - ); - request_id = message.request.id; - }, - addEventListener() {}, - }; - - // actual test - const resource = new WebSocketResource(socket); - resource.sendRequest({ - verb: 'PUT', - path: '/some/path', - body: new Uint8Array([1, 2, 3]).buffer, - error: done, - success(message, status, request) { - assert.strictEqual(message, 'OK'); - assert.strictEqual(status, 200); - done(); - }, - }); - - // mock socket response - socket.onmessage({ - data: new Blob([ - new textsecure.protobuf.WebSocketMessage({ - type: textsecure.protobuf.WebSocketMessage.Type.RESPONSE, - response: { id: request_id, message: 'OK', status: 200 }, - }) - .encode() - .toArrayBuffer(), - ]), - }); + // mock socket request + socket.onmessage({ + data: new Blob([ + new textsecure.protobuf.WebSocketMessage({ + type: textsecure.protobuf.WebSocketMessage.Type.REQUEST, + request: { + id: requestId, + verb: 'PUT', + path: '/some/path', + body: new Uint8Array([1, 2, 3]).buffer, + }, + }) + .encode() + .toArrayBuffer(), + ]), }); }); - describe('close', () => { - before(() => { - window.WebSocket = MockSocket; - }); - after(() => { - window.WebSocket = WebSocket; - }); - it('closes the connection', done => { - const mockServer = new MockServer('ws://localhost:8081'); - mockServer.on('connection', server => { - server.on('close', done); - }); - const resource = new WebSocketResource( - new WebSocket('ws://localhost:8081') - ); - resource.close(); - }); - }); + it('sends requests and receives responses', done => { + // mock socket and request handler + let requestId; + const socket = { + send(data) { + const message = textsecure.protobuf.WebSocketMessage.decode(data); + assert.strictEqual( + message.type, + textsecure.protobuf.WebSocketMessage.Type.REQUEST + ); + assert.strictEqual(message.request.verb, 'PUT'); + assert.strictEqual(message.request.path, '/some/path'); + assertEqualArrayBuffers( + message.request.body.toArrayBuffer(), + new Uint8Array([1, 2, 3]).buffer + ); + requestId = message.request.id; + }, + addEventListener() {}, + }; - describe.skip('with a keepalive config', function() { - before(() => { - window.WebSocket = MockSocket; - }); - after(() => { - window.WebSocket = WebSocket; - }); - this.timeout(60000); - it('sends keepalives once a minute', done => { - const mockServer = new MockServer('ws://localhost:8081'); - mockServer.on('connection', server => { - server.on('message', data => { - const message = textsecure.protobuf.WebSocketMessage.decode(data); - assert.strictEqual( - message.type, - textsecure.protobuf.WebSocketMessage.Type.REQUEST - ); - assert.strictEqual(message.request.verb, 'GET'); - assert.strictEqual(message.request.path, '/v1/keepalive'); - server.close(); - done(); - }); - }); - new WebSocketResource(new WebSocket('ws://localhost:8081'), { - keepalive: { path: '/v1/keepalive' }, - }); + // actual test + const resource = new WebSocketResource(socket); + resource.sendRequest({ + verb: 'PUT', + path: '/some/path', + body: new Uint8Array([1, 2, 3]).buffer, + error: done, + success(message, status) { + assert.strictEqual(message, 'OK'); + assert.strictEqual(status, 200); + done(); + }, }); - it('uses / as a default path', done => { - const mockServer = new MockServer('ws://localhost:8081'); - mockServer.on('connection', server => { - server.on('message', data => { - const message = textsecure.protobuf.WebSocketMessage.decode(data); - assert.strictEqual( - message.type, - textsecure.protobuf.WebSocketMessage.Type.REQUEST - ); - assert.strictEqual(message.request.verb, 'GET'); - assert.strictEqual(message.request.path, '/'); - server.close(); - done(); - }); - }); - new WebSocketResource(new WebSocket('ws://localhost:8081'), { - keepalive: true, - }); - }); - - it('optionally disconnects if no response', function(done) { - this.timeout(65000); - const mockServer = new MockServer('ws://localhost:8081'); - const socket = new WebSocket('ws://localhost:8081'); - mockServer.on('connection', server => { - server.on('close', done); - }); - new WebSocketResource(socket, { keepalive: true }); - }); - - it('allows resetting the keepalive timer', function(done) { - this.timeout(65000); - const mockServer = new MockServer('ws://localhost:8081'); - const socket = new WebSocket('ws://localhost:8081'); - const startTime = Date.now(); - mockServer.on('connection', server => { - server.on('message', data => { - const message = textsecure.protobuf.WebSocketMessage.decode(data); - assert.strictEqual( - message.type, - textsecure.protobuf.WebSocketMessage.Type.REQUEST - ); - assert.strictEqual(message.request.verb, 'GET'); - assert.strictEqual(message.request.path, '/'); - assert( - Date.now() > startTime + 60000, - 'keepalive time should be longer than a minute' - ); - server.close(); - done(); - }); - }); - const resource = new WebSocketResource(socket, { keepalive: true }); - setTimeout(() => { - resource.resetKeepAliveTimer(); - }, 5000); + // mock socket response + socket.onmessage({ + data: new Blob([ + new textsecure.protobuf.WebSocketMessage({ + type: textsecure.protobuf.WebSocketMessage.Type.RESPONSE, + response: { id: requestId, message: 'OK', status: 200 }, + }) + .encode() + .toArrayBuffer(), + ]), }); }); }); -})(); + + describe('close', () => { + before(() => { + window.WebSocket = MockSocket; + }); + after(() => { + window.WebSocket = WebSocket; + }); + it('closes the connection', done => { + const mockServer = new MockServer('ws://localhost:8081'); + mockServer.on('connection', server => { + server.on('close', done); + }); + const resource = new WebSocketResource( + new WebSocket('ws://localhost:8081') + ); + resource.close(); + }); + }); + + describe.skip('with a keepalive config', function thisNeeded() { + before(() => { + window.WebSocket = MockSocket; + }); + after(() => { + window.WebSocket = WebSocket; + }); + this.timeout(60000); + it('sends keepalives once a minute', done => { + const mockServer = new MockServer('ws://localhost:8081'); + mockServer.on('connection', server => { + server.on('message', data => { + const message = textsecure.protobuf.WebSocketMessage.decode(data); + assert.strictEqual( + message.type, + textsecure.protobuf.WebSocketMessage.Type.REQUEST + ); + assert.strictEqual(message.request.verb, 'GET'); + assert.strictEqual(message.request.path, '/v1/keepalive'); + server.close(); + done(); + }); + }); + this.resource = new WebSocketResource( + new WebSocket('ws://loc1alhost:8081'), + { + keepalive: { path: '/v1/keepalive' }, + } + ); + }); + + it('uses / as a default path', done => { + const mockServer = new MockServer('ws://localhost:8081'); + mockServer.on('connection', server => { + server.on('message', data => { + const message = textsecure.protobuf.WebSocketMessage.decode(data); + assert.strictEqual( + message.type, + textsecure.protobuf.WebSocketMessage.Type.REQUEST + ); + assert.strictEqual(message.request.verb, 'GET'); + assert.strictEqual(message.request.path, '/'); + server.close(); + done(); + }); + }); + this.resource = new WebSocketResource( + new WebSocket('ws://localhost:8081'), + { + keepalive: true, + } + ); + }); + + it('optionally disconnects if no response', function thisNeeded1(done) { + this.timeout(65000); + const mockServer = new MockServer('ws://localhost:8081'); + const socket = new WebSocket('ws://localhost:8081'); + mockServer.on('connection', server => { + server.on('close', done); + }); + this.resource = new WebSocketResource(socket, { keepalive: true }); + }); + + it('allows resetting the keepalive timer', function thisNeeded2(done) { + this.timeout(65000); + const mockServer = new MockServer('ws://localhost:8081'); + const socket = new WebSocket('ws://localhost:8081'); + const startTime = Date.now(); + mockServer.on('connection', server => { + server.on('message', data => { + const message = textsecure.protobuf.WebSocketMessage.decode(data); + assert.strictEqual( + message.type, + textsecure.protobuf.WebSocketMessage.Type.REQUEST + ); + assert.strictEqual(message.request.verb, 'GET'); + assert.strictEqual(message.request.path, '/'); + assert( + Date.now() > startTime + 60000, + 'keepalive time should be longer than a minute' + ); + server.close(); + done(); + }); + }); + const resource = new WebSocketResource(socket, { keepalive: true }); + setTimeout(() => { + resource.resetKeepAliveTimer(); + }, 5000); + }); + }); +}); diff --git a/libtextsecure/test/websocket_test.js b/libtextsecure/test/websocket_test.js index 3ba7ca5e3..dcaa749fd 100644 --- a/libtextsecure/test/websocket_test.js +++ b/libtextsecure/test/websocket_test.js @@ -1,3 +1,5 @@ +/* global TextSecureWebSocket */ + describe('TextSecureWebSocket', () => { const RealWebSocket = window.WebSocket; before(() => { @@ -13,19 +15,19 @@ describe('TextSecureWebSocket', () => { server.close(); done(); }); - var socket = new TextSecureWebSocket('ws://localhost:8080'); + const socket = new TextSecureWebSocket('ws://localhost:8080'); }); it('sends and receives', done => { const mockServer = new MockServer('ws://localhost:8080'); mockServer.on('connection', server => { - server.on('message', data => { + server.on('message', () => { server.send('ack'); server.close(); }); }); const socket = new TextSecureWebSocket('ws://localhost:8080'); - socket.onmessage = function(response) { + socket.onmessage = response => { assert.strictEqual(response.data, 'ack'); socket.close(); done(); @@ -40,20 +42,20 @@ describe('TextSecureWebSocket', () => { server.close(); socket.close(); }); - var socket = new TextSecureWebSocket('ws://localhost:8082'); - socket.onclose = function() { + const socket = new TextSecureWebSocket('ws://localhost:8082'); + socket.onclose = () => { assert.strictEqual(socket.getStatus(), WebSocket.CLOSING); done(); }; }); - it('reconnects', function(done) { + it('reconnects', function thisNeeded(done) { this.timeout(60000); const mockServer = new MockServer('ws://localhost:8082'); const socket = new TextSecureWebSocket('ws://localhost:8082'); - socket.onclose = function() { - const mockServer = new MockServer('ws://localhost:8082'); - mockServer.on('connection', server => { + socket.onclose = () => { + const secondServer = new MockServer('ws://localhost:8082'); + secondServer.on('connection', server => { socket.close(); server.close(); done(); diff --git a/test/.eslintrc.js b/test/.eslintrc.js index 10d3dec2f..0f2f1a02f 100644 --- a/test/.eslintrc.js +++ b/test/.eslintrc.js @@ -8,6 +8,15 @@ module.exports = { globals: { assert: true, + assertEqualArrayBuffers: true, + clearDatabase: true, + dcodeIO: true, + getString: true, + hexToArrayBuffer: true, + MockServer: true, + MockSocket: true, + PROTO_ROOT: true, + stringToArrayBuffer: true, }, parserOptions: { @@ -25,5 +34,8 @@ module.exports = { // We want to keep each test structured the same, even if its contents are tiny 'arrow-body-style': 'off', + + strict: 'off', + 'more/no-then': 'off', }, }; diff --git a/test/_test.js b/test/_test.js index c5ad6411f..56dd75b71 100644 --- a/test/_test.js +++ b/test/_test.js @@ -1,43 +1,45 @@ +/* global chai, Whisper */ + mocha.setup('bdd'); window.assert = chai.assert; window.PROTO_ROOT = '../protos'; -(function() { - var OriginalReporter = mocha._reporter; +const OriginalReporter = mocha._reporter; - var SauceReporter = function(runner) { - var failedTests = []; +const SauceReporter = runner => { + const failedTests = []; - runner.on('end', function() { - window.mochaResults = runner.stats; - window.mochaResults.reports = failedTests; + runner.on('end', () => { + window.mochaResults = runner.stats; + window.mochaResults.reports = failedTests; + }); + + runner.on('fail', (test, err) => { + const flattenTitles = item => { + const titles = []; + while (item.parent.title) { + titles.push(item.parent.title); + // eslint-disable-next-line no-param-reassign + item = item.parent; + } + return titles.reverse(); + }; + failedTests.push({ + name: test.title, + result: false, + message: err.message, + stack: err.stack, + titles: flattenTitles(test), }); + }); - runner.on('fail', function(test, err) { - var flattenTitles = function(test) { - var titles = []; - while (test.parent.title) { - titles.push(test.parent.title); - test = test.parent; - } - return titles.reverse(); - }; - failedTests.push({ - name: test.title, - result: false, - message: err.message, - stack: err.stack, - titles: flattenTitles(test), - }); - }); + // eslint-disable-next-line no-new + new OriginalReporter(runner); +}; - new OriginalReporter(runner); - }; +SauceReporter.prototype = OriginalReporter.prototype; - SauceReporter.prototype = OriginalReporter.prototype; - - mocha.reporter(SauceReporter); -})(); +mocha.reporter(SauceReporter); // Override the database id. window.Whisper = window.Whisper || {}; @@ -47,22 +49,22 @@ Whisper.Database.id = 'test'; /* * global helpers for tests */ -function assertEqualArrayBuffers(ab1, ab2) { +window.assertEqualArrayBuffers = (ab1, ab2) => { assert.deepEqual(new Uint8Array(ab1), new Uint8Array(ab2)); -} +}; -function hexToArrayBuffer(str) { - var ret = new ArrayBuffer(str.length / 2); - var array = new Uint8Array(ret); - for (var i = 0; i < str.length / 2; i++) { +window.hexToArrayBuffer = str => { + const ret = new ArrayBuffer(str.length / 2); + const array = new Uint8Array(ret); + for (let i = 0; i < str.length / 2; i += 1) { array[i] = parseInt(str.substr(i * 2, 2), 16); } return ret; -} +}; -function deleteDatabase() { +function deleteIndexedDB() { return new Promise((resolve, reject) => { - var idbReq = indexedDB.deleteDatabase('test'); + const idbReq = indexedDB.deleteIndexedDB('test'); idbReq.onsuccess = resolve; idbReq.error = reject; }); @@ -70,10 +72,10 @@ function deleteDatabase() { /* Delete the database before running any tests */ before(async () => { - await deleteDatabase(); + await deleteIndexedDB(); await window.Signal.Data.removeAll(); }); -async function clearDatabase() { +window.clearDatabase = async () => { await window.Signal.Data.removeAll(); -} +}; diff --git a/test/backup_test.js b/test/backup_test.js index 9008d64f1..2ac94cea9 100644 --- a/test/backup_test.js +++ b/test/backup_test.js @@ -4,7 +4,7 @@ /* global textsecure: false */ /* global _: false */ -/* eslint-disable no-unreachable */ +/* eslint-disable no-unreachable, no-console */ 'use strict'; diff --git a/test/conversation_controller_test.js b/test/conversation_controller_test.js index 2bd5cea9e..b8c01d99c 100644 --- a/test/conversation_controller_test.js +++ b/test/conversation_controller_test.js @@ -1,8 +1,10 @@ +/* global Whisper */ + 'use strict'; -describe('ConversationController', function() { - it('sorts conversations based on timestamp then by intl-friendly title', function() { - var collection = window.getInboxCollection(); +describe('ConversationController', () => { + it('sorts conversations based on timestamp then by intl-friendly title', () => { + const collection = window.getInboxCollection(); collection.reset([]); collection.add( diff --git a/test/crypto_test.js b/test/crypto_test.js index e864411ee..fe0800132 100644 --- a/test/crypto_test.js +++ b/test/crypto_test.js @@ -1,3 +1,5 @@ +/* global Signal, textsecure */ + 'use strict'; describe('Crypto', () => { @@ -16,39 +18,36 @@ describe('Crypto', () => { describe('symmetric encryption', () => { it('roundtrips', async () => { - var message = 'this is my message'; - var plaintext = new dcodeIO.ByteBuffer.wrap( + const message = 'this is my message'; + const plaintext = dcodeIO.ByteBuffer.wrap( message, 'binary' ).toArrayBuffer(); - var key = textsecure.crypto.getRandomBytes(32); + const key = textsecure.crypto.getRandomBytes(32); - var encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); - var decrypted = await Signal.Crypto.decryptSymmetric(key, encrypted); + const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); + const decrypted = await Signal.Crypto.decryptSymmetric(key, encrypted); - var equal = Signal.Crypto.constantTimeEqual(plaintext, decrypted); + const equal = Signal.Crypto.constantTimeEqual(plaintext, decrypted); if (!equal) { throw new Error('The output and input did not match!'); } }); it('roundtrip fails if nonce is modified', async () => { - var message = 'this is my message'; - var plaintext = new dcodeIO.ByteBuffer.wrap( + const message = 'this is my message'; + const plaintext = dcodeIO.ByteBuffer.wrap( message, 'binary' ).toArrayBuffer(); - var key = textsecure.crypto.getRandomBytes(32); + const key = textsecure.crypto.getRandomBytes(32); - var encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); - var uintArray = new Uint8Array(encrypted); + const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); + const uintArray = new Uint8Array(encrypted); uintArray[2] = 9; try { - var decrypted = await Signal.Crypto.decryptSymmetric( - key, - uintArray.buffer - ); + await Signal.Crypto.decryptSymmetric(key, uintArray.buffer); } catch (error) { assert.strictEqual( error.message, @@ -61,22 +60,19 @@ describe('Crypto', () => { }); it('roundtrip fails if mac is modified', async () => { - var message = 'this is my message'; - var plaintext = new dcodeIO.ByteBuffer.wrap( + const message = 'this is my message'; + const plaintext = dcodeIO.ByteBuffer.wrap( message, 'binary' ).toArrayBuffer(); - var key = textsecure.crypto.getRandomBytes(32); + const key = textsecure.crypto.getRandomBytes(32); - var encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); - var uintArray = new Uint8Array(encrypted); + const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); + const uintArray = new Uint8Array(encrypted); uintArray[uintArray.length - 3] = 9; try { - var decrypted = await Signal.Crypto.decryptSymmetric( - key, - uintArray.buffer - ); + await Signal.Crypto.decryptSymmetric(key, uintArray.buffer); } catch (error) { assert.strictEqual( error.message, @@ -89,22 +85,19 @@ describe('Crypto', () => { }); it('roundtrip fails if encrypted contents are modified', async () => { - var message = 'this is my message'; - var plaintext = new dcodeIO.ByteBuffer.wrap( + const message = 'this is my message'; + const plaintext = dcodeIO.ByteBuffer.wrap( message, 'binary' ).toArrayBuffer(); - var key = textsecure.crypto.getRandomBytes(32); + const key = textsecure.crypto.getRandomBytes(32); - var encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); - var uintArray = new Uint8Array(encrypted); + const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); + const uintArray = new Uint8Array(encrypted); uintArray[35] = 9; try { - var decrypted = await Signal.Crypto.decryptSymmetric( - key, - uintArray.buffer - ); + await Signal.Crypto.decryptSymmetric(key, uintArray.buffer); } catch (error) { assert.strictEqual( error.message, diff --git a/test/database_test.js b/test/database_test.js index 7d67ad356..bd75b7c0a 100644 --- a/test/database_test.js +++ b/test/database_test.js @@ -1,30 +1,32 @@ +/* global Whisper */ + 'use strict'; -describe('Database', function() { - describe('handleDOMException', function() { - it('handles null, still calls reject', function() { - var called = 0; - var reject = function() { +describe('Database', () => { + describe('handleDOMException', () => { + it('handles null, still calls reject', () => { + let called = 0; + const reject = () => { called += 1; }; - var error = null; - var prefix = 'something'; + const error = null; + const prefix = 'something'; Whisper.Database.handleDOMException(prefix, error, reject); assert.strictEqual(called, 1); }); - it('handles object code and message', function() { - var called = 0; - var reject = function() { + it('handles object code and message', () => { + let called = 0; + const reject = () => { called += 1; }; - var error = { + const error = { code: 4, message: 'some cryptic error', }; - var prefix = 'something'; + const prefix = 'something'; Whisper.Database.handleDOMException(prefix, error, reject); diff --git a/test/fixtures.js b/test/fixtures.js index 832f01332..4ec2c496a 100644 --- a/test/fixtures.js +++ b/test/fixtures.js @@ -1,12 +1,14 @@ -Whisper.Fixtures = function() { - var VERA_ID = '+13016886524'; // nsa - var NESTOR_ID = '+17034820623'; // cia - var MASHA_ID = '+441242221491'; // gchq - var FRED_ID = '+14155537400'; // fbi sf - var MICHEL_ID = '+12024561111'; // twh +/* global Whisper */ - var now = Date.now(); - var conversationCollection = new Whisper.ConversationCollection([ +Whisper.Fixtures = () => { + const VERA_ID = '+13016886524'; // nsa + const NESTOR_ID = '+17034820623'; // cia + const MASHA_ID = '+441242221491'; // gchq + const FRED_ID = '+14155537400'; // fbi sf + const MICHEL_ID = '+12024561111'; // twh + + const now = Date.now(); + const conversationCollection = new Whisper.ConversationCollection([ { name: 'Vera Zasulich', id: VERA_ID, @@ -51,7 +53,7 @@ Whisper.Fixtures = function() { }, ]); - var Vera = conversationCollection.get(VERA_ID); + const Vera = conversationCollection.get(VERA_ID); Vera.messageCollection.add([ { conversationId: VERA_ID, @@ -62,7 +64,7 @@ Whisper.Fixtures = function() { }, ]); - var Nestor = conversationCollection.get(NESTOR_ID); + const Nestor = conversationCollection.get(NESTOR_ID); Nestor.messageCollection.add([ { conversationId: NESTOR_ID, @@ -73,7 +75,7 @@ Whisper.Fixtures = function() { }, ]); - var Fred = conversationCollection.get(FRED_ID); + const Fred = conversationCollection.get(FRED_ID); Fred.messageCollection.add([ { conversationId: FRED_ID, @@ -85,7 +87,7 @@ Whisper.Fixtures = function() { }, ]); - var Michel = conversationCollection.get(MICHEL_ID); + const Michel = conversationCollection.get(MICHEL_ID); Michel.messageCollection.add([ { conversationId: MICHEL_ID, @@ -118,7 +120,7 @@ Whisper.Fixtures = function() { }, ]); - var Masha = conversationCollection.get(MASHA_ID); + const Masha = conversationCollection.get(MASHA_ID); Masha.messageCollection.add( [ { @@ -150,7 +152,7 @@ Whisper.Fixtures = function() { body: "I can't wait to try it!", unread: 1, }, - ].map(function(m) { + ].map((m) => { return { conversationId: MASHA_ID, type: m.type, @@ -165,7 +167,7 @@ Whisper.Fixtures = function() { }) ); - var group = conversationCollection.add({ + const group = conversationCollection.add({ name: '📖 Book Club', type: 'group', active_at: now - 100000, @@ -210,7 +212,7 @@ Whisper.Fixtures = function() { delivered_to: [MICHEL_ID, FRED_ID], sent_to: [NESTOR_ID], }, - ].map(function(m) { + ].map((m) => { return Object.assign({}, m, { conversationId: group.id, sent_at: m.date, @@ -221,16 +223,16 @@ Whisper.Fixtures = function() { ); function dataURItoBlob(dataURI) { - var binary = atob(dataURI.split(',')[1]); - var array = []; - for (var i = 0; i < binary.length; i++) { + const binary = atob(dataURI.split(',')[1]); + const array = []; + for (let i = 0; i < binary.length; i += 1) { array.push(binary.charCodeAt(i)); } return new Uint8Array(array).buffer; } - conversationCollection.saveAll = function() { - return Promise.all( + conversationCollection.saveAll = function thisNeeded() { + Promise.all( this.map(async (convo) => { await window.Signal.Data.saveConversation(convo.attributes, { Conversation: Whisper.Conversation, @@ -239,7 +241,7 @@ Whisper.Fixtures = function() { await Promise.all( convo.messageCollection.map(async (message) => { const id = await window.Signal.Data.saveMessage(message.attributes, { - Message: Whisper.Message + Message: Whisper.Message, }); message.set({ id }); }) diff --git a/test/fixtures_test.js b/test/fixtures_test.js index 15399b108..e4e6ac8d2 100644 --- a/test/fixtures_test.js +++ b/test/fixtures_test.js @@ -1,11 +1,11 @@ +/* global $, ConversationController, textsecure, Whisper */ + 'use strict'; -describe('Fixtures', function() { - before(async function() { +describe('Fixtures', () => { + before(async () => { // NetworkStatusView checks this method every five seconds while showing - window.getSocketStatus = function() { - return WebSocket.OPEN; - }; + window.getSocketStatus = () => WebSocket.OPEN; await clearDatabase(); await textsecure.storage.user.setNumberAndDeviceId( @@ -26,11 +26,11 @@ describe('Fixtures', function() { ConversationController.reset(); await ConversationController.load(); - var view = new Whisper.InboxView({ window: window }); + let view = new Whisper.InboxView({ window }); view.onEmpty(); view.$el.prependTo($('#render-light-theme')); - var view = new Whisper.InboxView({ window: window }); + view = new Whisper.InboxView({ window }); view.$el.removeClass('light-theme').addClass('dark-theme'); view.onEmpty(); view.$el.prependTo($('#render-dark-theme')); diff --git a/test/i18n_test.js b/test/i18n_test.js index 16e7c0fdd..8530b8cbf 100644 --- a/test/i18n_test.js +++ b/test/i18n_test.js @@ -1,16 +1,18 @@ -describe('i18n', function() { - describe('i18n', function() { - it('returns empty string for unknown string', function() { +/* global i18n */ + +describe('i18n', () => { + describe('i18n', () => { + it('returns empty string for unknown string', () => { assert.strictEqual(i18n('random'), ''); }); - it('returns message for given string', function() { + it('returns message for given string', () => { assert.equal(i18n('reportIssue'), 'Report an issue'); }); - it('returns message with single substitution', function() { + it('returns message with single substitution', () => { const actual = i18n('attemptingReconnection', 5); assert.equal(actual, 'Attempting reconnect in 5 seconds'); }); - it('returns message with multiple substitutions', function() { + it('returns message with multiple substitutions', () => { const actual = i18n('theyChangedTheTimer', ['Someone', '5 minutes']); assert.equal( actual, @@ -19,8 +21,8 @@ describe('i18n', function() { }); }); - describe('getLocale', function() { - it('returns a string with length two or greater', function() { + describe('getLocale', () => { + it('returns a string with length two or greater', () => { const locale = i18n.getLocale(); assert.isAtLeast(locale.trim().length, 2); }); diff --git a/test/keychange_listener_test.js b/test/keychange_listener_test.js index f37e9fa3e..08da00bf2 100644 --- a/test/keychange_listener_test.js +++ b/test/keychange_listener_test.js @@ -1,26 +1,28 @@ -describe('KeyChangeListener', function() { - var phoneNumberWithKeyChange = '+13016886524'; // nsa - var address = new libsignal.SignalProtocolAddress( +/* global ConversationController, libsignal, SignalProtocolStore, Whisper */ + +describe('KeyChangeListener', () => { + const phoneNumberWithKeyChange = '+13016886524'; // nsa + const address = new libsignal.SignalProtocolAddress( phoneNumberWithKeyChange, 1 ); - var oldKey = libsignal.crypto.getRandomBytes(33); - var newKey = libsignal.crypto.getRandomBytes(33); - var store; + const oldKey = libsignal.crypto.getRandomBytes(33); + const newKey = libsignal.crypto.getRandomBytes(33); + let store; - beforeEach(function() { + beforeEach(() => { store = new SignalProtocolStore(); Whisper.KeyChangeListener.init(store); return store.saveIdentity(address.toString(), oldKey); }); - afterEach(function() { + afterEach(() => { return store.removeIdentityKey(phoneNumberWithKeyChange); }); - describe('When we have a conversation with this contact', function() { + describe('When we have a conversation with this contact', () => { let convo; - before(async function() { + before(async () => { convo = ConversationController.dangerouslyCreateAndAdd({ id: phoneNumberWithKeyChange, type: 'private', @@ -30,12 +32,12 @@ describe('KeyChangeListener', function() { }); }); - after(async function() { + after(async () => { await convo.destroyMessages(); await window.Signal.Data.saveConversation(convo.id); }); - it('generates a key change notice in the private conversation with this contact', function(done) { + it('generates a key change notice in the private conversation with this contact', done => { convo.once('newmessage', async () => { await convo.fetchMessages(); const message = convo.messageCollection.at(0); @@ -46,10 +48,9 @@ describe('KeyChangeListener', function() { }); }); - describe('When we have a group with this contact', function() { + describe('When we have a group with this contact', () => { let convo; - before(async function() { - console.log('Creating group with contact', phoneNumberWithKeyChange); + before(async () => { convo = ConversationController.dangerouslyCreateAndAdd({ id: 'groupId', type: 'group', @@ -59,12 +60,12 @@ describe('KeyChangeListener', function() { Conversation: Whisper.Conversation, }); }); - after(async function() { + after(async () => { await convo.destroyMessages(); await window.Signal.Data.saveConversation(convo.id); }); - it('generates a key change notice in the group conversation with this contact', function(done) { + it('generates a key change notice in the group conversation with this contact', done => { convo.once('newmessage', async () => { await convo.fetchMessages(); const message = convo.messageCollection.at(0); diff --git a/test/libphonenumber_util_test.js b/test/libphonenumber_util_test.js index bd6cd631f..0e478e4eb 100644 --- a/test/libphonenumber_util_test.js +++ b/test/libphonenumber_util_test.js @@ -1,25 +1,26 @@ -(function() { - 'use strict'; - describe('libphonenumber util', function() { - describe('parseNumber', function() { - it('numbers with + are valid without providing regionCode', function() { - var result = libphonenumber.util.parseNumber('+14155555555'); +/* global libphonenumber */ + +'use strict'; + +describe('libphonenumber util', () => { + describe('parseNumber', () => { + it('numbers with + are valid without providing regionCode', () => { + const result = libphonenumber.util.parseNumber('+14155555555'); + assert.isTrue(result.isValidNumber); + assert.strictEqual(result.nationalNumber, '4155555555'); + assert.strictEqual(result.e164, '+14155555555'); + assert.strictEqual(result.regionCode, 'US'); + assert.strictEqual(result.countryCode, '1'); + }); + it('variant numbers with the right regionCode are valid', () => { + ['4155555555', '14155555555', '+14155555555'].forEach(number => { + const result = libphonenumber.util.parseNumber(number, 'US'); assert.isTrue(result.isValidNumber); assert.strictEqual(result.nationalNumber, '4155555555'); assert.strictEqual(result.e164, '+14155555555'); assert.strictEqual(result.regionCode, 'US'); assert.strictEqual(result.countryCode, '1'); }); - it('variant numbers with the right regionCode are valid', function() { - ['4155555555', '14155555555', '+14155555555'].forEach(function(number) { - var result = libphonenumber.util.parseNumber(number, 'US'); - assert.isTrue(result.isValidNumber); - assert.strictEqual(result.nationalNumber, '4155555555'); - assert.strictEqual(result.e164, '+14155555555'); - assert.strictEqual(result.regionCode, 'US'); - assert.strictEqual(result.countryCode, '1'); - }); - }); }); }); -})(); +}); diff --git a/test/models/conversations_test.js b/test/models/conversations_test.js index 1b27ae032..0292ef24d 100644 --- a/test/models/conversations_test.js +++ b/test/models/conversations_test.js @@ -1,226 +1,213 @@ -(function() { - 'use strict'; - var attributes = { - type: 'outgoing', - body: 'hi', - conversationId: 'foo', - attachments: [], - timestamp: new Date().getTime(), - }; - var conversation_attributes = { - type: 'private', - id: '+14155555555', - }; +/* global storage, textsecure, Whisper */ + +'use strict'; + +describe('ConversationCollection', () => { textsecure.messaging = new textsecure.MessageSender(''); - describe('ConversationCollection', function() { - before(clearDatabase); - after(clearDatabase); + before(clearDatabase); + after(clearDatabase); - it('should be ordered newest to oldest', function() { - var conversations = new Whisper.ConversationCollection(); - // Timestamps - var today = new Date(); - var tomorrow = new Date(); - tomorrow.setDate(today.getDate() + 1); + it('should be ordered newest to oldest', () => { + const conversations = new Whisper.ConversationCollection(); + // Timestamps + const today = new Date(); + const tomorrow = new Date(); + tomorrow.setDate(today.getDate() + 1); - // Add convos - conversations.add({ timestamp: today }); - conversations.add({ timestamp: tomorrow }); + // Add convos + conversations.add({ timestamp: today }); + conversations.add({ timestamp: tomorrow }); - var models = conversations.models; - var firstTimestamp = models[0].get('timestamp').getTime(); - var secondTimestamp = models[1].get('timestamp').getTime(); + const { models } = conversations; + const firstTimestamp = models[0].get('timestamp').getTime(); + const secondTimestamp = models[1].get('timestamp').getTime(); - // Compare timestamps - assert(firstTimestamp > secondTimestamp); + // Compare timestamps + assert(firstTimestamp > secondTimestamp); + }); +}); + +describe('Conversation', () => { + const attributes = { type: 'private', id: '+18085555555' }; + before(async () => { + const convo = new Whisper.ConversationCollection().add(attributes); + await window.Signal.Data.saveConversation(convo.attributes, { + Conversation: Whisper.Conversation, + }); + + const message = convo.messageCollection.add({ + body: 'hello world', + conversationId: convo.id, + type: 'outgoing', + sent_at: Date.now(), + received_at: Date.now(), + }); + await window.Signal.Data.saveMessage(message.attributes, { + Message: Whisper.Message, }); }); + after(clearDatabase); - describe('Conversation', function() { - var attributes = { type: 'private', id: '+18085555555' }; - before(async () => { - var convo = new Whisper.ConversationCollection().add(attributes); - await window.Signal.Data.saveConversation(convo.attributes, { - Conversation: Whisper.Conversation, - }); + it('sorts its contacts in an intl-friendly way', () => { + const convo = new Whisper.Conversation({ id: '+18085555555' }); + convo.contactCollection.add( + new Whisper.Conversation({ + name: 'C', + }) + ); + convo.contactCollection.add( + new Whisper.Conversation({ + name: 'B', + }) + ); + convo.contactCollection.add( + new Whisper.Conversation({ + name: 'Á', + }) + ); - var message = convo.messageCollection.add({ - body: 'hello world', - conversationId: convo.id, - type: 'outgoing', - sent_at: Date.now(), - received_at: Date.now(), - }); - await window.Signal.Data.saveMessage(message.attributes, { - Message: Whisper.Message, - }); - }); - after(clearDatabase); - - it('sorts its contacts in an intl-friendly way', function() { - var convo = new Whisper.Conversation({ id: '+18085555555' }); - convo.contactCollection.add( - new Whisper.Conversation({ - name: 'C', - }) - ); - convo.contactCollection.add( - new Whisper.Conversation({ - name: 'B', - }) - ); - convo.contactCollection.add( - new Whisper.Conversation({ - name: 'Á', - }) - ); - - assert.strictEqual(convo.contactCollection.at('0').get('name'), 'Á'); - assert.strictEqual(convo.contactCollection.at('1').get('name'), 'B'); - assert.strictEqual(convo.contactCollection.at('2').get('name'), 'C'); - }); - - it('contains its own messages', async function() { - var convo = new Whisper.ConversationCollection().add({ - id: '+18085555555', - }); - await convo.fetchMessages(); - assert.notEqual(convo.messageCollection.length, 0); - }); - - it('contains only its own messages', async function() { - var convo = new Whisper.ConversationCollection().add({ - id: '+18085556666', - }); - await convo.fetchMessages(); - assert.strictEqual(convo.messageCollection.length, 0); - }); - - it('adds conversation to message collection upon leaving group', async function() { - var convo = new Whisper.ConversationCollection().add({ - type: 'group', - id: 'a random string', - }); - await convo.leaveGroup(); - assert.notEqual(convo.messageCollection.length, 0); - }); - - it('has a title', function() { - var convos = new Whisper.ConversationCollection(); - var convo = convos.add(attributes); - assert.equal(convo.getTitle(), '+1 808-555-5555'); - - convo = convos.add({ type: '' }); - assert.equal(convo.getTitle(), 'Unknown group'); - - convo = convos.add({ name: 'name' }); - assert.equal(convo.getTitle(), 'name'); - }); - - it('returns the number', function() { - var convos = new Whisper.ConversationCollection(); - var convo = convos.add(attributes); - assert.equal(convo.getNumber(), '+1 808-555-5555'); - - convo = convos.add({ type: '' }); - assert.equal(convo.getNumber(), ''); - }); - - it('has an avatar', function() { - var convo = new Whisper.ConversationCollection().add(attributes); - var avatar = convo.getAvatar(); - assert.property(avatar, 'content'); - assert.property(avatar, 'color'); - }); - - describe('phone number parsing', function() { - after(function() { - storage.remove('regionCode'); - }); - function checkAttributes(number) { - var convo = new Whisper.ConversationCollection().add({ - type: 'private', - }); - convo.set('id', number); - convo.validate(convo.attributes); - assert.strictEqual(convo.get('id'), '+14155555555', number); - } - it('processes the phone number when validating', function() { - ['+14155555555'].forEach(checkAttributes); - }); - it('defaults to the local regionCode', function() { - storage.put('regionCode', 'US'); - ['14155555555', '4155555555'].forEach(checkAttributes); - }); - it('works with common phone number formats', function() { - storage.put('regionCode', 'US'); - [ - '415 555 5555', - '415-555-5555', - '(415) 555 5555', - '(415) 555-5555', - '1 415 555 5555', - '1 415-555-5555', - '1 (415) 555 5555', - '1 (415) 555-5555', - '+1 415 555 5555', - '+1 415-555-5555', - '+1 (415) 555 5555', - '+1 (415) 555-5555', - ].forEach(checkAttributes); - }); - }); + assert.strictEqual(convo.contactCollection.at('0').get('name'), 'Á'); + assert.strictEqual(convo.contactCollection.at('1').get('name'), 'B'); + assert.strictEqual(convo.contactCollection.at('2').get('name'), 'C'); }); - describe('Conversation search', function() { - let convo; + it('contains its own messages', async () => { + const convo = new Whisper.ConversationCollection().add({ + id: '+18085555555', + }); + await convo.fetchMessages(); + assert.notEqual(convo.messageCollection.length, 0); + }); - beforeEach(async function() { - convo = new Whisper.ConversationCollection().add({ - id: '+14155555555', + it('contains only its own messages', async () => { + const convo = new Whisper.ConversationCollection().add({ + id: '+18085556666', + }); + await convo.fetchMessages(); + assert.strictEqual(convo.messageCollection.length, 0); + }); + + it('adds conversation to message collection upon leaving group', async () => { + const convo = new Whisper.ConversationCollection().add({ + type: 'group', + id: 'a random string', + }); + await convo.leaveGroup(); + assert.notEqual(convo.messageCollection.length, 0); + }); + + it('has a title', () => { + const convos = new Whisper.ConversationCollection(); + let convo = convos.add(attributes); + assert.equal(convo.getTitle(), '+1 808-555-5555'); + + convo = convos.add({ type: '' }); + assert.equal(convo.getTitle(), 'Unknown group'); + + convo = convos.add({ name: 'name' }); + assert.equal(convo.getTitle(), 'name'); + }); + + it('returns the number', () => { + const convos = new Whisper.ConversationCollection(); + let convo = convos.add(attributes); + assert.equal(convo.getNumber(), '+1 808-555-5555'); + + convo = convos.add({ type: '' }); + assert.equal(convo.getNumber(), ''); + }); + + it('has an avatar', () => { + const convo = new Whisper.ConversationCollection().add(attributes); + const avatar = convo.getAvatar(); + assert.property(avatar, 'content'); + assert.property(avatar, 'color'); + }); + + describe('phone number parsing', () => { + after(() => { + storage.remove('regionCode'); + }); + function checkAttributes(number) { + const convo = new Whisper.ConversationCollection().add({ type: 'private', - name: 'John Doe', }); - await window.Signal.Data.saveConversation(convo.attributes, { - Conversation: Whisper.Conversation, - }); - }); - - afterEach(clearDatabase); - - async function testSearch(queries) { - await Promise.all( - queries.map(async function(query) { - var collection = new Whisper.ConversationCollection(); - await collection.search(query); - - assert.isDefined( - collection.get(convo.id), - 'no result for "' + query + '"' - ); - }) - ); + convo.set('id', number); + convo.validate(convo.attributes); + assert.strictEqual(convo.get('id'), '+14155555555', number); } - it('matches by partial phone number', function() { - return testSearch([ - '1', - '4', - '+1', - '415', - '4155', - '4155555555', - '14155555555', - '+14155555555', - ]); + it('processes the phone number when validating', () => { + ['+14155555555'].forEach(checkAttributes); }); - it('matches by name', function() { - return testSearch(['John', 'Doe', 'john', 'doe', 'John Doe', 'john doe']); + it('defaults to the local regionCode', () => { + storage.put('regionCode', 'US'); + ['14155555555', '4155555555'].forEach(checkAttributes); }); - it('does not match +', async function() { - var collection = new Whisper.ConversationCollection(); - await collection.search('+'); - assert.isUndefined(collection.get(convo.id), 'got result for "+"'); + it('works with common phone number formats', () => { + storage.put('regionCode', 'US'); + [ + '415 555 5555', + '415-555-5555', + '(415) 555 5555', + '(415) 555-5555', + '1 415 555 5555', + '1 415-555-5555', + '1 (415) 555 5555', + '1 (415) 555-5555', + '+1 415 555 5555', + '+1 415-555-5555', + '+1 (415) 555 5555', + '+1 (415) 555-5555', + ].forEach(checkAttributes); }); }); -})(); +}); + +describe('Conversation search', () => { + let convo; + + beforeEach(async () => { + convo = new Whisper.ConversationCollection().add({ + id: '+14155555555', + type: 'private', + name: 'John Doe', + }); + await window.Signal.Data.saveConversation(convo.attributes, { + Conversation: Whisper.Conversation, + }); + }); + + afterEach(clearDatabase); + + async function testSearch(queries) { + await Promise.all( + queries.map(async query => { + const collection = new Whisper.ConversationCollection(); + await collection.search(query); + + assert.isDefined(collection.get(convo.id), `no result for "${query}"`); + }) + ); + } + it('matches by partial phone number', () => { + return testSearch([ + '1', + '4', + '+1', + '415', + '4155', + '4155555555', + '14155555555', + '+14155555555', + ]); + }); + it('matches by name', () => { + return testSearch(['John', 'Doe', 'john', 'doe', 'John Doe', 'john doe']); + }); + it('does not match +', async () => { + const collection = new Whisper.ConversationCollection(); + await collection.search('+'); + assert.isUndefined(collection.get(convo.id), 'got result for "+"'); + }); +}); diff --git a/test/models/messages_test.js b/test/models/messages_test.js index 67066c8e0..70efb2708 100644 --- a/test/models/messages_test.js +++ b/test/models/messages_test.js @@ -1,159 +1,145 @@ -(function() { - 'use strict'; +/* global ConversationController, i18n, Whisper */ - var attributes = { - type: 'outgoing', - body: 'hi', - conversationId: 'foo', - attachments: [], - received_at: new Date().getTime(), - }; +'use strict'; - var attachment = { - data: 'datasaurus', - contentType: 'plain/text', - }; +const attributes = { + type: 'outgoing', + body: 'hi', + conversationId: 'foo', + attachments: [], + received_at: new Date().getTime(), +}; - var source = '+14155555555'; +const source = '+14155555555'; - describe('MessageCollection', function() { - before(async function() { - await clearDatabase(); - ConversationController.reset(); - await ConversationController.load(); - }); - after(function() { - return clearDatabase(); - }); - - it('gets outgoing contact', function() { - var messages = new Whisper.MessageCollection(); - var message = messages.add(attributes); - message.getContact(); - }); - - it('gets incoming contact', function() { - var messages = new Whisper.MessageCollection(); - var message = messages.add({ - type: 'incoming', - source: source, - }); - message.getContact(); - }); - - it('adds without saving', function() { - var messages = new Whisper.MessageCollection(); - var message = messages.add(attributes); - assert.notEqual(messages.length, 0); - - var messages = new Whisper.MessageCollection(); - assert.strictEqual(messages.length, 0); - }); - - it('should be ordered oldest to newest', function() { - var messages = new Whisper.MessageCollection(); - // Timestamps - var today = new Date(); - var tomorrow = new Date(); - tomorrow.setDate(today.getDate() + 1); - - // Add threads - messages.add({ received_at: today }); - messages.add({ received_at: tomorrow }); - - var models = messages.models; - var firstTimestamp = models[0].get('received_at').getTime(); - var secondTimestamp = models[1].get('received_at').getTime(); - - // Compare timestamps - assert(firstTimestamp < secondTimestamp); - }); - - it('checks if is incoming message', function() { - var messages = new Whisper.MessageCollection(); - var message = messages.add(attributes); - assert.notOk(message.isIncoming()); - message = messages.add({ type: 'incoming' }); - assert.ok(message.isIncoming()); - }); - - it('checks if is outgoing message', function() { - var messages = new Whisper.MessageCollection(); - var message = messages.add(attributes); - assert.ok(message.isOutgoing()); - message = messages.add({ type: 'incoming' }); - assert.notOk(message.isOutgoing()); - }); - - it('checks if is group update', function() { - var messages = new Whisper.MessageCollection(); - var message = messages.add(attributes); - assert.notOk(message.isGroupUpdate()); - - message = messages.add({ group_update: true }); - assert.ok(message.isGroupUpdate()); - }); - - it('returns an accurate description', function() { - var messages = new Whisper.MessageCollection(); - var message = messages.add(attributes); - - assert.equal( - message.getDescription(), - 'hi', - 'If no group updates or end session flags, return message body.' - ); - - message = messages.add({ group_update: { left: 'Alice' } }); - assert.equal( - message.getDescription(), - 'Alice left the group', - 'Notes one person leaving the group.' - ); - - message = messages.add({ group_update: { name: 'blerg' } }); - assert.equal( - message.getDescription(), - "Title is now 'blerg'", - 'Returns a single notice if only group_updates.name changes.' - ); - - message = messages.add({ group_update: { joined: ['Bob'] } }); - assert.equal( - message.getDescription(), - 'Bob joined the group', - 'Returns a single notice if only group_updates.joined changes.' - ); - - message = messages.add({ - group_update: { joined: ['Bob', 'Alice', 'Eve'] }, - }); - assert.equal( - message.getDescription(), - 'Bob, Alice, Eve joined the group', - 'Notes when >1 person joins the group.' - ); - - message = messages.add({ - group_update: { joined: ['Bob'], name: 'blerg' }, - }); - assert.equal( - message.getDescription(), - "Title is now 'blerg', Bob joined the group", - 'Notes when there are multiple changes to group_updates properties.' - ); - - message = messages.add({ flags: true }); - assert.equal(message.getDescription(), i18n('sessionEnded')); - }); - - it('checks if it is end of the session', function() { - var messages = new Whisper.MessageCollection(); - var message = messages.add(attributes); - assert.notOk(message.isEndSession()); - - message = messages.add({ flags: true }); - assert.ok(message.isEndSession()); - }); +describe('MessageCollection', () => { + before(async () => { + await clearDatabase(); + ConversationController.reset(); + await ConversationController.load(); }); -})(); + after(() => { + return clearDatabase(); + }); + + it('gets outgoing contact', () => { + const messages = new Whisper.MessageCollection(); + const message = messages.add(attributes); + message.getContact(); + }); + + it('gets incoming contact', () => { + const messages = new Whisper.MessageCollection(); + const message = messages.add({ + type: 'incoming', + source, + }); + message.getContact(); + }); + + it('should be ordered oldest to newest', () => { + const messages = new Whisper.MessageCollection(); + // Timestamps + const today = new Date(); + const tomorrow = new Date(); + tomorrow.setDate(today.getDate() + 1); + + // Add threads + messages.add({ received_at: today }); + messages.add({ received_at: tomorrow }); + + const { models } = messages; + const firstTimestamp = models[0].get('received_at').getTime(); + const secondTimestamp = models[1].get('received_at').getTime(); + + // Compare timestamps + assert(firstTimestamp < secondTimestamp); + }); + + it('checks if is incoming message', () => { + const messages = new Whisper.MessageCollection(); + let message = messages.add(attributes); + assert.notOk(message.isIncoming()); + message = messages.add({ type: 'incoming' }); + assert.ok(message.isIncoming()); + }); + + it('checks if is outgoing message', () => { + const messages = new Whisper.MessageCollection(); + let message = messages.add(attributes); + assert.ok(message.isOutgoing()); + message = messages.add({ type: 'incoming' }); + assert.notOk(message.isOutgoing()); + }); + + it('checks if is group update', () => { + const messages = new Whisper.MessageCollection(); + let message = messages.add(attributes); + assert.notOk(message.isGroupUpdate()); + + message = messages.add({ group_update: true }); + assert.ok(message.isGroupUpdate()); + }); + + it('returns an accurate description', () => { + const messages = new Whisper.MessageCollection(); + let message = messages.add(attributes); + + assert.equal( + message.getDescription(), + 'hi', + 'If no group updates or end session flags, return message body.' + ); + + message = messages.add({ group_update: { left: 'Alice' } }); + assert.equal( + message.getDescription(), + 'Alice left the group', + 'Notes one person leaving the group.' + ); + + message = messages.add({ group_update: { name: 'blerg' } }); + assert.equal( + message.getDescription(), + "Title is now 'blerg'", + 'Returns a single notice if only group_updates.name changes.' + ); + + message = messages.add({ group_update: { joined: ['Bob'] } }); + assert.equal( + message.getDescription(), + 'Bob joined the group', + 'Returns a single notice if only group_updates.joined changes.' + ); + + message = messages.add({ + group_update: { joined: ['Bob', 'Alice', 'Eve'] }, + }); + assert.equal( + message.getDescription(), + 'Bob, Alice, Eve joined the group', + 'Notes when >1 person joins the group.' + ); + + message = messages.add({ + group_update: { joined: ['Bob'], name: 'blerg' }, + }); + assert.equal( + message.getDescription(), + "Title is now 'blerg', Bob joined the group", + 'Notes when there are multiple changes to group_updates properties.' + ); + + message = messages.add({ flags: true }); + assert.equal(message.getDescription(), i18n('sessionEnded')); + }); + + it('checks if it is end of the session', () => { + const messages = new Whisper.MessageCollection(); + let message = messages.add(attributes); + assert.notOk(message.isEndSession()); + + message = messages.add({ flags: true }); + assert.ok(message.isEndSession()); + }); +}); diff --git a/test/reliable_trigger_test.js b/test/reliable_trigger_test.js index 469346f95..99bceadf2 100644 --- a/test/reliable_trigger_test.js +++ b/test/reliable_trigger_test.js @@ -1,28 +1,32 @@ +/* global Backbone */ + 'use strict'; -describe('ReliableTrigger', function() { - describe('trigger', function() { - var Model, model; +describe('ReliableTrigger', () => { + describe('trigger', () => { + let Model; + let model; - before(function() { - Model = Backbone.Model; + before(() => { + ({ Model } = Backbone); }); - beforeEach(function() { + beforeEach(() => { model = new Model(); }); - it('returns successfully if this._events is falsey', function() { + it('returns successfully if this._events is falsey', () => { model._events = null; model.trigger('click'); }); - it('handles map of events to trigger', function() { - var a = 0, - b = 0; - model.on('a', function(arg) { + it('handles map of events to trigger', () => { + let a = 0; + let b = 0; + + model.on('a', arg => { a = arg; }); - model.on('b', function(arg) { + model.on('b', arg => { b = arg; }); @@ -34,13 +38,14 @@ describe('ReliableTrigger', function() { assert.strictEqual(a, 1); assert.strictEqual(b, 2); }); - it('handles space-separated list of events to trigger', function() { - var a = false, - b = false; - model.on('a', function() { + it('handles space-separated list of events to trigger', () => { + let a = false; + let b = false; + + model.on('a', () => { a = true; }); - model.on('b', function() { + model.on('b', () => { b = true; }); @@ -49,9 +54,9 @@ describe('ReliableTrigger', function() { assert.strictEqual(a, true); assert.strictEqual(b, true); }); - it('calls all clients registered for "all" event', function() { - var count = 0; - model.on('all', function() { + it('calls all clients registered for "all" event', () => { + let count = 0; + model.on('all', () => { count += 1; }); @@ -60,13 +65,14 @@ describe('ReliableTrigger', function() { assert.strictEqual(count, 2); }); - it('calls all clients registered for target event', function() { - var a = false, - b = false; - model.on('event', function() { + it('calls all clients registered for target event', () => { + let a = false; + let b = false; + + model.on('event', () => { a = true; }); - model.on('event', function() { + model.on('event', () => { b = true; }); @@ -75,14 +81,15 @@ describe('ReliableTrigger', function() { assert.strictEqual(a, true); assert.strictEqual(b, true); }); - it('successfully returns and calls all clients even if first failed', function() { - var a = false, - b = false; - model.on('event', function() { + it('successfully returns and calls all clients even if first failed', () => { + let a = false; + let b = false; + + model.on('event', () => { a = true; throw new Error('a is set, but exception is thrown'); }); - model.on('event', function() { + model.on('event', () => { b = true; }); @@ -91,9 +98,9 @@ describe('ReliableTrigger', function() { assert.strictEqual(a, true); assert.strictEqual(b, true); }); - it('calls clients with no args', function() { - var called = false; - model.on('event', function() { + it('calls clients with no args', () => { + let called = false; + model.on('event', () => { called = true; }); @@ -101,20 +108,20 @@ describe('ReliableTrigger', function() { assert.strictEqual(called, true); }); - it('calls clients with 1 arg', function() { - var args; - model.on('event', function() { - args = arguments; + it('calls clients with 1 arg', () => { + let args; + model.on('event', (...eventArgs) => { + args = eventArgs; }); model.trigger('event', 1); assert.strictEqual(args[0], 1); }); - it('calls clients with 2 args', function() { - var args; - model.on('event', function() { - args = arguments; + it('calls clients with 2 args', () => { + let args; + model.on('event', (...eventArgs) => { + args = eventArgs; }); model.trigger('event', 1, 2); @@ -122,10 +129,10 @@ describe('ReliableTrigger', function() { assert.strictEqual(args[0], 1); assert.strictEqual(args[1], 2); }); - it('calls clients with 3 args', function() { - var args; - model.on('event', function() { - args = arguments; + it('calls clients with 3 args', () => { + let args; + model.on('event', (...eventArgs) => { + args = eventArgs; }); model.trigger('event', 1, 2, 3); @@ -134,10 +141,10 @@ describe('ReliableTrigger', function() { assert.strictEqual(args[1], 2); assert.strictEqual(args[2], 3); }); - it('calls clients with 4+ args', function() { - var args; - model.on('event', function() { - args = arguments; + it('calls clients with 4+ args', () => { + let args; + model.on('event', (...eventArgs) => { + args = eventArgs; }); model.trigger('event', 1, 2, 3, 4); diff --git a/test/spellcheck_test.js b/test/spellcheck_test.js index 21c145975..57f7b529f 100644 --- a/test/spellcheck_test.js +++ b/test/spellcheck_test.js @@ -1,5 +1,5 @@ -describe('spellChecker', function() { - it('should work', function() { +describe('spellChecker', () => { + it('should work', () => { assert(window.spellChecker.spellCheck('correct')); assert(!window.spellChecker.spellCheck('fhqwgads')); }); diff --git a/test/storage_test.js b/test/storage_test.js index dfd866d54..ab4f847cf 100644 --- a/test/storage_test.js +++ b/test/storage_test.js @@ -1,18 +1,14 @@ +/* global _, textsecure, libsignal, storage */ + 'use strict'; -describe('SignalProtocolStore', function() { - var number = '+5558675309'; - var store; - var identityKey; - var testKey; +describe('SignalProtocolStore', () => { + const number = '+5558675309'; + let store; + let identityKey; + let testKey; - function wrapDeferred(deferred) { - return new Promise(function(resolve, reject) { - return deferred.then(resolve, reject); - }); - } - - before(function(done) { + before(done => { store = textsecure.storage.protocol; identityKey = { pubKey: libsignal.crypto.getRandomBytes(33), @@ -28,59 +24,59 @@ describe('SignalProtocolStore', function() { storage.fetch().then(done, done); }); - describe('getLocalRegistrationId', function() { - it('retrieves my registration id', async function() { + describe('getLocalRegistrationId', () => { + it('retrieves my registration id', async () => { const id = await store.getLocalRegistrationId(); assert.strictEqual(id, 1337); }); }); - describe('getIdentityKeyPair', function() { - it('retrieves my identity key', async function() { + describe('getIdentityKeyPair', () => { + it('retrieves my identity key', async () => { const key = await store.getIdentityKeyPair(); assertEqualArrayBuffers(key.pubKey, identityKey.pubKey); assertEqualArrayBuffers(key.privKey, identityKey.privKey); }); }); - describe('saveIdentity', function() { - var address = new libsignal.SignalProtocolAddress(number, 1); - var identifier = address.toString(); + describe('saveIdentity', () => { + const address = new libsignal.SignalProtocolAddress(number, 1); + const identifier = address.toString(); - it('stores identity keys', async function() { + it('stores identity keys', async () => { await store.saveIdentity(identifier, testKey.pubKey); const key = await store.loadIdentityKey(number); assertEqualArrayBuffers(key, testKey.pubKey); }); - it('allows key changes', async function() { - var newIdentity = libsignal.crypto.getRandomBytes(33); + it('allows key changes', async () => { + const newIdentity = libsignal.crypto.getRandomBytes(33); await store.saveIdentity(identifier, testKey.pubKey); await store.saveIdentity(identifier, newIdentity); }); - describe('When there is no existing key (first use)', function() { - before(async function() { + describe('When there is no existing key (first use)', () => { + before(async () => { await store.removeIdentityKey(number); await store.saveIdentity(identifier, testKey.pubKey); }); - it('marks the key firstUse', async function() { + it('marks the key firstUse', async () => { const identity = await window.Signal.Data.getIdentityKeyById(number); assert(identity.firstUse); }); - it('sets the timestamp', async function() { + it('sets the timestamp', async () => { const identity = await window.Signal.Data.getIdentityKeyById(number); assert(identity.timestamp); }); - it('sets the verified status to DEFAULT', async function() { + it('sets the verified status to DEFAULT', async () => { const identity = await window.Signal.Data.getIdentityKeyById(number); assert.strictEqual(identity.verified, store.VerifiedStatus.DEFAULT); }); }); - describe('When there is a different existing key (non first use)', function() { + describe('When there is a different existing key (non first use)', () => { const newIdentity = libsignal.crypto.getRandomBytes(33); const oldTimestamp = Date.now(); - before(async function() { + before(async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: identifier, publicKey: testKey.pubKey, @@ -92,17 +88,17 @@ describe('SignalProtocolStore', function() { await store.saveIdentity(identifier, newIdentity); }); - it('marks the key not firstUse', async function() { + it('marks the key not firstUse', async () => { const identity = await window.Signal.Data.getIdentityKeyById(number); assert(!identity.firstUse); }); - it('updates the timestamp', async function() { + it('updates the timestamp', async () => { const identity = await window.Signal.Data.getIdentityKeyById(number); assert.notEqual(identity.timestamp, oldTimestamp); }); - describe('The previous verified status was DEFAULT', function() { - before(async function() { + describe('The previous verified status was DEFAULT', () => { + before(async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -114,13 +110,13 @@ describe('SignalProtocolStore', function() { await store.saveIdentity(identifier, newIdentity); }); - it('sets the new key to default', async function() { + it('sets the new key to default', async () => { const identity = await window.Signal.Data.getIdentityKeyById(number); assert.strictEqual(identity.verified, store.VerifiedStatus.DEFAULT); }); }); - describe('The previous verified status was VERIFIED', function() { - before(async function() { + describe('The previous verified status was VERIFIED', () => { + before(async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -131,7 +127,7 @@ describe('SignalProtocolStore', function() { }); await store.saveIdentity(identifier, newIdentity); }); - it('sets the new key to unverified', async function() { + it('sets the new key to unverified', async () => { const identity = await window.Signal.Data.getIdentityKeyById(number); assert.strictEqual( @@ -140,8 +136,8 @@ describe('SignalProtocolStore', function() { ); }); }); - describe('The previous verified status was UNVERIFIED', function() { - before(async function() { + describe('The previous verified status was UNVERIFIED', () => { + before(async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -153,7 +149,7 @@ describe('SignalProtocolStore', function() { await store.saveIdentity(identifier, newIdentity); }); - it('sets the new key to unverified', async function() { + it('sets the new key to unverified', async () => { const identity = await window.Signal.Data.getIdentityKeyById(number); assert.strictEqual( identity.verified, @@ -162,9 +158,9 @@ describe('SignalProtocolStore', function() { }); }); }); - describe('When the key has not changed', function() { - var oldTimestamp = Date.now(); - before(async function() { + describe('When the key has not changed', () => { + const oldTimestamp = Date.now(); + before(async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -173,13 +169,13 @@ describe('SignalProtocolStore', function() { verified: store.VerifiedStatus.DEFAULT, }); }); - describe('If it is marked firstUse', function() { - before(async function() { + describe('If it is marked firstUse', () => { + before(async () => { const identity = await window.Signal.Data.getIdentityKeyById(number); identity.firstUse = true; await window.Signal.Data.createOrUpdateIdentityKey(identity); }); - it('nothing changes', async function() { + it('nothing changes', async () => { await store.saveIdentity(identifier, testKey.pubKey, true); const identity = await window.Signal.Data.getIdentityKeyById(number); @@ -187,15 +183,15 @@ describe('SignalProtocolStore', function() { assert.strictEqual(identity.timestamp, oldTimestamp); }); }); - describe('If it is not marked firstUse', function() { - before(async function() { + describe('If it is not marked firstUse', () => { + before(async () => { const identity = await window.Signal.Data.getIdentityKeyById(number); identity.firstUse = false; await window.Signal.Data.createOrUpdateIdentityKey(identity); }); - describe('If nonblocking approval is required', function() { + describe('If nonblocking approval is required', () => { let now; - before(async function() { + before(async () => { now = Date.now(); const identity = await window.Signal.Data.getIdentityKeyById( number @@ -203,7 +199,7 @@ describe('SignalProtocolStore', function() { identity.timestamp = now; await window.Signal.Data.createOrUpdateIdentityKey(identity); }); - it('sets non-blocking approval', async function() { + it('sets non-blocking approval', async () => { await store.saveIdentity(identifier, testKey.pubKey, true); const identity = await window.Signal.Data.getIdentityKeyById( @@ -218,11 +214,11 @@ describe('SignalProtocolStore', function() { }); }); }); - describe('saveIdentityWithAttributes', function() { - var now; - var validAttributes; + describe('saveIdentityWithAttributes', () => { + let now; + let validAttributes; - before(async function() { + before(async () => { now = Date.now(); validAttributes = { publicKey: testKey.pubKey, @@ -234,35 +230,35 @@ describe('SignalProtocolStore', function() { await store.removeIdentityKey(number); }); - describe('with valid attributes', function() { - before(async function() { + describe('with valid attributes', () => { + before(async () => { await store.saveIdentityWithAttributes(number, validAttributes); }); - it('publicKey is saved', async function() { + it('publicKey is saved', async () => { const identity = await window.Signal.Data.getIdentityKeyById(number); assertEqualArrayBuffers(identity.publicKey, testKey.pubKey); }); - it('firstUse is saved', async function() { + it('firstUse is saved', async () => { const identity = await window.Signal.Data.getIdentityKeyById(number); assert.strictEqual(identity.firstUse, true); }); - it('timestamp is saved', async function() { + it('timestamp is saved', async () => { const identity = await window.Signal.Data.getIdentityKeyById(number); assert.strictEqual(identity.timestamp, now); }); - it('verified is saved', async function() { + it('verified is saved', async () => { const identity = await window.Signal.Data.getIdentityKeyById(number); assert.strictEqual(identity.verified, store.VerifiedStatus.VERIFIED); }); - it('nonblockingApproval is saved', async function() { + it('nonblockingApproval is saved', async () => { const identity = await window.Signal.Data.getIdentityKeyById(number); assert.strictEqual(identity.nonblockingApproval, false); }); }); - describe('with invalid attributes', function() { - var attributes; - beforeEach(function() { + describe('with invalid attributes', () => { + let attributes; + beforeEach(() => { attributes = _.clone(validAttributes); }); @@ -275,38 +271,37 @@ describe('SignalProtocolStore', function() { } } - it('rejects an invalid publicKey', async function() { + it('rejects an invalid publicKey', async () => { attributes.publicKey = 'a string'; await testInvalidAttributes(); }); - it('rejects invalid firstUse', async function() { + it('rejects invalid firstUse', async () => { attributes.firstUse = 0; await testInvalidAttributes(); }); - it('rejects invalid timestamp', async function() { + it('rejects invalid timestamp', async () => { attributes.timestamp = NaN; await testInvalidAttributes(); }); - it('rejects invalid verified', async function() { + it('rejects invalid verified', async () => { attributes.verified = null; await testInvalidAttributes(); }); - it('rejects invalid nonblockingApproval', async function() { + it('rejects invalid nonblockingApproval', async () => { attributes.nonblockingApproval = 0; await testInvalidAttributes(); }); }); }); - describe('setApproval', function() { - it('sets nonblockingApproval', async function() { + describe('setApproval', () => { + it('sets nonblockingApproval', async () => { await store.setApproval(number, true); const identity = await window.Signal.Data.getIdentityKeyById(number); assert.strictEqual(identity.nonblockingApproval, true); }); }); - describe('setVerified', function() { - var record; + describe('setVerified', () => { async function saveRecordDefault() { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, @@ -317,9 +312,9 @@ describe('SignalProtocolStore', function() { nonblockingApproval: false, }); } - describe('with no public key argument', function() { + describe('with no public key argument', () => { before(saveRecordDefault); - it('updates the verified status', async function() { + it('updates the verified status', async () => { await store.setVerified(number, store.VerifiedStatus.VERIFIED); const identity = await window.Signal.Data.getIdentityKeyById(number); @@ -327,9 +322,9 @@ describe('SignalProtocolStore', function() { assertEqualArrayBuffers(identity.publicKey, testKey.pubKey); }); }); - describe('with the current public key', function() { + describe('with the current public key', () => { before(saveRecordDefault); - it('updates the verified status', async function() { + it('updates the verified status', async () => { await store.setVerified( number, store.VerifiedStatus.VERIFIED, @@ -341,10 +336,10 @@ describe('SignalProtocolStore', function() { assertEqualArrayBuffers(identity.publicKey, testKey.pubKey); }); }); - describe('with a mismatching public key', function() { - var newIdentity = libsignal.crypto.getRandomBytes(33); + describe('with a mismatching public key', () => { + const newIdentity = libsignal.crypto.getRandomBytes(33); before(saveRecordDefault); - it('does not change the record.', async function() { + it('does not change the record.', async () => { await store.setVerified( number, store.VerifiedStatus.VERIFIED, @@ -357,28 +352,27 @@ describe('SignalProtocolStore', function() { }); }); }); - describe('processContactSyncVerificationState', function() { - var record; - var newIdentity = libsignal.crypto.getRandomBytes(33); - var keychangeTriggered; + describe('processContactSyncVerificationState', () => { + const newIdentity = libsignal.crypto.getRandomBytes(33); + let keychangeTriggered; - beforeEach(function() { + beforeEach(() => { keychangeTriggered = 0; - store.bind('keychange', function() { - keychangeTriggered++; + store.bind('keychange', () => { + keychangeTriggered += 1; }); }); - afterEach(function() { + afterEach(() => { store.unbind('keychange'); }); - describe('when the new verified status is DEFAULT', function() { - describe('when there is no existing record', function() { - before(async function() { + describe('when the new verified status is DEFAULT', () => { + describe('when there is no existing record', () => { + before(async () => { await window.Signal.Data.removeIdentityKeyById(number); }); - it('does nothing', async function() { + it('does nothing', async () => { await store.processContactSyncVerificationState( number, store.VerifiedStatus.DEFAULT, @@ -398,9 +392,9 @@ describe('SignalProtocolStore', function() { assert.strictEqual(keychangeTriggered, 0); }); }); - describe('when the record exists', function() { - describe('when the existing key is different', function() { - before(async function() { + describe('when the record exists', () => { + describe('when the existing key is different', () => { + before(async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -411,7 +405,7 @@ describe('SignalProtocolStore', function() { }); }); - it('does not save the new identity (because this is a less secure state)', async function() { + it('does not save the new identity (because this is a less secure state)', async () => { await store.processContactSyncVerificationState( number, store.VerifiedStatus.DEFAULT, @@ -430,8 +424,8 @@ describe('SignalProtocolStore', function() { assert.strictEqual(keychangeTriggered, 0); }); }); - describe('when the existing key is the same but VERIFIED', function() { - before(async function() { + describe('when the existing key is the same but VERIFIED', () => { + before(async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -442,7 +436,7 @@ describe('SignalProtocolStore', function() { }); }); - it('updates the verified status', async function() { + it('updates the verified status', async () => { await store.processContactSyncVerificationState( number, store.VerifiedStatus.DEFAULT, @@ -458,8 +452,8 @@ describe('SignalProtocolStore', function() { assert.strictEqual(keychangeTriggered, 0); }); }); - describe('when the existing key is the same and already DEFAULT', function() { - before(async function() { + describe('when the existing key is the same and already DEFAULT', () => { + before(async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -470,7 +464,7 @@ describe('SignalProtocolStore', function() { }); }); - it('does not hang', async function() { + it('does not hang', async () => { await store.processContactSyncVerificationState( number, store.VerifiedStatus.DEFAULT, @@ -482,13 +476,13 @@ describe('SignalProtocolStore', function() { }); }); }); - describe('when the new verified status is UNVERIFIED', function() { - describe('when there is no existing record', function() { - before(async function() { + describe('when the new verified status is UNVERIFIED', () => { + describe('when there is no existing record', () => { + before(async () => { await window.Signal.Data.removeIdentityKeyById(number); }); - it('saves the new identity and marks it verified', async function() { + it('saves the new identity and marks it verified', async () => { await store.processContactSyncVerificationState( number, store.VerifiedStatus.UNVERIFIED, @@ -505,9 +499,9 @@ describe('SignalProtocolStore', function() { assert.strictEqual(keychangeTriggered, 0); }); }); - describe('when the record exists', function() { - describe('when the existing key is different', function() { - before(async function() { + describe('when the record exists', () => { + describe('when the existing key is different', () => { + before(async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -518,7 +512,7 @@ describe('SignalProtocolStore', function() { }); }); - it('saves the new identity and marks it UNVERIFIED', async function() { + it('saves the new identity and marks it UNVERIFIED', async () => { await store.processContactSyncVerificationState( number, store.VerifiedStatus.UNVERIFIED, @@ -537,8 +531,8 @@ describe('SignalProtocolStore', function() { assert.strictEqual(keychangeTriggered, 1); }); }); - describe('when the key exists and is DEFAULT', function() { - before(async function() { + describe('when the key exists and is DEFAULT', () => { + before(async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -549,7 +543,7 @@ describe('SignalProtocolStore', function() { }); }); - it('updates the verified status', async function() { + it('updates the verified status', async () => { await store.processContactSyncVerificationState( number, store.VerifiedStatus.UNVERIFIED, @@ -567,8 +561,8 @@ describe('SignalProtocolStore', function() { assert.strictEqual(keychangeTriggered, 0); }); }); - describe('when the key exists and is already UNVERIFIED', function() { - before(async function() { + describe('when the key exists and is already UNVERIFIED', () => { + before(async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -579,7 +573,7 @@ describe('SignalProtocolStore', function() { }); }); - it('does not hang', async function() { + it('does not hang', async () => { await store.processContactSyncVerificationState( number, store.VerifiedStatus.UNVERIFIED, @@ -591,13 +585,13 @@ describe('SignalProtocolStore', function() { }); }); }); - describe('when the new verified status is VERIFIED', function() { - describe('when there is no existing record', function() { - before(async function() { + describe('when the new verified status is VERIFIED', () => { + describe('when there is no existing record', () => { + before(async () => { await window.Signal.Data.removeIdentityKeyById(number); }); - it('saves the new identity and marks it verified', async function() { + it('saves the new identity and marks it verified', async () => { await store.processContactSyncVerificationState( number, store.VerifiedStatus.VERIFIED, @@ -610,9 +604,9 @@ describe('SignalProtocolStore', function() { assert.strictEqual(keychangeTriggered, 0); }); }); - describe('when the record exists', function() { - describe('when the existing key is different', function() { - before(async function() { + describe('when the record exists', () => { + describe('when the existing key is different', () => { + before(async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -623,7 +617,7 @@ describe('SignalProtocolStore', function() { }); }); - it('saves the new identity and marks it VERIFIED', async function() { + it('saves the new identity and marks it VERIFIED', async () => { await store.processContactSyncVerificationState( number, store.VerifiedStatus.VERIFIED, @@ -642,8 +636,8 @@ describe('SignalProtocolStore', function() { assert.strictEqual(keychangeTriggered, 1); }); }); - describe('when the existing key is the same but UNVERIFIED', function() { - before(async function() { + describe('when the existing key is the same but UNVERIFIED', () => { + before(async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -654,7 +648,7 @@ describe('SignalProtocolStore', function() { }); }); - it('saves the identity and marks it verified', async function() { + it('saves the identity and marks it verified', async () => { await store.processContactSyncVerificationState( number, store.VerifiedStatus.VERIFIED, @@ -672,8 +666,8 @@ describe('SignalProtocolStore', function() { assert.strictEqual(keychangeTriggered, 0); }); }); - describe('when the existing key is the same and already VERIFIED', function() { - before(async function() { + describe('when the existing key is the same and already VERIFIED', () => { + before(async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -684,7 +678,7 @@ describe('SignalProtocolStore', function() { }); }); - it('does not hang', async function() { + it('does not hang', async () => { await store.processContactSyncVerificationState( number, store.VerifiedStatus.VERIFIED, @@ -698,8 +692,8 @@ describe('SignalProtocolStore', function() { }); }); - describe('isUntrusted', function() { - it('returns false if identity key old enough', async function() { + describe('isUntrusted', () => { + it('returns false if identity key old enough', async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -713,7 +707,7 @@ describe('SignalProtocolStore', function() { assert.strictEqual(untrusted, false); }); - it('returns false if new but nonblockingApproval is true', async function() { + it('returns false if new but nonblockingApproval is true', async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -727,7 +721,7 @@ describe('SignalProtocolStore', function() { assert.strictEqual(untrusted, false); }); - it('returns false if new but firstUse is true', async function() { + it('returns false if new but firstUse is true', async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -741,7 +735,7 @@ describe('SignalProtocolStore', function() { assert.strictEqual(untrusted, false); }); - it('returns true if new, and no flags are set', async function() { + it('returns true if new, and no flags are set', async () => { await window.Signal.Data.createOrUpdateIdentityKey({ id: number, publicKey: testKey.pubKey, @@ -755,21 +749,21 @@ describe('SignalProtocolStore', function() { }); }); - describe('getVerified', function() { - before(async function() { + describe('getVerified', () => { + before(async () => { await store.setVerified(number, store.VerifiedStatus.VERIFIED); }); - it('resolves to the verified status', async function() { + it('resolves to the verified status', async () => { const result = await store.getVerified(number); assert.strictEqual(result, store.VerifiedStatus.VERIFIED); }); }); - describe('isTrustedIdentity', function() { + describe('isTrustedIdentity', () => { const address = new libsignal.SignalProtocolAddress(number, 1); const identifier = address.toString(); - describe('When invalid direction is given', function() { - it('should fail', async function() { + describe('When invalid direction is given', () => { + it('should fail', async () => { try { await store.isTrustedIdentity(number, testKey.pubKey); throw new Error('isTrustedIdentity should have failed'); @@ -778,9 +772,9 @@ describe('SignalProtocolStore', function() { } }); }); - describe('When direction is RECEIVING', function() { - it('always returns true', async function() { - var newIdentity = libsignal.crypto.getRandomBytes(33); + describe('When direction is RECEIVING', () => { + it('always returns true', async () => { + const newIdentity = libsignal.crypto.getRandomBytes(33); await store.saveIdentity(identifier, testKey.pubKey); const trusted = await store.isTrustedIdentity( @@ -794,12 +788,12 @@ describe('SignalProtocolStore', function() { } }); }); - describe('When direction is SENDING', function() { - describe('When there is no existing key (first use)', function() { - before(async function() { + describe('When direction is SENDING', () => { + describe('When there is no existing key (first use)', () => { + before(async () => { await store.removeIdentityKey(number); }); - it('returns true', async function() { + it('returns true', async () => { const newIdentity = libsignal.crypto.getRandomBytes(33); const trusted = await store.isTrustedIdentity( identifier, @@ -811,12 +805,12 @@ describe('SignalProtocolStore', function() { } }); }); - describe('When there is an existing key', function() { - before(async function() { + describe('When there is an existing key', () => { + before(async () => { await store.saveIdentity(identifier, testKey.pubKey); }); - describe('When the existing key is different', function() { - it('returns false', async function() { + describe('When the existing key is different', () => { + it('returns false', async () => { const newIdentity = libsignal.crypto.getRandomBytes(33); const trusted = await store.isTrustedIdentity( identifier, @@ -828,12 +822,12 @@ describe('SignalProtocolStore', function() { } }); }); - describe('When the existing key matches the new key', function() { + describe('When the existing key matches the new key', () => { const newIdentity = libsignal.crypto.getRandomBytes(33); - before(async function() { + before(async () => { await store.saveIdentity(identifier, newIdentity); }); - it('returns false if keys match but we just received this new identiy', async function() { + it('returns false if keys match but we just received this new identiy', async () => { const trusted = await store.isTrustedIdentity( identifier, newIdentity, @@ -844,7 +838,7 @@ describe('SignalProtocolStore', function() { throw new Error('isTrusted returned true on untrusted key'); } }); - it('returns true if we have already approved identity', async function() { + it('returns true if we have already approved identity', async () => { await store.saveIdentity(identifier, newIdentity, true); const trusted = await store.isTrustedIdentity( @@ -860,27 +854,27 @@ describe('SignalProtocolStore', function() { }); }); }); - describe('storePreKey', function() { - it('stores prekeys', async function() { + describe('storePreKey', () => { + it('stores prekeys', async () => { await store.storePreKey(1, testKey); const key = await store.loadPreKey(1); assertEqualArrayBuffers(key.pubKey, testKey.pubKey); assertEqualArrayBuffers(key.privKey, testKey.privKey); }); }); - describe('removePreKey', function() { - before(async function() { + describe('removePreKey', () => { + before(async () => { await store.storePreKey(2, testKey); }); - it('deletes prekeys', async function() { + it('deletes prekeys', async () => { await store.removePreKey(2, testKey); const key = await store.loadPreKey(2); assert.isUndefined(key); }); }); - describe('storeSignedPreKey', function() { - it('stores signed prekeys', async function() { + describe('storeSignedPreKey', () => { + it('stores signed prekeys', async () => { await store.storeSignedPreKey(3, testKey); const key = await store.loadSignedPreKey(3); @@ -888,36 +882,36 @@ describe('SignalProtocolStore', function() { assertEqualArrayBuffers(key.privKey, testKey.privKey); }); }); - describe('removeSignedPreKey', function() { - before(async function() { + describe('removeSignedPreKey', () => { + before(async () => { await store.storeSignedPreKey(4, testKey); }); - it('deletes signed prekeys', async function() { + it('deletes signed prekeys', async () => { await store.removeSignedPreKey(4, testKey); const key = await store.loadSignedPreKey(4); assert.isUndefined(key); }); }); - describe('storeSession', function() { - it('stores sessions', async function() { + describe('storeSession', () => { + it('stores sessions', async () => { const testRecord = 'an opaque string'; - await store.storeSession(number + '.1', testRecord); - const record = await store.loadSession(number + '.1'); + await store.storeSession(`${number}.1`, testRecord); + const record = await store.loadSession(`${number}.1`); assert.deepEqual(record, testRecord); }); }); - describe('removeAllSessions', function() { - it('removes all sessions for a number', async function() { + describe('removeAllSessions', () => { + it('removes all sessions for a number', async () => { const testRecord = 'an opaque string'; - const devices = [1, 2, 3].map(function(deviceId) { + const devices = [1, 2, 3].map(deviceId => { return [number, deviceId].join('.'); }); await Promise.all( - devices.map(async function(encodedNumber) { + devices.map(async encodedNumber => { await store.storeSession(encodedNumber, testRecord + encodedNumber); }) ); @@ -927,30 +921,31 @@ describe('SignalProtocolStore', function() { const records = await Promise.all( devices.map(store.loadSession.bind(store)) ); - for (var i in records) { + + for (let i = 0, max = records.length; i < max; i += 1) { assert.isUndefined(records[i]); } }); }); - describe('clearSessionStore', function() { - it('clears the session store', async function() { + describe('clearSessionStore', () => { + it('clears the session store', async () => { const testRecord = 'an opaque string'; - await store.storeSession(number + '.1', testRecord); + await store.storeSession(`${number}.1`, testRecord); await store.clearSessionStore(); - const record = await store.loadSession(number + '.1'); + const record = await store.loadSession(`${number}.1`); assert.isUndefined(record); }); }); - describe('getDeviceIds', function() { - it('returns deviceIds for a number', async function() { + describe('getDeviceIds', () => { + it('returns deviceIds for a number', async () => { const testRecord = 'an opaque string'; - const devices = [1, 2, 3].map(function(deviceId) { + const devices = [1, 2, 3].map(deviceId => { return [number, deviceId].join('.'); }); await Promise.all( - devices.map(async function(encodedNumber) { + devices.map(async encodedNumber => { await store.storeSession(encodedNumber, testRecord + encodedNumber); }) ); @@ -958,20 +953,20 @@ describe('SignalProtocolStore', function() { const deviceIds = await store.getDeviceIds(number); assert.sameMembers(deviceIds, [1, 2, 3]); }); - it('returns empty array for a number with no device ids', async function() { + it('returns empty array for a number with no device ids', async () => { const deviceIds = await store.getDeviceIds('foo'); assert.sameMembers(deviceIds, []); }); }); - describe('Not yet processed messages', function() { - beforeEach(async function() { + describe('Not yet processed messages', () => { + beforeEach(async () => { await store.removeAllUnprocessed(); const items = await store.getAllUnprocessed(); assert.strictEqual(items.length, 0); }); - it('adds two and gets them back', async function() { + it('adds two and gets them back', async () => { await Promise.all([ store.addUnprocessed({ id: 2, name: 'second', timestamp: 2 }), store.addUnprocessed({ id: 3, name: 'third', timestamp: 3 }), @@ -987,9 +982,9 @@ describe('SignalProtocolStore', function() { assert.strictEqual(items[2].name, 'third'); }); - it('saveUnprocessed successfully updates item', async function() { + it('saveUnprocessed successfully updates item', async () => { const id = 1; - await store.addUnprocessed({ id: id, name: 'first', timestamp: 1 }); + await store.addUnprocessed({ id, name: 'first', timestamp: 1 }); await store.saveUnprocessed({ id, name: 'updated', timestamp: 1 }); const items = await store.getAllUnprocessed(); @@ -998,9 +993,9 @@ describe('SignalProtocolStore', function() { assert.strictEqual(items[0].timestamp, 1); }); - it('removeUnprocessed successfully deletes item', async function() { + it('removeUnprocessed successfully deletes item', async () => { const id = 1; - await store.addUnprocessed({ id: id, name: 'first', timestamp: 1 }); + await store.addUnprocessed({ id, name: 'first', timestamp: 1 }); await store.removeUnprocessed(id); const items = await store.getAllUnprocessed(); diff --git a/test/views/attachment_view_test.js b/test/views/attachment_view_test.js index fbc1f1f8e..99d8d1f3e 100644 --- a/test/views/attachment_view_test.js +++ b/test/views/attachment_view_test.js @@ -1,17 +1,15 @@ -/* global assert: false */ - -/* global Whisper: false */ +/* global assert, storage, Whisper */ 'use strict'; describe('AttachmentView', () => { - var convo, message; + let convo; before(async () => { await clearDatabase(); convo = new Whisper.Conversation({ id: 'foo' }); - message = convo.messageCollection.add({ + convo.messageCollection.add({ conversationId: convo.id, body: 'hello world', type: 'outgoing', diff --git a/test/views/conversation_search_view_test.js b/test/views/conversation_search_view_test.js index 75a82900f..d1bd9dc38 100644 --- a/test/views/conversation_search_view_test.js +++ b/test/views/conversation_search_view_test.js @@ -1,11 +1,13 @@ -describe('ConversationSearchView', function() { - it('should match partial numbers', function() { - var $el = $('
'); - var view = new Whisper.ConversationSearchView({ +/* global $, Whisper */ + +describe('ConversationSearchView', () => { + it('should match partial numbers', () => { + const $el = $('
'); + const view = new Whisper.ConversationSearchView({ el: $el, input: $(''), }).render(); - var maybe_numbers = [ + const maybeNumbers = [ '+1 415', '+1415', '+1415', @@ -19,11 +21,11 @@ describe('ConversationSearchView', function() { '1 415-123-4567', '415-123-4567', ]; - maybe_numbers.forEach(function(n) { + maybeNumbers.forEach(n => { assert.ok(view.maybeNumber(n), n); }); }); - describe('Searching for left groups', function() { + describe('Searching for left groups', () => { let convo; before(() => { @@ -39,32 +41,32 @@ describe('ConversationSearchView', function() { Conversation: Whisper.Conversation, }); }); - describe('with no messages', function() { - var input; - var view; + describe('with no messages', () => { + let input; + let view; - before(function(done) { + before(done => { input = $(''); - view = new Whisper.ConversationSearchView({ input: input }).render(); + view = new Whisper.ConversationSearchView({ input }).render(); view.$input.val('left'); view.filterContacts(); - view.typeahead_view.collection.on('reset', function() { + view.typeahead_view.collection.on('reset', () => { done(); }); }); - it('should not surface left groups with no messages', function() { + it('should not surface left groups with no messages', () => { assert.isUndefined( view.typeahead_view.collection.get(convo.id), 'got left group' ); }); }); - describe('with messages', function() { - var input; - var view; - before(async function() { + describe('with messages', () => { + let input; + let view; + before(async () => { input = $(''); - view = new Whisper.ConversationSearchView({ input: input }).render(); + view = new Whisper.ConversationSearchView({ input }).render(); convo.set({ id: '2-search-view', left: false }); await window.Signal.Data.saveConversation(convo.attributes, { @@ -78,7 +80,7 @@ describe('ConversationSearchView', function() { view.typeahead_view.collection.on('reset', resolve); }); }); - it('should surface left groups with messages', function() { + it('should surface left groups with messages', () => { assert.isDefined( view.typeahead_view.collection.get(convo.id), 'got left group' diff --git a/test/views/group_update_view_test.js b/test/views/group_update_view_test.js index dd3d06d4c..45c9a7440 100644 --- a/test/views/group_update_view_test.js +++ b/test/views/group_update_view_test.js @@ -1,20 +1,22 @@ -describe('GroupUpdateView', function() { - it('should show new group members', function() { - var view = new Whisper.GroupUpdateView({ +/* global Whisper */ + +describe('GroupUpdateView', () => { + it('should show new group members', () => { + const view = new Whisper.GroupUpdateView({ model: { joined: ['Alice', 'Bob'] }, }).render(); assert.match(view.$el.text(), /Alice.*Bob.*joined the group/); }); - it('should note updates to the title', function() { - var view = new Whisper.GroupUpdateView({ + it('should note updates to the title', () => { + const view = new Whisper.GroupUpdateView({ model: { name: 'New name' }, }).render(); assert.match(view.$el.text(), /Title is now 'New name'/); }); - it('should say "Updated the group"', function() { - var view = new Whisper.GroupUpdateView({ + it('should say "Updated the group"', () => { + const view = new Whisper.GroupUpdateView({ model: { avatar: 'New avatar' }, }).render(); assert.match(view.$el.text(), /Updated the group/); diff --git a/test/views/inbox_view_test.js b/test/views/inbox_view_test.js index 5cf9253ac..abc076139 100644 --- a/test/views/inbox_view_test.js +++ b/test/views/inbox_view_test.js @@ -1,24 +1,20 @@ -describe('InboxView', function() { +/* global ConversationController, textsecure, Whisper */ + +describe('InboxView', () => { let inboxView; let conversation; before(async () => { - try { - await ConversationController.load(); - } catch (error) { - console.log( - 'InboxView before:', - error && error.stack ? error.stack : error - ); - } + ConversationController.reset(); + await ConversationController.load(); await ConversationController.getOrCreateAndWait( textsecure.storage.user.getNumber(), 'private' ); inboxView = new Whisper.InboxView({ model: {}, - window: window, - initialLoadComplete: function() {}, + window, + initialLoadComplete() {}, }).render(); conversation = new Whisper.Conversation({ @@ -27,32 +23,32 @@ describe('InboxView', function() { }); }); - describe('the conversation stack', function() { - it('should be rendered', function() { + describe('the conversation stack', () => { + it('should be rendered', () => { assert.ok(inboxView.$('.conversation-stack').length === 1); }); - describe('opening a conversation', function() { - var triggeredOpenedCount = 0; + describe('opening a conversation', () => { + let triggeredOpenedCount = 0; - before(function() { - conversation.on('opened', function() { - triggeredOpenedCount++; + before(() => { + conversation.on('opened', () => { + triggeredOpenedCount += 1; }); inboxView.conversation_stack.open(conversation); }); - it('should trigger an opened event', function() { + it('should trigger an opened event', () => { assert.ok(triggeredOpenedCount === 1); }); - describe('and then opening it again immediately', function() { - before(function() { + describe('and then opening it again immediately', () => { + before(() => { inboxView.conversation_stack.open(conversation); }); - it('should trigger the opened event again', function() { + it('should trigger the opened event again', () => { assert.ok(triggeredOpenedCount === 2); }); }); diff --git a/test/views/last_seen_indicator_view_test.js b/test/views/last_seen_indicator_view_test.js index cb288fb58..c24d1d80d 100644 --- a/test/views/last_seen_indicator_view_test.js +++ b/test/views/last_seen_indicator_view_test.js @@ -1,22 +1,24 @@ -describe('LastSeenIndicatorView', function() { - it('renders provided count', function() { - var view = new Whisper.LastSeenIndicatorView({ count: 10 }); +/* global Whisper */ + +describe('LastSeenIndicatorView', () => { + it('renders provided count', () => { + const view = new Whisper.LastSeenIndicatorView({ count: 10 }); assert.equal(view.count, 10); view.render(); assert.match(view.$el.html(), /10 Unread Messages/); }); - it('renders count of 1', function() { - var view = new Whisper.LastSeenIndicatorView({ count: 1 }); + it('renders count of 1', () => { + const view = new Whisper.LastSeenIndicatorView({ count: 1 }); assert.equal(view.count, 1); view.render(); assert.match(view.$el.html(), /1 Unread Message/); }); - it('increments count', function() { - var view = new Whisper.LastSeenIndicatorView({ count: 4 }); + it('increments count', () => { + const view = new Whisper.LastSeenIndicatorView({ count: 4 }); assert.equal(view.count, 4); view.render(); diff --git a/test/views/list_view_test.js b/test/views/list_view_test.js index 8ba47d170..139b95abf 100644 --- a/test/views/list_view_test.js +++ b/test/views/list_view_test.js @@ -1,20 +1,22 @@ -describe('ListView', function() { - var collection; +/* global Backbone, Whisper */ - beforeEach(function() { +describe('ListView', () => { + let collection; + + beforeEach(() => { collection = new Backbone.Collection(); }); - it('should add children to the list element as they are added to the collection', function() { - var view = new Whisper.ListView({ collection: collection }); + it('should add children to the list element as they are added to the collection', () => { + const view = new Whisper.ListView({ collection }); collection.add('hello'); assert.equal(view.$el.children().length, 1); collection.add('world'); assert.equal(view.$el.children().length, 2); }); - it('should add all the children to the list element on reset', function() { - var view = new Whisper.ListView({ collection: collection }); + it('should add all the children to the list element on reset', () => { + const view = new Whisper.ListView({ collection }); collection.reset(['goodbye', 'world']); assert.equal(view.$el.children().length, 2); }); diff --git a/test/views/network_status_view_test.js b/test/views/network_status_view_test.js index d4f5e5798..a3daa7883 100644 --- a/test/views/network_status_view_test.js +++ b/test/views/network_status_view_test.js @@ -1,149 +1,143 @@ -describe('NetworkStatusView', function() { - describe('getNetworkStatus', function() { - var networkStatusView; - var socketStatus = WebSocket.OPEN; +/* global _, $, Whisper */ - var oldGetSocketStatus; +describe('NetworkStatusView', () => { + describe('getNetworkStatus', () => { + let networkStatusView; + let socketStatus = WebSocket.OPEN; + + let oldGetSocketStatus; /* BEGIN stubbing globals */ - before(function() { + before(() => { oldGetSocketStatus = window.getSocketStatus; - window.getSocketStatus = function() { - return socketStatus; - }; + window.getSocketStatus = () => socketStatus; }); - after(function() { + after(() => { window.getSocketStatus = oldGetSocketStatus; // It turns out that continued calls to window.getSocketStatus happen // because we host NetworkStatusView in three mock interfaces, and the view // checks every N seconds. That results in infinite errors unless there is // something to call. - window.getSocketStatus = function() { - return WebSocket.OPEN; - }; + window.getSocketStatus = () => WebSocket.OPEN; }); /* END stubbing globals */ - beforeEach(function() { + beforeEach(() => { networkStatusView = new Whisper.NetworkStatusView(); $('.network-status-container').append(networkStatusView.el); }); - afterEach(function() { + afterEach(() => { // prevents huge number of errors on console after running tests clearInterval(networkStatusView.renderIntervalHandle); networkStatusView = null; }); - describe('initialization', function() { - it('should have an empty interval', function() { + describe('initialization', () => { + it('should have an empty interval', () => { assert.equal( networkStatusView.socketReconnectWaitDuration.asSeconds(), 0 ); }); }); - describe('network status with no connection', function() { - beforeEach(function() { - networkStatusView.navigatorOnLine = function() { - return false; - }; + describe('network status with no connection', () => { + beforeEach(() => { + networkStatusView.navigatorOnLine = () => false; }); - it('should be interrupted', function() { + it('should be interrupted', () => { networkStatusView.update(); - var status = networkStatusView.getNetworkStatus(); + const status = networkStatusView.getNetworkStatus(); assert(status.hasInterruption); assert.equal(status.instructions, 'Check your network connection.'); }); - it('should display an offline message', function() { + it('should display an offline message', () => { networkStatusView.update(); assert.match(networkStatusView.$el.text(), /Offline/); }); - it('should override socket status', function() { + it('should override socket status', () => { _([ WebSocket.CONNECTING, WebSocket.OPEN, WebSocket.CLOSING, WebSocket.CLOSED, - ]).map(function(socketStatusVal) { + ]).forEach(socketStatusVal => { socketStatus = socketStatusVal; networkStatusView.update(); assert.match(networkStatusView.$el.text(), /Offline/); }); }); - it('should override registration status', function() { + it('should override registration status', () => { Whisper.Registration.remove(); networkStatusView.update(); assert.match(networkStatusView.$el.text(), /Offline/); }); }); - describe('network status when registration is not done', function() { - beforeEach(function() { + describe('network status when registration is not done', () => { + beforeEach(() => { Whisper.Registration.remove(); }); - it('should display an unlinked message', function() { + it('should display an unlinked message', () => { networkStatusView.update(); assert.match(networkStatusView.$el.text(), /Relink/); }); - it('should override socket status', function() { + it('should override socket status', () => { _([ WebSocket.CONNECTING, WebSocket.OPEN, WebSocket.CLOSING, WebSocket.CLOSED, - ]).map(function(socketStatusVal) { + ]).forEach(socketStatusVal => { socketStatus = socketStatusVal; networkStatusView.update(); assert.match(networkStatusView.$el.text(), /Relink/); }); }); }); - describe('network status when registration is done', function() { - beforeEach(function() { - networkStatusView.navigatorOnLine = function() { - return true; - }; + describe('network status when registration is done', () => { + beforeEach(() => { + networkStatusView.navigatorOnLine = () => true; Whisper.Registration.markDone(); networkStatusView.update(); }); - it('should not display an unlinked message', function() { + it('should not display an unlinked message', () => { networkStatusView.update(); assert.notMatch(networkStatusView.$el.text(), /Relink/); }); }); - describe('network status when socket is connecting', function() { - beforeEach(function() { + describe('network status when socket is connecting', () => { + beforeEach(() => { Whisper.Registration.markDone(); socketStatus = WebSocket.CONNECTING; networkStatusView.update(); }); - it('it should display a connecting string if connecting and not in the connecting grace period', function() { + it('it should display a connecting string if connecting and not in the connecting grace period', () => { networkStatusView.withinConnectingGracePeriod = false; - var status = networkStatusView.getNetworkStatus(); + networkStatusView.getNetworkStatus(); assert.match(networkStatusView.$el.text(), /Connecting/); }); - it('it should not be interrupted if in connecting grace period', function() { + it('it should not be interrupted if in connecting grace period', () => { assert(networkStatusView.withinConnectingGracePeriod); - var status = networkStatusView.getNetworkStatus(); + const status = networkStatusView.getNetworkStatus(); assert.match(networkStatusView.$el.text(), /Connecting/); assert(!status.hasInterruption); }); - it('it should be interrupted if connecting grace period is over', function() { + it('it should be interrupted if connecting grace period is over', () => { networkStatusView.withinConnectingGracePeriod = false; - var status = networkStatusView.getNetworkStatus(); + const status = networkStatusView.getNetworkStatus(); assert(status.hasInterruption); }); }); - describe('network status when socket is open', function() { - before(function() { + describe('network status when socket is open', () => { + before(() => { socketStatus = WebSocket.OPEN; }); - it('should not be interrupted', function() { - var status = networkStatusView.getNetworkStatus(); + it('should not be interrupted', () => { + const status = networkStatusView.getNetworkStatus(); assert(!status.hasInterruption); assert.match( networkStatusView.$el @@ -154,23 +148,23 @@ describe('NetworkStatusView', function() { ); }); }); - describe('network status when socket is closed or closing', function() { - _([WebSocket.CLOSED, WebSocket.CLOSING]).map(function(socketStatusVal) { - it('should be interrupted', function() { + describe('network status when socket is closed or closing', () => { + _([WebSocket.CLOSED, WebSocket.CLOSING]).forEach(socketStatusVal => { + it('should be interrupted', () => { socketStatus = socketStatusVal; networkStatusView.update(); - var status = networkStatusView.getNetworkStatus(); + const status = networkStatusView.getNetworkStatus(); assert(status.hasInterruption); }); }); }); - describe('the socket reconnect interval', function() { - beforeEach(function() { + describe('the socket reconnect interval', () => { + beforeEach(() => { socketStatus = WebSocket.CLOSED; networkStatusView.setSocketReconnectInterval(61000); networkStatusView.update(); }); - it('should format the message based on the socketReconnectWaitDuration property', function() { + it('should format the message based on the socketReconnectWaitDuration property', () => { assert.equal( networkStatusView.socketReconnectWaitDuration.asSeconds(), 61 @@ -180,7 +174,7 @@ describe('NetworkStatusView', function() { /Attempting reconnect/ ); }); - it('should be reset by changing the socketStatus to CONNECTING', function() {}); + it('should be reset by changing the socketStatus to CONNECTING', () => {}); }); }); }); diff --git a/test/views/scroll_down_button_view_test.js b/test/views/scroll_down_button_view_test.js index 6adf5b5d4..27ff41072 100644 --- a/test/views/scroll_down_button_view_test.js +++ b/test/views/scroll_down_button_view_test.js @@ -1,28 +1,30 @@ -describe('ScrollDownButtonView', function() { - it('renders with count = 0', function() { - var view = new Whisper.ScrollDownButtonView(); +/* global Whisper */ + +describe('ScrollDownButtonView', () => { + it('renders with count = 0', () => { + const view = new Whisper.ScrollDownButtonView(); view.render(); assert.equal(view.count, 0); assert.match(view.$el.html(), /Scroll to bottom/); }); - it('renders with count = 1', function() { - var view = new Whisper.ScrollDownButtonView({ count: 1 }); + it('renders with count = 1', () => { + const view = new Whisper.ScrollDownButtonView({ count: 1 }); view.render(); assert.equal(view.count, 1); assert.match(view.$el.html(), /New message below/); }); - it('renders with count = 2', function() { - var view = new Whisper.ScrollDownButtonView({ count: 2 }); + it('renders with count = 2', () => { + const view = new Whisper.ScrollDownButtonView({ count: 2 }); view.render(); assert.equal(view.count, 2); assert.match(view.$el.html(), /New messages below/); }); - it('increments count and re-renders', function() { - var view = new Whisper.ScrollDownButtonView(); + it('increments count and re-renders', () => { + const view = new Whisper.ScrollDownButtonView(); view.render(); assert.equal(view.count, 0); assert.notMatch(view.$el.html(), /New message below/); diff --git a/test/views/threads_test.js b/test/views/threads_test.js index e52942516..3999d23e9 100644 --- a/test/views/threads_test.js +++ b/test/views/threads_test.js @@ -1,17 +1,19 @@ -describe('Threads', function() { - it('should be ordered newest to oldest', function() { +/* global Whisper */ + +describe('Threads', () => { + it('should be ordered newest to oldest', () => { // Timestamps - var today = new Date(); - var tomorrow = new Date(); + const today = new Date(); + const tomorrow = new Date(); tomorrow.setDate(today.getDate() + 1); // Add threads Whisper.Threads.add({ timestamp: today }); Whisper.Threads.add({ timestamp: tomorrow }); - var models = Whisper.Threads.models; - var firstTimestamp = models[0].get('timestamp').getTime(); - var secondTimestamp = models[1].get('timestamp').getTime(); + const { models } = Whisper.Threads; + const firstTimestamp = models[0].get('timestamp').getTime(); + const secondTimestamp = models[1].get('timestamp').getTime(); // Compare timestamps assert(firstTimestamp > secondTimestamp); diff --git a/test/views/timestamp_view_test.js b/test/views/timestamp_view_test.js index e9b54c38a..2e22d734f 100644 --- a/test/views/timestamp_view_test.js +++ b/test/views/timestamp_view_test.js @@ -1,38 +1,41 @@ +/* global moment, Whisper */ + 'use strict'; -describe('TimestampView', function() { - it('formats long-ago timestamps correctly', function() { - var timestamp = Date.now(); - var brief_view = new Whisper.TimestampView({ brief: true }).render(), - ext_view = new Whisper.ExtendedTimestampView().render(); +describe('TimestampView', () => { + it('formats long-ago timestamps correctly', () => { + const timestamp = Date.now(); + const briefView = new Whisper.TimestampView({ brief: true }).render(); + const extendedView = new Whisper.ExtendedTimestampView().render(); // Helper functions to check absolute and relative timestamps // Helper to check an absolute TS for an exact match - var check = function(view, ts, expected) { - var result = view.getRelativeTimeSpanString(ts); + const check = (view, ts, expected) => { + const result = view.getRelativeTimeSpanString(ts); assert.strictEqual(result, expected); }; // Helper to check relative times for an exact match against both views - var checkDiff = function(sec_ago, expected_brief, expected_ext) { - check(brief_view, timestamp - sec_ago * 1000, expected_brief); - check(ext_view, timestamp - sec_ago * 1000, expected_ext); + const checkDiff = (secAgo, expectedBrief, expectedExtended) => { + check(briefView, timestamp - secAgo * 1000, expectedBrief); + check(extendedView, timestamp - secAgo * 1000, expectedExtended); }; // Helper to check an absolute TS for an exact match against both views - var checkAbs = function(ts, expected_brief, expected_ext) { - if (!expected_ext) { - expected_ext = expected_brief; + const checkAbs = (ts, expectedBrief, expectedExtended) => { + if (!expectedExtended) { + // eslint-disable-next-line no-param-reassign + expectedExtended = expectedBrief; } - check(brief_view, ts, expected_brief); - check(ext_view, ts, expected_ext); + check(briefView, ts, expectedBrief); + check(extendedView, ts, expectedExtended); }; // Helper to check an absolute TS for a match at the beginning against - var checkStartsWith = function(view, ts, expected) { - var result = view.getRelativeTimeSpanString(ts); - var regexp = new RegExp('^' + expected); + const checkStartsWith = (view, ts, expected) => { + const result = view.getRelativeTimeSpanString(ts); + const regexp = new RegExp(`^${expected}`); assert.match(result, regexp); }; @@ -48,82 +51,85 @@ describe('TimestampView', function() { checkDiff(125 * 60, '2 hours', '2 hours ago'); // set to third of month to avoid problems on the 29th/30th/31st - var last_month = moment() - .subtract(1, 'month') - .date(3), - months = [ - 'Jan', - 'Feb', - 'Mar', - 'Apr', - 'May', - 'Jun', - 'Jul', - 'Aug', - 'Sep', - 'Oct', - 'Nov', - 'Dec', - ], - day_of_month = new Date().getDate(); - check(brief_view, last_month, months[last_month.month()] + ' 3'); - checkStartsWith(ext_view, last_month, months[last_month.month()] + ' 3'); + const lastMonth = moment() + .subtract(1, 'month') + .date(3); + const months = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ]; + check(briefView, lastMonth, `${months[lastMonth.month()]} 3`); + checkStartsWith(extendedView, lastMonth, `${months[lastMonth.month()]} 3`); // subtract 26 hours to be safe in case of DST stuff - var yesterday = new Date(timestamp - 26 * 60 * 60 * 1000), - days_of_week = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; - check(brief_view, yesterday, days_of_week[yesterday.getDay()]); - checkStartsWith(ext_view, yesterday, days_of_week[yesterday.getDay()]); + const yesterday = new Date(timestamp - 26 * 60 * 60 * 1000); + const daysOfWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; + check(briefView, yesterday, daysOfWeek[yesterday.getDay()]); + checkStartsWith(extendedView, yesterday, daysOfWeek[yesterday.getDay()]); // Check something long ago // months are zero-indexed in JS for some reason - check(brief_view, new Date(2012, 4, 5, 17, 30, 0), 'May 5, 2012'); - checkStartsWith(ext_view, new Date(2012, 4, 5, 17, 30, 0), 'May 5, 2012'); + check(briefView, new Date(2012, 4, 5, 17, 30, 0), 'May 5, 2012'); + checkStartsWith( + extendedView, + new Date(2012, 4, 5, 17, 30, 0), + 'May 5, 2012' + ); }); - describe('updates within a minute reasonable intervals', function() { - var view; - beforeEach(function() { + describe('updates within a minute reasonable intervals', () => { + let view; + beforeEach(() => { view = new Whisper.TimestampView(); }); - afterEach(function() { + afterEach(() => { clearTimeout(view.timeout); }); - it('updates timestamps this minute within a minute', function() { - var now = Date.now(); + it('updates timestamps this minute within a minute', () => { + const now = Date.now(); view.$el.attr('data-timestamp', now - 1000); view.update(); assert.isAbove(view.delay, 0); // non zero assert.isBelow(view.delay, 60 * 1000); // < minute }); - it('updates timestamps from this hour within a minute', function() { - var now = Date.now(); + it('updates timestamps from this hour within a minute', () => { + const now = Date.now(); view.$el.attr('data-timestamp', now - 1000 - 1000 * 60 * 5); // 5 minutes and 1 sec ago view.update(); assert.isAbove(view.delay, 0); // non zero assert.isBelow(view.delay, 60 * 1000); // minute }); - it('updates timestamps from today within an hour', function() { - var now = Date.now(); + it('updates timestamps from today within an hour', () => { + const now = Date.now(); view.$el.attr('data-timestamp', now - 1000 - 1000 * 60 * 60 * 5); // 5 hours and 1 sec ago view.update(); assert.isAbove(view.delay, 60 * 1000); // minute assert.isBelow(view.delay, 60 * 60 * 1000); // hour }); - it('updates timestamps from this week within a day', function() { - var now = Date.now(); + it('updates timestamps from this week within a day', () => { + const now = Date.now(); view.$el.attr('data-timestamp', now - 1000 - 6 * 24 * 60 * 60 * 1000); // 6 days and 1 sec ago view.update(); assert.isAbove(view.delay, 60 * 60 * 1000); // hour assert.isBelow(view.delay, 36 * 60 * 60 * 1000); // day and a half }); - it('does not updates very old timestamps', function() { - var now = Date.now(); + it('does not updates very old timestamps', () => { + const now = Date.now(); // return falsey value for long ago dates that don't update view.$el.attr('data-timestamp', now - 8 * 24 * 60 * 60 * 1000); view.update(); diff --git a/test/views/whisper_view_test.js b/test/views/whisper_view_test.js index 4b2b4396f..40de73aa5 100644 --- a/test/views/whisper_view_test.js +++ b/test/views/whisper_view_test.js @@ -1,35 +1,37 @@ -describe('Whisper.View', function() { - it('renders a template with render_attributes', function() { - var viewClass = Whisper.View.extend({ +/* global Whisper */ + +describe('Whisper.View', () => { + it('renders a template with render_attributes', () => { + const ViewClass = Whisper.View.extend({ template: '
{{ variable }}
', render_attributes: { variable: 'value', }, }); - var view = new viewClass(); + const view = new ViewClass(); view.render(); assert.strictEqual(view.$el.html(), '
value
'); }); - it('renders a template with no render_attributes', function() { - var viewClass = Whisper.View.extend({ + it('renders a template with no render_attributes', () => { + const ViewClass = Whisper.View.extend({ template: '
static text
', }); - var view = new viewClass(); + const view = new ViewClass(); view.render(); assert.strictEqual(view.$el.html(), '
static text
'); }); - it('renders a template function with render_attributes function', function() { - var viewClass = Whisper.View.extend({ - template: function() { + it('renders a template function with render_attributes function', () => { + const ViewClass = Whisper.View.extend({ + template() { return '
{{ variable }}
'; }, - render_attributes: function() { + render_attributes() { return { variable: 'value' }; }, }); - var view = new viewClass(); + const view = new ViewClass(); view.render(); assert.strictEqual(view.$el.html(), '
value
'); });