Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,160 @@
define(function(require) {
'use strict';
var CalendarError = require('common/error');
var ErrorController = require('controllers/error');
var Factory = require('test/support/factory');
var Responder = require('common/responder');
var core = require('core');
var nextTick = require('common/next_tick');
var notification = require('notification');
suite('controllers/error', function() {
/**
* Because of uplifting difficulties I chose to copy/paste
* the following code rather then attempt to uplift related testing fixes...
* I may later live to regret this but given the short time we have until
* shipping v1.0.1 I have chosen to copy/paste.
*/
function mockRequestWakeLock(handler) {
var realApi;
function lockMock() {
return {
mAquired: false,
mIsUnlocked: false,
unlock: function() {
this.mIsUnlocked = true;
}
};
}
suiteSetup(function() {
realApi = navigator.requestWakeLock;
navigator.requestWakeLock = function(type) {
var lock = lockMock();
lock.type = type;
lock.mAquired = true;
handler && handler(lock);
return lock;
};
});
suiteTeardown(function() {
navigator.requestWakeLock = realApi;
});
}
var subject;
var detail;
setup(function(done) {
testSupport.calendar.core();
subject = new ErrorController();
core.db.open(done);
detail = {
account: Factory('account')
};
});
teardown(function(done) {
testSupport.calendar.clearStore(
core.db,
['accounts'],
function() {
core.db.close();
done();
}
);
});
test('initialization', function() {
assert.instanceOf(subject, Responder);
});
suite('default handling', function() {
test('authenticate', function(done) {
var callsAuth = false;
var error = new CalendarError.Authentication(detail);
subject.handleAuthenticate = function(account) {
assert.equal(account, detail.account, 'sends account');
callsAuth = true;
};
subject.once('error', function(givenErr) {
done(function() {
assert.ok(callsAuth);
assert.equal(error, givenErr, 'sends error');
});
});
subject.dispatch(error);
});
});
test('.accountErrorUrl', function() {
assert.ok(subject.accountErrorUrl);
});
suite('#handleAuthenticate', function() {
var sent;
var account;
var lock;
mockRequestWakeLock(function(_lock) {
lock = _lock;
});
var realSendApi;
suiteSetup(function() {
realSendApi = notification.sendNotification;
notification.sendNotification = function() {
sent = Array.slice(arguments);
return Promise.resolve();
};
});
suiteTeardown(function() {
notification.sendNotification = realSendApi;
});
setup(function() {
sent = null;
lock = null;
account = Factory('account', { _id: 'woot' });
});
test('with count 1', function(done) {
var expectedURL = subject.accountErrorUrl + account._id;
account.error = { count: 1 };
subject.handleAuthenticate(account, function() {
nextTick(function() {
done(function() {
assert.ok(lock.mIsUnlocked, 'unlocks');
assert.ok(sent, 'sends notification');
assert.equal(sent[2], expectedURL, 'sends to modify account');
});
});
});
assert.ok(lock, 'aquires lock');
});
test('with count 2', function(done) {
account.error = { count: 2 };
subject.handleAuthenticate(account, function() {
done(function() {
assert.ok(!lock, 'does not aquire lock');
assert.ok(!sent, 'does not resend error');
});
});
});
});
});
});

View file

