').append(view.$el);
message.destroy();
assert.strictEqual(div.find(view.$el).length, 0);
@@ -58,7 +58,7 @@ describe('MessageView', function() {
it('allows links', function() {
var url = 'http://example.com';
message.set('body', url);
- var view = new Whisper.MessageView({model: message});
+ var view = new Whisper.MessageView({ model: message });
view.render();
var link = view.$el.find('.body a');
assert.strictEqual(link.length, 1);
@@ -69,7 +69,7 @@ describe('MessageView', function() {
it('disallows xss', function() {
var xss = '';
message.set('body', xss);
- var view = new Whisper.MessageView({model: message});
+ var view = new Whisper.MessageView({ model: message });
view.render();
assert.include(view.$el.text(), xss); // should appear as escaped text
assert.strictEqual(view.$el.find('script').length, 0); // should not appear as html
@@ -77,11 +77,14 @@ describe('MessageView', function() {
it('supports emoji', function() {
message.set('body', 'I \u2764\uFE0F emoji!');
- var view = new Whisper.MessageView({model: message});
+ var view = new Whisper.MessageView({ model: message });
view.render();
var img = view.$el.find('.content img');
assert.strictEqual(img.length, 1);
- assert.strictEqual(img.attr('src'), 'node_modules/emoji-datasource-apple/img/apple/64/2764-fe0f.png');
+ assert.strictEqual(
+ img.attr('src'),
+ 'node_modules/emoji-datasource-apple/img/apple/64/2764-fe0f.png'
+ );
assert.strictEqual(img.attr('title'), ':heart:');
assert.strictEqual(img.attr('class'), 'emoji');
});
diff --git a/test/views/network_status_view_test.js b/test/views/network_status_view_test.js
index 2834c7c02c0c..d4f5e5798bdc 100644
--- a/test/views/network_status_view_test.js
+++ b/test/views/network_status_view_test.js
@@ -1,163 +1,186 @@
-
describe('NetworkStatusView', function() {
- describe('getNetworkStatus', function() {
- var networkStatusView;
- var socketStatus = WebSocket.OPEN;
+ describe('getNetworkStatus', function() {
+ var networkStatusView;
+ var socketStatus = WebSocket.OPEN;
- var oldGetSocketStatus;
+ var oldGetSocketStatus;
- /* BEGIN stubbing globals */
- before(function() {
- oldGetSocketStatus = window.getSocketStatus;
- window.getSocketStatus = function() { return socketStatus; };
- });
-
- after(function() {
- 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; };
- });
- /* END stubbing globals */
-
- beforeEach(function() {
- networkStatusView = new Whisper.NetworkStatusView();
- $('.network-status-container').append(networkStatusView.el);
- });
- afterEach(function() {
- // 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() {
- assert.equal(networkStatusView.socketReconnectWaitDuration.asSeconds(), 0);
- });
- });
- describe('network status with no connection', function() {
- beforeEach(function() {
- networkStatusView.navigatorOnLine = function() { return false; };
- });
- it('should be interrupted', function() {
- networkStatusView.update();
- var status = networkStatusView.getNetworkStatus();
- assert(status.hasInterruption);
- assert.equal(status.instructions, "Check your network connection.");
- });
- it('should display an offline message', function() {
- networkStatusView.update();
- assert.match(networkStatusView.$el.text(), /Offline/);
- });
- it('should override socket status', function() {
- _([WebSocket.CONNECTING,
- WebSocket.OPEN,
- WebSocket.CLOSING,
- WebSocket.CLOSED]).map(function(socketStatusVal) {
- socketStatus = socketStatusVal;
- networkStatusView.update();
- assert.match(networkStatusView.$el.text(), /Offline/);
- });
- });
- it('should override registration status', function() {
- Whisper.Registration.remove();
- networkStatusView.update();
- assert.match(networkStatusView.$el.text(), /Offline/);
- });
- });
- describe('network status when registration is not done', function() {
- beforeEach(function() {
- Whisper.Registration.remove();
- });
- it('should display an unlinked message', function() {
- networkStatusView.update();
- assert.match(networkStatusView.$el.text(), /Relink/);
- });
- it('should override socket status', function() {
- _([WebSocket.CONNECTING,
- WebSocket.OPEN,
- WebSocket.CLOSING,
- WebSocket.CLOSED]).map(function(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; };
- Whisper.Registration.markDone();
- networkStatusView.update();
- });
- it('should not display an unlinked message', function() {
- networkStatusView.update();
- assert.notMatch(networkStatusView.$el.text(), /Relink/);
- });
- });
- describe('network status when socket is connecting', function() {
- beforeEach(function() {
- 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() {
- networkStatusView.withinConnectingGracePeriod = false;
- var status = networkStatusView.getNetworkStatus();
-
- assert.match(networkStatusView.$el.text(), /Connecting/);
- });
- it('it should not be interrupted if in connecting grace period', function() {
- assert(networkStatusView.withinConnectingGracePeriod);
- var status = networkStatusView.getNetworkStatus();
-
- assert.match(networkStatusView.$el.text(), /Connecting/);
- assert(!status.hasInterruption);
- });
- it('it should be interrupted if connecting grace period is over', function() {
- networkStatusView.withinConnectingGracePeriod = false;
- var status = networkStatusView.getNetworkStatus();
-
- assert(status.hasInterruption);
- });
- });
- describe('network status when socket is open', function() {
- before(function() {
- socketStatus = WebSocket.OPEN;
- });
- it('should not be interrupted', function() {
- var status = networkStatusView.getNetworkStatus();
- assert(!status.hasInterruption);
- assert.match(networkStatusView.$el.find('.network-status-message').text().trim(), /^$/);
- });
- });
- describe('network status when socket is closed or closing', function() {
- _([WebSocket.CLOSED, WebSocket.CLOSING]).map(function(socketStatusVal) {
- it('should be interrupted', function() {
- socketStatus = socketStatusVal;
- networkStatusView.update();
- var status = networkStatusView.getNetworkStatus();
- assert(status.hasInterruption);
- });
-
- });
- });
- describe('the socket reconnect interval', function() {
- beforeEach(function() {
- socketStatus = WebSocket.CLOSED;
- networkStatusView.setSocketReconnectInterval(61000);
- networkStatusView.update();
- });
- it('should format the message based on the socketReconnectWaitDuration property', function() {
- assert.equal(networkStatusView.socketReconnectWaitDuration.asSeconds(), 61);
- assert.match(networkStatusView.$('.network-status-message:last').text(), /Attempting reconnect/);
- });
- it('should be reset by changing the socketStatus to CONNECTING', function() {
-
- });
- });
+ /* BEGIN stubbing globals */
+ before(function() {
+ oldGetSocketStatus = window.getSocketStatus;
+ window.getSocketStatus = function() {
+ return socketStatus;
+ };
});
+
+ after(function() {
+ 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;
+ };
+ });
+ /* END stubbing globals */
+
+ beforeEach(function() {
+ networkStatusView = new Whisper.NetworkStatusView();
+ $('.network-status-container').append(networkStatusView.el);
+ });
+ afterEach(function() {
+ // 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() {
+ assert.equal(
+ networkStatusView.socketReconnectWaitDuration.asSeconds(),
+ 0
+ );
+ });
+ });
+ describe('network status with no connection', function() {
+ beforeEach(function() {
+ networkStatusView.navigatorOnLine = function() {
+ return false;
+ };
+ });
+ it('should be interrupted', function() {
+ networkStatusView.update();
+ var status = networkStatusView.getNetworkStatus();
+ assert(status.hasInterruption);
+ assert.equal(status.instructions, 'Check your network connection.');
+ });
+ it('should display an offline message', function() {
+ networkStatusView.update();
+ assert.match(networkStatusView.$el.text(), /Offline/);
+ });
+ it('should override socket status', function() {
+ _([
+ WebSocket.CONNECTING,
+ WebSocket.OPEN,
+ WebSocket.CLOSING,
+ WebSocket.CLOSED,
+ ]).map(function(socketStatusVal) {
+ socketStatus = socketStatusVal;
+ networkStatusView.update();
+ assert.match(networkStatusView.$el.text(), /Offline/);
+ });
+ });
+ it('should override registration status', function() {
+ Whisper.Registration.remove();
+ networkStatusView.update();
+ assert.match(networkStatusView.$el.text(), /Offline/);
+ });
+ });
+ describe('network status when registration is not done', function() {
+ beforeEach(function() {
+ Whisper.Registration.remove();
+ });
+ it('should display an unlinked message', function() {
+ networkStatusView.update();
+ assert.match(networkStatusView.$el.text(), /Relink/);
+ });
+ it('should override socket status', function() {
+ _([
+ WebSocket.CONNECTING,
+ WebSocket.OPEN,
+ WebSocket.CLOSING,
+ WebSocket.CLOSED,
+ ]).map(function(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;
+ };
+ Whisper.Registration.markDone();
+ networkStatusView.update();
+ });
+ it('should not display an unlinked message', function() {
+ networkStatusView.update();
+ assert.notMatch(networkStatusView.$el.text(), /Relink/);
+ });
+ });
+ describe('network status when socket is connecting', function() {
+ beforeEach(function() {
+ 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() {
+ networkStatusView.withinConnectingGracePeriod = false;
+ var status = networkStatusView.getNetworkStatus();
+
+ assert.match(networkStatusView.$el.text(), /Connecting/);
+ });
+ it('it should not be interrupted if in connecting grace period', function() {
+ assert(networkStatusView.withinConnectingGracePeriod);
+ var status = networkStatusView.getNetworkStatus();
+
+ assert.match(networkStatusView.$el.text(), /Connecting/);
+ assert(!status.hasInterruption);
+ });
+ it('it should be interrupted if connecting grace period is over', function() {
+ networkStatusView.withinConnectingGracePeriod = false;
+ var status = networkStatusView.getNetworkStatus();
+
+ assert(status.hasInterruption);
+ });
+ });
+ describe('network status when socket is open', function() {
+ before(function() {
+ socketStatus = WebSocket.OPEN;
+ });
+ it('should not be interrupted', function() {
+ var status = networkStatusView.getNetworkStatus();
+ assert(!status.hasInterruption);
+ assert.match(
+ networkStatusView.$el
+ .find('.network-status-message')
+ .text()
+ .trim(),
+ /^$/
+ );
+ });
+ });
+ describe('network status when socket is closed or closing', function() {
+ _([WebSocket.CLOSED, WebSocket.CLOSING]).map(function(socketStatusVal) {
+ it('should be interrupted', function() {
+ socketStatus = socketStatusVal;
+ networkStatusView.update();
+ var status = networkStatusView.getNetworkStatus();
+ assert(status.hasInterruption);
+ });
+ });
+ });
+ describe('the socket reconnect interval', function() {
+ beforeEach(function() {
+ socketStatus = WebSocket.CLOSED;
+ networkStatusView.setSocketReconnectInterval(61000);
+ networkStatusView.update();
+ });
+ it('should format the message based on the socketReconnectWaitDuration property', function() {
+ assert.equal(
+ networkStatusView.socketReconnectWaitDuration.asSeconds(),
+ 61
+ );
+ assert.match(
+ networkStatusView.$('.network-status-message:last').text(),
+ /Attempting reconnect/
+ );
+ });
+ it('should be reset by changing the socketStatus to CONNECTING', function() {});
+ });
+ });
});
diff --git a/test/views/scroll_down_button_view_test.js b/test/views/scroll_down_button_view_test.js
index eb8787ad094a..7d1ccc6f23d3 100644
--- a/test/views/scroll_down_button_view_test.js
+++ b/test/views/scroll_down_button_view_test.js
@@ -2,37 +2,37 @@
* vim: ts=4:sw=4:expandtab
*/
describe('ScrollDownButtonView', function() {
- it('renders with count = 0', function() {
- var view = new Whisper.ScrollDownButtonView();
- view.render();
- assert.equal(view.count, 0);
- assert.match(view.$el.html(), /Scroll to bottom/);
- });
+ it('renders with count = 0', function() {
+ var 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});
- view.render();
- assert.equal(view.count, 1);
- assert.match(view.$el.html(), /new-messages/);
- assert.match(view.$el.html(), /New message below/);
- });
+ it('renders with count = 1', function() {
+ var view = new Whisper.ScrollDownButtonView({ count: 1 });
+ view.render();
+ assert.equal(view.count, 1);
+ assert.match(view.$el.html(), /new-messages/);
+ assert.match(view.$el.html(), /New message below/);
+ });
- it('renders with count = 2', function() {
- var view = new Whisper.ScrollDownButtonView({count: 2});
- view.render();
- assert.equal(view.count, 2);
+ it('renders with count = 2', function() {
+ var view = new Whisper.ScrollDownButtonView({ count: 2 });
+ view.render();
+ assert.equal(view.count, 2);
- assert.match(view.$el.html(), /new-messages/);
- assert.match(view.$el.html(), /New messages below/);
- });
+ assert.match(view.$el.html(), /new-messages/);
+ assert.match(view.$el.html(), /New messages below/);
+ });
- it('increments count and re-renders', function() {
- var view = new Whisper.ScrollDownButtonView();
- view.render();
- assert.equal(view.count, 0);
- assert.notMatch(view.$el.html(), /new-messages/);
- view.increment(1);
- assert.equal(view.count, 1);
- assert.match(view.$el.html(), /new-messages/);
- });
+ it('increments count and re-renders', function() {
+ var view = new Whisper.ScrollDownButtonView();
+ view.render();
+ assert.equal(view.count, 0);
+ assert.notMatch(view.$el.html(), /new-messages/);
+ view.increment(1);
+ assert.equal(view.count, 1);
+ assert.match(view.$el.html(), /new-messages/);
+ });
});
diff --git a/test/views/threads_test.js b/test/views/threads_test.js
index b0dcf3df2f13..729d8be4ab36 100644
--- a/test/views/threads_test.js
+++ b/test/views/threads_test.js
@@ -3,12 +3,11 @@
*/
describe('Threads', function() {
-
it('should be ordered newest to oldest', function() {
// Timestamps
var today = new Date();
var tomorrow = new Date();
- tomorrow.setDate(today.getDate()+1);
+ tomorrow.setDate(today.getDate() + 1);
// Add threads
Whisper.Threads.add({ timestamp: today });
@@ -21,6 +20,4 @@ describe('Threads', function() {
// Compare timestamps
assert(firstTimestamp > secondTimestamp);
});
-
-
});
diff --git a/test/views/timestamp_view_test.js b/test/views/timestamp_view_test.js
index bf426926f85f..994830b37de2 100644
--- a/test/views/timestamp_view_test.js
+++ b/test/views/timestamp_view_test.js
@@ -4,122 +4,133 @@
'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();
+ 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();
- // Helper functions to check absolute and relative timestamps
+ // 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);
- assert.strictEqual(result, expected);
- };
+ // Helper to check an absolute TS for an exact match
+ var check = function(view, ts, expected) {
+ var 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);
- };
+ // 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);
+ };
- // 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;
- }
- check(brief_view, ts, expected_brief);
- check(ext_view, ts, expected_ext);
- };
+ // 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;
+ }
+ check(brief_view, ts, expected_brief);
+ check(ext_view, ts, expected_ext);
+ };
- // 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);
- assert.match(result, regexp);
- };
+ // 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);
+ assert.match(result, regexp);
+ };
- // check integer timestamp, JS Date object and moment object
- checkAbs(timestamp, 'now', 'now');
- checkAbs(new Date(), 'now', 'now');
- checkAbs(moment(), 'now', 'now');
+ // check integer timestamp, JS Date object and moment object
+ checkAbs(timestamp, 'now', 'now');
+ checkAbs(new Date(), 'now', 'now');
+ checkAbs(moment(), 'now', 'now');
- // check recent timestamps
- checkDiff(30, 'now', 'now'); // 30 seconds
- checkDiff(40*60, '40 minutes', '40 minutes ago');
- checkDiff(60*60, '1 hour', '1 hour ago');
- checkDiff(125*60, '2 hours', '2 hours ago');
+ // check recent timestamps
+ checkDiff(30, 'now', 'now'); // 30 seconds
+ checkDiff(40 * 60, '40 minutes', '40 minutes ago');
+ checkDiff(60 * 60, '1 hour', '1 hour ago');
+ 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');
+ // 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');
- // 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()]);
+ // 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()]);
- // 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 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');
+ });
+
+ describe('updates within a minute reasonable intervals', function() {
+ var view;
+ beforeEach(function() {
+ view = new Whisper.TimestampView();
+ });
+ afterEach(function() {
+ clearTimeout(view.timeout);
});
-
- describe('updates within a minute reasonable intervals', function() {
- var view;
- beforeEach(function() {
- view = new Whisper.TimestampView();
- });
- afterEach(function() {
- clearTimeout(view.timeout);
- });
-
- it('updates timestamps this minute within a minute', function() {
- var 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();
- 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();
- 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();
- 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, 24 * 60 * 60 * 1000); // day
- });
-
- it('does not updates very old timestamps', function() {
- var 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();
- assert.notOk(view.delay);
- });
-
+ it('updates timestamps this minute within a minute', function() {
+ var 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();
+ 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();
+ 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();
+ 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, 24 * 60 * 60 * 1000); // day
+ });
+
+ it('does not updates very old timestamps', function() {
+ var 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();
+ assert.notOk(view.delay);
+ });
+ });
});
diff --git a/test/views/whisper_view_test.js b/test/views/whisper_view_test.js
index 26296c0919e0..4b2b4396f394 100644
--- a/test/views/whisper_view_test.js
+++ b/test/views/whisper_view_test.js
@@ -3,8 +3,8 @@ describe('Whisper.View', function() {
var viewClass = Whisper.View.extend({
template: '
{{ variable }}
',
render_attributes: {
- variable: 'value'
- }
+ variable: 'value',
+ },
});
var view = new viewClass();
@@ -13,7 +13,7 @@ describe('Whisper.View', function() {
});
it('renders a template with no render_attributes', function() {
var viewClass = Whisper.View.extend({
- template: '
static text
'
+ template: '
static text
',
});
var view = new viewClass();
@@ -22,10 +22,12 @@ describe('Whisper.View', function() {
});
it('renders a template function with render_attributes function', function() {
var viewClass = Whisper.View.extend({
- template: function() { return '
{{ variable }}
'; },
+ template: function() {
+ return '
{{ variable }}
';
+ },
render_attributes: function() {
return { variable: 'value' };
- }
+ },
});
var view = new viewClass();
view.render();
diff --git a/ts/components/conversation/Message.tsx b/ts/components/conversation/Message.tsx
index eb484e82b124..6a9407715673 100644
--- a/ts/components/conversation/Message.tsx
+++ b/ts/components/conversation/Message.tsx
@@ -1,6 +1,5 @@
import React from 'react';
-
/**
* A placeholder Message component for now, giving the structure of a plain message with
* none of the dynamic functionality. This page will be used to build up our corpus of
diff --git a/ts/components/conversation/Quote.tsx b/ts/components/conversation/Quote.tsx
index 54365c4f54fd..b1157202af91 100644
--- a/ts/components/conversation/Quote.tsx
+++ b/ts/components/conversation/Quote.tsx
@@ -4,7 +4,6 @@ import classnames from 'classnames';
import * as MIME from '../../../ts/types/MIME';
import * as GoogleChrome from '../../../ts/util/GoogleChrome';
-
interface Props {
attachments: Array
;
authorColor: string;
@@ -54,9 +53,9 @@ function getObjectUrl(thumbnail: Attachment | undefined): string | null {
export class Quote extends React.Component {
public renderImage(url: string, icon?: string) {
- const iconElement = icon
- ?
- : null;
+ const iconElement = icon ? (
+
+ ) : null;
return (
@@ -98,9 +97,7 @@ export class Quote extends React.Component
{
: this.renderIcon('movie');
}
if (GoogleChrome.isImageTypeSupported(contentType)) {
- return objectUrl
- ? this.renderImage(objectUrl)
- : this.renderIcon('image');
+ return objectUrl ? this.renderImage(objectUrl) : this.renderIcon('image');
}
if (MIME.isAudio(contentType)) {
return this.renderIcon('microphone');
@@ -113,7 +110,9 @@ export class Quote extends React.Component {
const { i18n, text, attachments } = this.props;
if (text) {
- return ;
+ return (
+
+ );
}
if (!attachments || attachments.length === 0) {
@@ -140,7 +139,13 @@ export class Quote extends React.Component {
}
public renderIOSLabel() {
- const { i18n, isIncoming, isFromMe, authorTitle, authorProfileName } = this.props;
+ const {
+ i18n,
+ isIncoming,
+ isFromMe,
+ authorTitle,
+ authorProfileName,
+ } = this.props;
const profileString = authorProfileName ? ` ~${authorProfileName}` : '';
const authorName = `${authorTitle}${profileString}`;
@@ -185,27 +190,25 @@ export class Quote extends React.Component {
isFromMe,
} = this.props;
-
- const authorProfileElement = authorProfileName
- ? ~{authorProfileName}
- : null;
+ const authorProfileElement = authorProfileName ? (
+ ~{authorProfileName}
+ ) : null;
return (
- { isFromMe
- ? i18n('you')
- : {authorTitle}{' '}{authorProfileElement}
- }
+ {isFromMe ? (
+ i18n('you')
+ ) : (
+
+ {authorTitle} {authorProfileElement}
+
+ )}
);
}
public render() {
- const {
- authorColor,
- onClick,
- isFromMe,
- } = this.props;
+ const { authorColor, onClick, isFromMe } = this.props;
if (!validateQuote(this.props)) {
return null;
diff --git a/ts/components/utility/BackboneWrapper.tsx b/ts/components/utility/BackboneWrapper.tsx
index a57651cede90..0a3e75fe2feb 100644
--- a/ts/components/utility/BackboneWrapper.tsx
+++ b/ts/components/utility/BackboneWrapper.tsx
@@ -14,7 +14,7 @@ interface BackboneView {
}
interface BackboneViewConstructor {
- new (options: object): BackboneView;
+ new (options: object): BackboneView;
}
/**
@@ -41,7 +41,7 @@ export class BackboneWrapper extends React.Component {
protected setEl = (element: HTMLDivElement | null) => {
this.el = element;
this.setup();
- }
+ };
protected setup = () => {
const { el } = this;
@@ -56,7 +56,7 @@ export class BackboneWrapper extends React.Component {
// It's important to let the view create its own root DOM element. This ensures that
// its tagName property actually takes effect.
el.appendChild(this.view.el);
- }
+ };
protected teardown() {
if (!this.view) {
diff --git a/ts/html/index.ts b/ts/html/index.ts
index 3aad63218f0c..7121781bc8d3 100644
--- a/ts/html/index.ts
+++ b/ts/html/index.ts
@@ -1,6 +1,5 @@
import linkTextInternal from '../../js/modules/link_text';
-
export const linkText = (value: string): string =>
linkTextInternal(value, { target: '_blank' });
diff --git a/ts/styleguide/ConversationContext.tsx b/ts/styleguide/ConversationContext.tsx
index 139dd8a1e6bf..dba62ce9c5e5 100644
--- a/ts/styleguide/ConversationContext.tsx
+++ b/ts/styleguide/ConversationContext.tsx
@@ -1,7 +1,6 @@
import React from 'react';
import classnames from 'classnames';
-
interface Props {
/**
* Corresponds to the theme setting in the app, and the class added to the root element.
@@ -21,10 +20,8 @@ export class ConversationContext extends React.Component {
return (
-
-
- {this.props.children}
-
+
diff --git a/ts/styleguide/StyleGuideUtil.ts b/ts/styleguide/StyleGuideUtil.ts
index bdf0ab3bf4c2..ecba629d8faa 100644
--- a/ts/styleguide/StyleGuideUtil.ts
+++ b/ts/styleguide/StyleGuideUtil.ts
@@ -1,9 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom';
-import {
- padStart,
- sample,
-} from 'lodash';
+import { padStart, sample } from 'lodash';
import _ from 'lodash';
import moment from 'moment';
@@ -58,7 +55,6 @@ const landscapeRedObjectUrl = makeObjectUrl(landscapeRed, 'image/png');
import portraitTeal from '../../fixtures/50x1000-teal.jpeg';
const portraitTealObjectUrl = makeObjectUrl(portraitTeal, 'image/png');
-
function makeObjectUrl(data: ArrayBuffer, contentType: string): string {
const blob = new Blob([data], {
type: contentType,
@@ -69,7 +65,6 @@ function makeObjectUrl(data: ArrayBuffer, contentType: string): string {
const ourNumber = '+12025559999';
const groupNumber = '+12025550099';
-
export {
mp3,
mp3ObjectUrl,
@@ -93,7 +88,6 @@ export {
groupNumber,
};
-
// Required, or TypeScript complains about adding keys to window
const parent = window as any;
@@ -112,12 +106,7 @@ import filesize from 'filesize';
const i18n = setup(locale, localeMessages);
-export {
- theme,
- locale,
- i18n,
-};
-
+export { theme, locale, i18n };
parent.i18n = i18n;
parent.moment = moment;
@@ -145,7 +134,6 @@ parent.filesize = filesize;
parent.ConversationController._initialFetchComplete = true;
parent.ConversationController._initialPromise = Promise.resolve();
-
const COLORS = [
'red',
'pink',
@@ -199,12 +187,7 @@ group.contactCollection.add(CONTACTS[0]);
group.contactCollection.add(CONTACTS[1]);
group.contactCollection.add(CONTACTS[2]);
-export {
- COLORS,
- CONTACTS,
- me,
- group,
-};
+export { COLORS, CONTACTS, me, group };
parent.textsecure.storage.user.getNumber = () => ourNumber;
diff --git a/ts/test/types/Conversation_test.ts b/ts/test/types/Conversation_test.ts
index f5aea6fc6aac..67187f10ab37 100644
--- a/ts/test/types/Conversation_test.ts
+++ b/ts/test/types/Conversation_test.ts
@@ -32,10 +32,10 @@ describe('Conversation', () => {
currentLastMessageText: 'Existing message',
currentTimestamp: 555,
lastMessage: {
- type: 'outgoing',
- conversationId: 'foo',
- sent_at: 666,
- timestamp: 666,
+ type: 'outgoing',
+ conversationId: 'foo',
+ sent_at: 666,
+ timestamp: 666,
} as OutgoingMessage,
lastMessageNotificationText: 'New outgoing message',
};
@@ -54,10 +54,10 @@ describe('Conversation', () => {
currentLastMessageText: 'bingo',
currentTimestamp: 555,
lastMessage: {
- type: 'verified-change',
- conversationId: 'foo',
- sent_at: 666,
- timestamp: 666,
+ type: 'verified-change',
+ conversationId: 'foo',
+ sent_at: 666,
+ timestamp: 666,
} as VerifiedChangeMessage,
lastMessageNotificationText: 'Verified Changed',
};
@@ -77,15 +77,15 @@ describe('Conversation', () => {
currentLastMessageText: 'I am expired',
currentTimestamp: 555,
lastMessage: {
- type: 'incoming',
- conversationId: 'foo',
- sent_at: 666,
- timestamp: 666,
- expirationTimerUpdate: {
- expireTimer: 111,
- fromSync: false,
- source: '+12223334455',
- },
+ type: 'incoming',
+ conversationId: 'foo',
+ sent_at: 666,
+ timestamp: 666,
+ expirationTimerUpdate: {
+ expireTimer: 111,
+ fromSync: false,
+ source: '+12223334455',
+ },
} as IncomingMessage,
lastMessageNotificationText: 'Last message before expired',
};
diff --git a/ts/test/types/message/initializeAttachmentMetadata_test.ts b/ts/test/types/message/initializeAttachmentMetadata_test.ts
index 2979f13f9f76..d76618f280bb 100644
--- a/ts/test/types/message/initializeAttachmentMetadata_test.ts
+++ b/ts/test/types/message/initializeAttachmentMetadata_test.ts
@@ -7,7 +7,6 @@ import { MIMEType } from '../../../../ts/types/MIME';
// @ts-ignore
import { stringToArrayBuffer } from '../../../../js/modules/string_to_array_buffer';
-
describe('Message', () => {
describe('initializeAttachmentMetadata', () => {
it('should handle visual media attachments', async () => {
@@ -18,12 +17,14 @@ describe('Message', () => {
timestamp: 1523317140899,
received_at: 1523317140899,
sent_at: 1523317140800,
- attachments: [{
- contentType: 'image/jpeg' as MIMEType,
- data: stringToArrayBuffer('foo'),
- fileName: 'foo.jpg',
- size: 1111,
- }],
+ attachments: [
+ {
+ contentType: 'image/jpeg' as MIMEType,
+ data: stringToArrayBuffer('foo'),
+ fileName: 'foo.jpg',
+ size: 1111,
+ },
+ ],
};
const expected: IncomingMessage = {
type: 'incoming',
@@ -32,12 +33,14 @@ describe('Message', () => {
timestamp: 1523317140899,
received_at: 1523317140899,
sent_at: 1523317140800,
- attachments: [{
- contentType: 'image/jpeg' as MIMEType,
- data: stringToArrayBuffer('foo'),
- fileName: 'foo.jpg',
- size: 1111,
- }],
+ attachments: [
+ {
+ contentType: 'image/jpeg' as MIMEType,
+ data: stringToArrayBuffer('foo'),
+ fileName: 'foo.jpg',
+ size: 1111,
+ },
+ ],
hasAttachments: 1,
hasVisualMediaAttachments: 1,
hasFileAttachments: undefined,