@ -0,0 +1,122 @@
define(function(require) {
'use strict';
/* global MockMozIntl */
require('/shared/test/unit/mocks/mock_moz_intl.js');
var Factory = require('test/support/factory');
var mockRequestWakeLock = require('test/support/mock_request_wake_lock');
var controller = require('controllers/notifications');
var core = require('core');
var mochaPromise = require('test/support/mocha_promise');
var notification = require('notification');
var waitFor = require('test/support/wait_for');
suite('controllers/notifications', function() {
var alarm;
var db;
var sendNotification;
var storeFactory;
setup(function() {
window.mozIntl = MockMozIntl;
mockRequestWakeLock.setup();
sendNotification = sinon.spy(notification, 'sendNotification');
});
setup(function(done) {
storeFactory = core.storeFactory;
db = core.db;
db.open(done);
});
setup(function(done) {
var start = new Date();
var end = new Date();
end.setHours(end.getHours() + 1);
// Inject event, busytime, and alarm into db.
var event = Factory('event', {
_id: 'event-one',
remote: {
title: 'Birthday',
startDate: start,
endDate: end
}
});
event.description = null;
event.remote.description = null;
var busytime = Factory('busytime', {
eventId: 'event-one',
startDate: start,
endDate: end,
_id: 'busytime-one'
});
alarm = Factory('alarm', {
eventId: 'event-one',
busytimeId: 'busytime-one',
_id: 'alarm-one'
});
var eventStore = storeFactory.get('Event');
var busytimeStore = storeFactory.get('Busytime');
var alarmStore = storeFactory.get('Alarm');
Promise.all([
eventStore.persist(event),
busytimeStore.persist(busytime),
alarmStore.persist(alarm)
])
.then(() => done());
});
teardown(function() {
sendNotification.restore();
mockRequestWakeLock.teardown();
});
teardown(function(done) {
testSupport.calendar.clearStore(db, [
'events',
'busytimes',
'alarms'
], done);
});
teardown(function() {
db.close();
});
suite('#onAlarm', function() {
mochaPromise(test, 'cpu lock', function() {
controller.onAlarm(alarm);
return waitFor(function() {
var locks = mockRequestWakeLock.locks;
var lock = locks[0];
return lock && lock.type === 'cpu' && lock.unlocked;
});
});
mochaPromise(test, 'should send alarm notification', function() {
controller.onAlarm(alarm);
return waitFor(function() {
// Notably, even though our event description was null, we don't pass on
// 'null' to the notification body.
return sendNotification.calledWith(
{
id: 'alarm-started-notice',
args: { title: 'Birthday', distance: 'pretty date' }
},
{ raw: '' }
);
});
});
});
});
});

View file

@ -0,0 +1,153 @@
/**
* TODO(gareth): It would be really wonderful for the interactions
* with the account store to be real (not stubbed) but there
* is currently some bizarreness around testSupport.calendar.dbFixtures
* which needs to be addressed first.
*/
define(function(require) {
'use strict';
var createDOMPromise = require('common/create_dom_promise');
var mockAlarms = require('test/support/mock_alarms');
var periodicSync = require('controllers/periodic_sync');
suite('controllers/periodic_sync', function() {
var db, storeFactory;
setup(function(done) {
mockAlarms.setup();
var core = testSupport.calendar.core();
db = core.db;
storeFactory = core.storeFactory;
db.open(done);
});
teardown(function() {
mockAlarms.teardown();
db.close();
});
test('mozAlarms mock', function(done) {
mockAlarms.add(new Date(), 'ignoreTimezone', { type: 'sync' });
createDOMPromise(mockAlarms.getAll())
.should
.eventually
.have
.length(1)
.notify(done);
});
suite('periodic sync', function() {
var settings;
setup(function(done) {
settings = storeFactory.get('Setting');
settings.set('syncFrequency', 1).then(() => done());
});
setup(function(done) {
periodicSync.observe().then(() => done());
});
teardown(function() {
settings._clearCache();
});
teardown(function(done) {
testSupport.calendar.clearStore(db, [ 'settings' ], done);
});
teardown(function() {
periodicSync.unobserve();
});
suite('without initial caldav calendar', function() {
setup(function() {
var accounts = storeFactory.get('Account');
sinon.stub(accounts, 'syncableAccounts').returns(Promise.resolve([]));
});
teardown(function() {
var accounts = storeFactory.get('Account');
accounts.syncableAccounts.restore();
});
test('should not schedule sync initially', function(done) {
createDOMPromise(mockAlarms.getAll())
.should
.eventually
.have
.length(0)
.notify(done);
});
});
suite('with initial caldav calendar', function() {
setup(function() {
var accounts = storeFactory.get('Account');
sinon.stub(accounts, 'syncableAccounts').returns(Promise.resolve([
{ _id: 'one', providerType: 'Caldav' }
]));
});
setup(function(done) {
periodicSync.events.once('schedule', () => done());
var accounts = storeFactory.get('Account');
accounts.emit('persist');
});
teardown(function() {
var accounts = storeFactory.get('Account');
accounts.syncableAccounts.restore();
});
test('should schedule sync initially', function(done) {
createDOMPromise(mockAlarms.getAll())
.should
.eventually
.have
.length(1)
.notify(done);
});
test('sync interval change revokes previous alarm', function(done) {
var first;
periodicSync.events.once('schedule', () => {
var getAll = createDOMPromise(mockAlarms.getAll());
getAll.then(result => {
assert.lengthOf(result, 1);
var alarm = result[0];
assert.notStrictEqual(alarm.alarmId, first);
done();
});
});
var getAll = createDOMPromise(mockAlarms.getAll());
getAll.then(result => {
var alarm = result[0];
first = alarm.alarmId;
var settings = storeFactory.get('Setting');
settings.set('syncFrequency', 2);
});
});
test('removing last caldav account should stop sync', function(done) {
periodicSync.events.on('pause', () => {
var getAll = createDOMPromise(mockAlarms.getAll());
getAll.then(result => {
assert.lengthOf(result, 0);
done();
});
});
var accounts = storeFactory.get('Account');
accounts.syncableAccounts.restore();
sinon.stub(accounts, 'syncableAccounts').returns(Promise.resolve([]));
accounts.emit('remove');
});
});
});
});
});

View file

@ -0,0 +1,305 @@
define(function(require) {
'use strict';
var Factory = require('test/support/factory');
var RecurringEvents = require('controllers/recurring_events');
var Responder = require('common/responder');
var core = require('core');
var nextTick = require('common/next_tick');
suite('Controllers.RecurringEvents', function() {
var db;
var storeFactory;
var subject;
var syncController;
var timeController;
setup(function(done) {
db = core.db;
storeFactory = core.storeFactory;
syncController = core.syncController;
timeController = core.timeController;
subject = new RecurringEvents();
db.open(done);
});
teardown(function(done) {
subject.unobserve();
testSupport.calendar.clearStore(
db,
['accounts'],
function() {
done(function() {
db.close();
});
}
);
});
test('initialization', function() {
assert.instanceOf(subject, Responder);
});
test('#observe', function() {
var date = new Date(2012, 1, 1);
timeController.move(date);
var expandCall;
subject.queueExpand = function(date) {
expandCall = date;
};
subject.observe();
assert.deepEqual(expandCall, date, 'expands initial time');
});
suite('controller events', function() {
var date = new Date(2012, 1, 1);
setup(function(done) {
subject.observe();
subject.waitBeforeMove = 10;
timeController.move(date);
subject.once('expandComplete', done);
});
test('syncComplete', function(done) {
subject.queueExpand = function(date) {
done(function() {
assert.deepEqual(timeController.position, date);
});
};
syncController.emit('syncComplete');
});
/*
// These tests are currently failing and have been temporarily disabled as per
// Bug 838993. They should be fixed and re-enabled as soon as possible as per
// Bug 840489.
test('monthChange', function(done) {
var expectedDate = new Date(2012, 10, 1);
// modify wait before move for faster tests.
subject.queueExpand = function(date) {
done(function() {
assert.deepEqual(expectedDate, date);
});
};
timeController.move(new Date(2012, 8, 1));
timeController.move(new Date(2012, 9, 1));
Calendar.nextTick(function() {
timeController.move(expectedDate);
});
});
*/
});
suite('#queueExpand', function() {
var expandCalls;
var expandStartEvents;
setup(function() {
expandCalls = [];
subject.expand = function(date, cb) {
expandCalls.push([date, cb]);
};
expandStartEvents = 0;
subject.on('expandStart', function() {
expandStartEvents++;
});
});
test('multiple expansions', function(done) {
var dates = [];
subject.once('expandComplete', function() {
done(function() {
assert.equal(expandStartEvents, 1, 'calls expand once');
assert.deepEqual(
dates,
[
new Date(2012, 1, 1),
new Date(2012, 8, 1),
new Date(2012, 10, 7)
]
);
});
});
subject.expand = function(date, cb) {
dates.push(date);
nextTick(cb);
};
// should actually trigger because its the first
// item in the queue...
subject.queueExpand(new Date(2012, 1, 1));
nextTick(function() {
subject.queueExpand(new Date(2012, 7, 7));
});
// should be skipped because the next is greater and
// we are still processing the first item in th queue.
subject.queueExpand(new Date(2012, 2, 7));
// queued
subject.queueExpand(new Date(2012, 8, 1));
// should be skipped its less then others
subject.queueExpand(new Date(2012, 1, 2));
nextTick(function() {
// after the second expansion this fires
// so should the final expansion this tests
// some complicated async ordering.
subject.queueExpand(new Date(2012, 10, 7));
});
});
test('single expand', function(done) {
var date = new Date(2012, 1, 7);
subject.once('expandComplete', function() {
done(function() {
assert.ok(!subject.pending);
assert.equal(expandStartEvents, 1);
});
});
subject.queueExpand(date);
assert.ok(subject.pending);
assert.lengthOf(expandCalls, 1);
// verify right date is being expanded.
assert.deepEqual(expandCalls[0][0], date);
// trigger callback
expandCalls[0][1]();
});
});
suite('#expand', function() {
var account;
var provider;
var expandDate = new Date(2012, 1, 1);
var expectedDate;
setup(function() {
expectedDate = new Date(expandDate.valueOf());
expectedDate.setDate(expectedDate.getDate() + subject.paddingInDays);
});
function setupProvider(type, id) {
setup(function(done) {
account = Factory('account', {
providerType: type,
_id: id || type
});
provider = core.providerFactory.get(type);
storeFactory.get('Account').persist(account, done);
});
}
test('with no accounts', function(done) {
subject.expand(expandDate, done);
});
suite('provider that cannot expand', function() {
setupProvider('Local');
test('will not expand', function(done) {
provider.ensureRecurrencesExpanded = function() {
throw new Error('local should not expand');
};
subject.expand(expandDate, done);
});
});
suite('provider that can expand', function() {
// two caldav accounts to catch duplicate busytimes error (Bug 1018833)
setupProvider('Caldav', 1);
setupProvider('Caldav', 2);
// custom helper to allow each test
// to inject specific logic while sharing the
// spy/mock easily... override spyHandler to use.
var spyHandler;
// number of times ensureRecurrencesExpanded was called.
var calledEnsure;
setup(function() {
spyHandler = null;
calledEnsure = 0;
provider.ensureRecurrencesExpanded = function(date, cb) {
calledEnsure++;
// we use the same date for all tests
assert.deepEqual(date, expectedDate);
if (!spyHandler) {
setTimeout(cb, 0, null, false);
} else {
spyHandler(cb);
}
};
});
test('with no expansions required', function(done) {
subject.expand(expandDate, function() {
done(function() {
assert.equal(calledEnsure, 1, 'calls ensure');
});
});
});
test('multiple expansions required', function(done) {
// expected number of times
var requiredTries = 3;
spyHandler = function(cb) {
if (calledEnsure === requiredTries) {
// did not expand
setTimeout(cb, 0, null, false);
} else {
// did expand
setTimeout(cb, 0, null, true);
}
};
subject.expand(expandDate, function() {
done(function() {
assert.equal(calledEnsure, requiredTries, 'number of tries');
});
});
});
test('expand beyond maximum', function(done) {
spyHandler = function(cb) {
nextTick(cb.bind(this, null, true));
};
subject.expand(expandDate, function() {
done(function() {
assert.equal(calledEnsure, subject.maximumExpansions);
});
});
});
});
});
});
});

View file

@ -0,0 +1,47 @@
define(function(require) {
'use strict';
var Manager = require('worker/manager');
var ServiceController = require('controllers/service');
suite('Controllers.Service', function() {
var subject;
setup(function() {
subject = new ServiceController();
});
test('initialize', function() {
assert.instanceOf(subject, Manager);
});
test('#start', function() {
subject.start();
assert.ok(subject._ensureActiveWorker('caldav'));
});
/*
// These tests are currently failing and have been temporarily disabled as per
// Bug 838993. They should be fixed and re-enabled as soon as possible as per
// Bug 840489.
test('caldav worker', function(done) {
subject.start();
subject.request('caldav', 'noop', function(data) {
done(function() {
assert.deepEqual(data, { ready: true });
});
});
});
*/
teardown(function() {
subject.workers.forEach(function(worker) {
worker.instance.terminate();
worker.instance = null;
});
});
});
});

View file

@ -0,0 +1,307 @@
define(function(require) {
'use strict';
var CalendarError = require('common/error');
var Factory = require('test/support/factory');
var SyncController = require('controllers/sync');
var core = require('core');
var nextTick = require('common/next_tick');
suite('Controllers.Sync', function() {
var account;
var calendar;
var event;
var subject;
var db;
var accModel;
setup(function(done) {
db = core.db;
subject = new SyncController();
var storeFactory = core.storeFactory;
calendar = storeFactory.get('Calendar');
account = storeFactory.get('Account');
event = storeFactory.get('Event');
accModel = Factory('account', {
_id: 'one'
});
db.open(function(err) {
if (err) {
done(err);
return;
}
done();
});
});
teardown(function(done) {
testSupport.calendar.clearStore(
db,
['accounts', 'calendars', 'events', 'busytimes'],
done
);
});
teardown(function() {
db.close();
});
test('initialization', function() {
assert.equal(subject.pending, 0);
});
test('sync all, no accounts', function(done) {
subject.once('syncComplete', done);
subject.all();
});
test('sync all, no accounts with callback', function(done) {
subject.all(done);
});
suite('#all', function() {
var list = [];
setup(function(done) {
var trans = db.transaction('accounts', 'readwrite');
list.push(Factory('account'));
list.push(Factory('account'));
account.persist(list[0], trans);
account.persist(list[1], trans);
trans.oncomplete = function() {
done();
};
});
test('sync account', function(done) {
var calledModels = [];
var pending = 2;
function complete() {
list.forEach(function(item, idx) {
assert.hasProperties(item, calledModels[idx]);
});
}
subject.account = function(model) {
calledModels.push(model);
if (!--pending) {
done(complete);
}
};
subject.all();
});
});
suite('individual sync operations', function() {
var calendars;
var accountSyncCall;
var calendarSyncCalls;
var events;
function assertEmit(event) {
assert.isTrue(
(event in events),
'has emitted ' + event
);
}
function assertDoesNotEmit(event) {
assert.isFalse(
(event in events),
'emitted ' + event
);
}
var handler = {
handleEvent: function(event) {
events[event.type] = event.data;
}
};
setup(function(done) {
var trans = db.transaction(
['accounts', 'calendars'],
'readwrite'
);
trans.oncomplete = function() {
done();
};
// setup events
events = {};
subject.on('syncStart', handler);
subject.on('syncComplete', handler);
// setup mocks
calendarSyncCalls = [];
account.sync = function() {
accountSyncCall = Array.slice(arguments);
};
calendar.sync = function() {
calendarSyncCalls.push(Array.slice(arguments));
};
// setup db
calendars = [];
account.persist(accModel, trans);
var numberOfCalendars = 2;
while (numberOfCalendars--) {
var item = Factory('calendar', {
accountId: accModel._id
});
calendars.push(item);
calendar.persist(item, trans);
}
});
suite('#account', function() {
var err;
setup(function() {
err = new CalendarError();
account.sync = function() {
var args = Array.slice(arguments);
var cb = args.pop();
nextTick(cb.bind(this, err));
};
});
teardown(function() {
delete account.sync;
delete core.errorController.dispatch;
});
test('error without a callback', function(done) {
core.errorController.dispatch = function(given) {
done(function() {
assert.equal(subject.pending, 0);
assert.equal(err, given);
});
};
assert.equal(subject.pending, 0);
subject.account(accModel);
assert.equal(subject.pending, 1);
});
test('error with a callback', function(done) {
subject.account(accModel, function(givenErr) {
done(function() {
assert.equal(givenErr, err, 'sends error');
assert.equal(subject.pending, 0, 'pending');
});
});
});
test('success', function(done) {
var pendingCalendarSync = 2;
// verify we sync accounts
account.sync = function(account, callback) {
assert.equal(account._id, accModel._id);
assertDoesNotEmit('syncComplete');
callback();
};
var lastCalendar;
// verify we sync calendars
calendar.sync = function(acc, calendar, callback) {
assert.equal(accModel._id, acc._id);
assert.equal(calendar.accountId, acc._id);
nextTick(function() {
callback();
if (!--pendingCalendarSync) {
assert.notEqual(lastCalendar._id, calendar._id);
} else {
lastCalendar = calendar;
assertDoesNotEmit('syncComplete');
}
});
};
subject.account(accModel, function() {
done(function() {
assertEmit('syncComplete');
});
});
});
});
suite('#calendar', function() {
test('multiple in progress', function() {
subject.calendar(accModel, calendars[0]);
assertEmit('syncStart');
delete events.syncStart;
subject.calendar(accModel, calendars[1]);
assertDoesNotEmit('syncStart');
var firstSync = calendarSyncCalls.shift();
firstSync[firstSync.length - 1]();
// because there are two pending...
assertDoesNotEmit('syncComplete');
var secondSync = calendarSyncCalls.shift();
secondSync[secondSync.length - 1]();
// now both are fully completed.
assertEmit('syncComplete');
});
test('success', function(done) {
subject.calendar(accModel, calendars[0], function() {
assertEmit('syncComplete');
done();
});
assertEmit('syncStart');
assert.lengthOf(calendarSyncCalls, 1, 'emits syncComplete');
var sync = calendarSyncCalls[0];
assert.deepEqual(
sync.slice(0, 2),
[accModel, calendars[0]]
);
assertDoesNotEmit('syncComplete');
sync[sync.length - 1]();
});
test('failure', function(done) {
var sentErr = new Error();
subject.calendar(accModel, calendars[0], function(err) {
assert.equal(err, sentErr);
assertEmit('syncComplete');
done();
});
var sync = calendarSyncCalls.shift();
assert.ok(sync);
sync[sync.length - 1](sentErr);
});
});
});
});
});

View file

@ -0,0 +1,256 @@
define(function(require) {
'use strict';
var Responder = require('common/responder');
var TimeController = require('controllers/time');
var core = require('core');
window.page = window.page || {};
suite('Controllers.Time', function() {
var subject;
var busytimeStore;
var db;
setup(function(done) {
subject = new TimeController();
subject.calendarStore = {
shouldDisplayCalendar: function(id) {
return true;
},
on: function() {}
};
busytimeStore = core.storeFactory.get('Busytime');
db = core.db;
db.open(function() {
done();
});
});
teardown(function(done) {
testSupport.calendar.clearStore(
core.db,
['events', 'busytimes', 'alarms'],
done
);
});
teardown(function() {
core.db.close();
});
test('initialize', function() {
assert.instanceOf(subject, Responder);
});
suite('#handleEvent', function() {
test('switching between days', function() {
function type() {
return subject.mostRecentDayType;
}
subject.selectedDay = new Date(2012, 1, 5);
assert.deepEqual(
subject.mostRecentDay,
subject.selectedDay,
'mostRecentDay - selected day'
);
assert.equal(
type(),
'selectedDay',
'"selectedDay" change should update type'
);
subject.move(new Date(2012, 1, 10));
assert.equal(
type(), 'day',
'move - sets most recent type'
);
assert.deepEqual(
subject.mostRecentDay,
subject.position,
'mostRecentDay - day'
);
// back & forth
subject.move(new Date(2012, 1, 15));
assert.equal(type(), 'day');
subject.selectedDay = new Date(2012, 1, 20);
assert.equal(type(), 'selectedDay');
});
});
test('#scale', function() {
var calledWith;
subject.on('scaleChange', function() {
calledWith = Array.slice(arguments);
});
subject.scale = 'year';
assert.deepEqual(calledWith, ['year', null]);
calledWith = null;
subject.scale = 'year';
assert.isNull(calledWith, 'should not trigger change when value is same');
subject.scale = 'day';
assert.deepEqual(
calledWith,
['day', 'year']
);
});
test('#moveToMostRecentDay', function() {
var date = new Date();
var calledMove;
subject.move(date);
subject.move = function() {
TimeController.prototype.move.apply(this, arguments);
calledMove = arguments;
};
subject.selectedDay = new Date(2012, 1, 1);
subject.moveToMostRecentDay();
assert.equal(
calledMove[0],
subject.selectedDay,
'should move to selected day'
);
calledMove = null;
subject.moveToMostRecentDay();
assert.ok(!calledMove, 'should not move when "day" was last changed');
});
test('#selectedDay', function() {
var calledWith;
subject.on('selectedDayChange', function() {
calledWith = arguments;
});
var date = new Date(2012, 1, 1);
subject.selectedDay = date;
assert.equal(calledWith[0], date);
assert.equal(subject.selectedDay, date);
calledWith = null;
// try and set it again with same object...
subject.selectedDay = new Date(2012, 1, 1);
assert.isNull(calledWith, 'should not fire event when day is same');
var newDate = new Date(2012, 1, 2);
subject.selectedDay = newDate;
assert.equal(subject.selectedDay, newDate);
assert.equal(calledWith[0], newDate);
assert.equal(calledWith[1], date);
});
suite('#move', function() {
var events;
var date;
function clearEvents() {
events = {
year: [],
month: [],
day: []
};
}
setup(function() {
clearEvents();
date = new Date(2012, 5, 5);
var handle = {
handleEvent: function(e) {
var name = e.type.replace('Change', '');
events[name].push(e.data[0]);
}
};
subject.on('yearChange', handle);
subject.on('monthChange', handle);
subject.on('dayChange', handle);
subject.move(date);
});
function fires(type, value) {
var eventValue = events[type][0];
assert.deepEqual(
eventValue, value, 'fires: ' + type + ' change'
);
assert.deepEqual(
subject[type],
value,
'should update .' + type
);
}
function doesNotFire(type) {
assert.deepEqual(
events[type],
[]
);
}
test('initial move', function() {
fires('year', new Date(2012, 0, 1));
fires('month', new Date(2012, 5, 1));
fires('day', new Date(2012, 5, 5));
});
test('move day', function() {
clearEvents();
subject.move(new Date(2012, 5, 6));
doesNotFire('year');
doesNotFire('month');
fires('day', new Date(2012, 5, 6));
});
test('move month', function() {
clearEvents();
subject.move(new Date(2012, 8, 6));
doesNotFire('year');
fires('month', new Date(2012, 8, 1));
fires('day', new Date(2012, 8, 6));
});
test('move into the past', function() {
clearEvents();
subject.move(new Date(2011, 5, 4));
fires('year', new Date(2011, 0, 1));
fires('month', new Date(2011, 5, 1));
fires('day', new Date(2011, 5, 4));
});
});
});
});