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,139 @@
define(function(require, exports) {
'use strict';
var Db = require('db');
var Factory = require('test/support/factory');
var MockProvider = require('test/support/mock_provider');
var app = require('app');
var core = require('core');
require('test/support/factories/all');
exports._lastEnvId = 0;
exports.core = function() {
var pendingManager = app.pendingManager;
if (pendingManager) {
// hack to ensure clean tests
pendingManager.objects.forEach(item => pendingManager.unregister(item));
}
if (core.db && core.db.isOpen) {
core.db.close();
}
app.setupCore('b2g-test-calendar');
core.providerFactory.providers.Mock = new MockProvider();
return core;
};
exports.accountEnvironment = function(accOverrides, calOverrides) {
accOverrides = accOverrides || {};
accOverrides.providerType = accOverrides.providerType || 'Mock';
calOverrides = calOverrides || {};
setup(function(done) {
var id = ++exports._lastEnvId;
accOverrides._id = id;
calOverrides.accountId = id;
var trans = core.db.transaction(['accounts', 'calendars'], 'readwrite');
trans.oncomplete = () => done();
trans.onerror = event => done(event.target.error);
var account = this.account = Factory('account', accOverrides);
var calendar = this.calendar = Factory('calendar', calOverrides);
var storeFactory = core.storeFactory;
var accountStore = storeFactory.get('Account');
var calendarStore = storeFactory.get('Calendar');
accountStore.persist(account, trans);
calendarStore.persist(calendar, trans);
});
};
exports.eventEnvironment = function(busytimeOverrides, eventOverrides) {
eventOverrides = eventOverrides || {};
eventOverrides._id = eventOverrides._id || 'one';
busytimeOverrides = busytimeOverrides || {};
setup(function(done) {
var storeFactory = core.storeFactory;
var busytimeStore = storeFactory.get('Busytime');
var eventStore = storeFactory.get('Event');
var trans = core.db.transaction(eventStore._dependentStores, 'readwrite');
trans.oncomplete = () => done();
trans.onerror = event => done(event.target.error);
eventOverrides.calendarId = this.calendar._id;
var event = this.event = Factory('event', eventOverrides);
busytimeOverrides.calendarId = this.calendar._id;
busytimeOverrides.eventId = this.event._id || eventOverrides._id;
var busytime = this.busytime = Factory('busytime', busytimeOverrides);
eventStore.persist(event, trans);
busytimeStore.persist(busytime, trans);
});
};
exports.dbFixtures = function(factory, storeName, list) {
var object = Object.create(null);
setup(function(done) {
var db = core.db;
var store = core.storeFactory.get(storeName);
var trans = db.transaction(store._dependentStores, 'readwrite');
trans.oncomplete = () => done();
trans.onerror = event => done(event.target.error);
for (var key in list) {
store.persist(
(object[key] = Factory(factory, list[key])),
trans
);
}
});
return object;
};
exports.clearStore = function(db, name, callback) {
if (typeof(name) === 'function') {
callback = name;
name = Object.keys(Db.prototype.store);
}
var trans = db.transaction(name, 'readwrite');
trans.oncomplete = () => callback();
trans.onerror = () => callback(new Error('Could not wipe accounts db'));
name = [].concat(name);
name.forEach(storeName => {
var store = trans.objectStore(storeName);
store.clear();
});
};
exports.bench = function(iter, cb) {
var start = window.performance.now();
for (var i = 0; i < iter; i++) {
cb();
}
return window.performance.now() - start;
};
exports.vs = function(iter, cmds) {
var results = {};
for (var key in cmds) {
results[key] = exports.bench(iter, cmds[key]);
}
return results;
};
exports.triggerEvent = function(element, eventType) {
var event = document.createEvent('HTMLEvents');
event.initEvent(eventType, true, true);
element.dispatchEvent(event);
};
});

View file

@ -0,0 +1,10 @@
define(function(require, exports) {
'use strict';
var nextTick = require('common/next_tick');
exports.load = function(id, require, onLoad) {
nextTick(() => onLoad());
};
});

View file

@ -0,0 +1,12 @@
/* global requireElements */
define(function(require, exports) {
'use strict';
var nextTick = require('common/next_tick');
exports.load = function(id, require, onLoad) {
requireElements('calendar/elements/' + id + '.html');
nextTick(() => onLoad());
};
});

View file

@ -0,0 +1,232 @@
define(function(require) {
'use strict';
/**
* Module dependencies
*/
var AccountModel = require('models/account');
var CalendarModel = require('models/calendar');
var Caldav = require('ext/caldav');
var Calc = require('common/calc');
var Factory = require('test/support/factory');
/**
* Module state
*/
var calendarId = 0;
function handleTransportDate(obj) {
// handle case of incoming start date
if (obj.startDate) {
obj.start = Calc.dateToTransport(obj.startDate);
}
if (obj.endDate) {
obj.end = Calc.dateToTransport(obj.endDate);
}
// handle case of defaults
if (!obj.start) {
obj.start = Calc.dateToTransport(
new Date()
);
}
if (obj.start) {
obj.startDate = Calc.dateFromTransport(obj.start);
}
if (!obj.end) {
obj.end = Calc.dateToTransport(
// 1 hour after start
new Date(obj.startDate.getTime() + 3600 * 1000)
);
}
if (obj.end) {
obj.endDate = Calc.dateFromTransport(obj.end);
}
}
Factory.define('remote.calendar', {
properties: {
id: '',
url: '/',
name: 'my calendar',
color: '#333',
description: 'description',
syncToken: '1',
// read, write, delete
privilegeSet: ['read', 'write-content', 'unbind']
},
onbuild: function(obj) {
var id = obj.id;
if (!id) {
id = obj.id = 'cuuid/' + calendarId++;
}
}
});
var eventId = 0;
Factory.define('remote.event', {
properties: {
location: 'location',
isRecurring: false,
alarms: [
{action: 'DISPLAY', trigger: 60000}
]
//XXX: raw data
},
onbuild: function(obj) {
var id = obj.id;
if (!id) {
id = obj.id = 'euuid/' + eventId++;
}
handleTransportDate(obj);
if (!obj.title) {
obj.title = 'title ' + id;
}
if (!obj.description) {
obj.description = 'description ' + id;
}
}
});
Factory.define('caldav.calendar', {
get object() {
return Caldav.Resources.Calendar;
},
properties: {
url: '/cal',
name: 'name',
color: '#333',
ctag: 'token',
description: '1',
privilegeSet: [
'read',
'write',
'write-content'
]
}
});
Factory.define('caldav.account', {
properties: {
user: 'user',
password: 'password',
domain: 'http://google.com',
entrypoint: '/dav/',
calendarHome: '/dav/my/foobar'
}
});
Factory.define('caldav.connection', {
extend: 'caldav.account',
get object() {
return Caldav.Connection;
}
});
Factory.define('account', {
get object() {
return AccountModel;
},
properties: {
providerType: 'Local',
user: 'user',
password: 'password',
domain: 'http://google.com',
entrypoint: '/',
preset: 'local'
}
});
Factory.define('calendar', {
get object() {
return CalendarModel;
},
properties: {
accountId: 1,
remote: Factory.get('remote.calendar')
},
oncreate: function(obj) {
if (!obj._id) {
obj._id = obj.accountId + '-' + obj.remote.id;
}
}
});
Factory.define('event', {
properties: {
calendarId: 1,
remote: Factory.get('remote.event')
},
oncreate: function(obj) {
if (!obj._id) {
obj._id = obj.calendarId + '-' + obj.remote.id;
}
}
});
var busytimeId = 0;
Factory.define('busytime', {
properties: {
calendarId: 'calendar-1',
eventId: 'event-1'
},
oncreate: function(obj) {
if (!obj._id) {
obj._id = obj.eventId + '-' + (++busytimeId);
}
handleTransportDate(obj);
if (obj.endDate === obj.startDate) {
obj.endDate.setHours(obj.endDate.getHours() + 2);
handleTransportDate(obj);
}
}
});
Factory.define('alarm', {
oncreate: function(obj) {
if (obj.startDate && obj.startDate instanceof Date) {
obj.startDate = Calc.dateToTransport(obj.startDate);
}
}
});
Factory.define('icalComponent', {
oncreate: function(obj) {
if (obj.lastRecurrenceId && obj.lastRecurrenceId instanceof Date) {
obj.lastRecurrenceId = Calc.dateToTransport(obj.lastRecurrenceId);
}
},
properties: {
ical: 'fooo!'
}
});
});

View file

@ -0,0 +1,209 @@
/**
* Test factory builder. Inspired by FactoryGirl (of ruby/rails fame).
* Tries very hard to respect getters in js objects
* as a result there is a performance hit so factories
* should not be used when building thousands of objects
* but should be fine for the 10-100 objects in small-large
* tests.
*/
define(function(require, exports, module) {
'use strict';
function propIsFactory(object, key) {
var descriptor = Object.getOwnPropertyDescriptor(
object, key
);
if (!descriptor) {
return false;
}
return (
descriptor.value &&
(descriptor.value instanceof Factory)
);
}
/**
* Copy a set of property descriptors from
* one object to another
*/
function copyProp(from, keys, to) {
var list = [].concat(keys);
list.forEach(function(key) {
if (!from.hasOwnProperty(key)) {
return;
}
Object.defineProperty(
to,
key,
Object.getOwnPropertyDescriptor(
from,
key
)
);
});
return to;
}
/**
* Copies all properties
* (in order from left to right to the final argument)
*/
function copy() {
var args = Array.prototype.slice.call(arguments);
var target = args.pop();
args.forEach(function(object) {
if (!object) {
return;
}
for (var key in object) {
if (object.hasOwnProperty(key)) {
Object.defineProperty(
target,
key,
Object.getOwnPropertyDescriptor(
object,
key
)
);
}
}
});
return target;
}
/* static api */
Factory._defined = Object.create(null);
Factory.get = function(name) {
return Factory._defined[name];
};
Factory.define = function(name, options) {
if (options.extend) {
var factory = Factory.get(options.extend);
Factory._defined[name] = factory.extend(
options
);
} else {
Factory._defined[name] = new Factory(
options
);
}
return Factory._defined[name];
};
Factory.create = function(name, opts) {
return Factory.get(name).create(opts);
};
Factory.build = function(name, opts) {
return Factory.get(name).build(opts);
};
function Factory(options) {
if (!(this instanceof Factory)) {
return Factory.create.apply(Factory, arguments);
}
copy(options, this);
return this;
}
module.exports = Factory;
Factory.prototype = {
parent: null,
object: null,
properties: {},
extend: function(options) {
var newFactory = {};
// we need to copy the prop
// rather then do an assignment for lazy-est
// possible evaluation of properties.
copyProp(
this,
['object', 'onbuild', 'oncreate'],
newFactory
);
copy(options, newFactory);
newFactory.properties = copy(
this.properties,
newFactory.properties,
{}
);
return new Factory(newFactory);
},
build: function(overrides, childFactoryMethod) {
if (typeof(overrides) === 'undefined') {
overrides = {};
}
if (typeof(childFactoryMethod) === 'undefined') {
childFactoryMethod = 'build';
}
var defaults = {};
var key;
var props = this.properties;
copy(props, overrides, defaults);
// expand factories
var factoryOverrides;
for (key in defaults) {
// when default property is a factory
if (propIsFactory(props, key)) {
factoryOverrides = undefined;
if (!propIsFactory(defaults, key)) {
// user overrides defaults
factoryOverrides = defaults[key];
}
defaults[key] = props[key][childFactoryMethod](
factoryOverrides
);
}
}
if (typeof(this.onbuild) === 'function') {
this.onbuild(defaults);
}
return defaults;
},
create: function(overrides) {
var result;
var constructor = this.object;
var attrs = this.build(overrides, 'create');
if (constructor) {
result = new constructor(attrs);
} else {
result = attrs;
}
if (typeof(this.oncreate) === 'function') {
this.oncreate(result);
}
return result;
}
};
});

View file

@ -0,0 +1,429 @@
define(function(require) {
'use strict';
var Factory = require('test/support/factory');
suite('factory', function() {
var subject;
var realDefined;
setup(function() {
realDefined = Factory._defined;
Factory._defined = Object.create(null);
});
teardown(function() {
Factory._defined = realDefined;
});
function Model(options) {
var key;
for (key in options) {
if (options.hasOwnProperty(key)) {
this[key] = options[key];
}
}
}
suite('hooks', function() {
setup(function() {
subject = new Factory({
onbuild: function(obj) {
obj.hitBuild = true;
},
oncreate: function(obj) {
obj.hitCreate = true;
},
properties: {
one: true
}
});
});
test('create', function() {
var out = subject.create();
assert.isTrue(out.hitBuild);
assert.isTrue(out.hitCreate);
});
test('build', function() {
var out = subject.build();
assert.isTrue(out.hitBuild);
assert.ok(!out.hitCreate);
});
});
suite('simple property factory', function() {
setup(function() {
subject = new Factory({
properties: {
get one() {
return 'cool';
},
two: 'foo'
}
});
});
test('initialization', function() {
assert.deepEqual(subject.properties, {
one: 'cool',
two: 'foo'
});
});
test('create - no overrides', function() {
var result = subject.create();
assert.deepEqual(
result,
subject.properties
);
});
test('create - overrides', function() {
var result = subject.create(
{ one: '1', three: '3' }
);
assert.deepEqual(
result, {
one: '1',
two: 'foo',
three: '3'
}
);
});
});
suite('with getters', function() {
var increment;
setup(function() {
increment = 0;
subject = new Factory({
properties: {
get increment() {
return increment++;
}
}
});
});
test('increment getter', function() {
subject.create();
subject.create();
subject.create();
var result = subject.create();
// This is probably something
// you would not want to do in real
// life but it provides that
// increments are clean.
assert.equal(result.increment, 0);
assert.equal(result.increment, 1);
assert.equal(result.increment, 2);
assert.equal(result.increment, 3);
});
});
suite('with constructors', function() {
setup(function() {
subject = new Factory({
object: Model,
properties: {
value: 'foo'
}
});
});
test('create - no overrides', function() {
var result = subject.create();
assert.instanceOf(result, Model);
assert.equal(result.value, 'foo');
});
test('create - with overrides', function() {
var result = subject.create(
{ value: 'val', other: true }
);
assert.instanceOf(result, Model);
assert.equal(result.value, 'val');
assert.equal(result.other, true);
});
test('build', function() {
var result = subject.build({ val: 1 });
assert.isFalse((
result instanceof Model
));
assert.equal(result.val, 1);
assert.equal(result.value, 'foo');
});
});
suite('with factory props', function() {
var childFactory;
setup(function() {
childFactory = new Factory({
object: Model,
properties: {
get child() {
return true;
}
}
});
subject = new Factory({
properties: {
parent: 'yes',
child: childFactory,
inertChild: childFactory
}
});
});
test('create', function() {
var result = subject.create({
parentVal: 1,
child: {
otherVal: 1
}
});
assert.instanceOf(result.child, Model);
assert.instanceOf(result.inertChild, Model);
assert.equal(result.parent, 'yes');
assert.equal(result.parentVal, 1);
assert.equal(result.inertChild.child, true);
assert.equal(result.child.child, true);
assert.equal(result.child.otherVal, 1);
});
test('build', function() {
var result = subject.build({
child: {
otherVal: 1
}
});
assert.isFalse((
result.child instanceof Model
));
assert.isFalse((
result.inertChild instanceof Model
));
});
test('#extend', function() {
var sub = subject.extend({
object: Model,
properties: {
foo: 'bar'
}
});
assert.ok(!subject.properties.foo);
assert.equal(sub.object, Model);
var result = sub.create({
other: 'fooz'
});
assert.instanceOf(result, Model);
assert.notEqual(
sub.properties,
subject.properties
);
assert.equal(result.other, 'fooz');
assert.instanceOf(result.child, Model);
assert.instanceOf(result.inertChild, Model);
assert.equal(result.child.child, true);
});
});
suite('static api', function() {
var defined;
setup(function() {
defined = Factory.define('one', {
object: Model,
properties: {
one: true
}
});
});
test('#define', function() {
assert.instanceOf(defined, Factory);
assert.equal(defined.object, Model);
assert.deepEqual(
defined.properties,
{ one: true }
);
assert.equal(Factory.get('one'), defined);
});
test('#define - /w extend', function() {
Factory.define('one.ext', {
extend: 'one',
properties: {
two: false
}
});
assert.instanceOf(
Factory.get('one.ext'),
Factory
);
var created = Factory.create('one.ext');
assert.equal(created.one, true);
assert.equal(created.two, false);
});
test('#create', function() {
var result = Factory.create('one', {
extra: true
});
assert.instanceOf(result, Model);
assert.equal(result.extra, true);
assert.equal(result.one, true);
});
test('#build', function() {
var result = Factory.build('one', {
extra: true
});
assert.isFalse((
result instanceof Model
));
assert.equal(result.extra, true);
assert.equal(result.one, true);
});
});
suite('acceptance', function() {
var result;
function Event() { Model.apply(this, arguments); }
function Cal() { Model.apply(this, arguments); }
function Account() { Model.apply(this, arguments); }
setup(function() {
Factory.define('event', {
object: Event,
properties: {
isEvent: true
}
});
Factory.define('calendar', {
object: Cal,
properties: {
isCalendar: true,
event: Factory.get('event')
}
});
Factory.define('account', {
object: Account,
properties: {
isAccount: true,
normalCal: Factory.get('calendar'),
extendCal: Factory.get('calendar').extend({
properties: {
isCrazy: true,
event: Factory.get('event').extend({
properties: {
isCrazy: true
}
})
}
})
}
});
});
function hasProps() {
// account
assert.isTrue(result.isAccount);
// normal cal
assert.isTrue(result.normalCal.isCalendar);
assert.ok(!result.normalCal.isCrazy);
// crazy cal
assert.isTrue(result.extendCal.isCrazy);
assert.isTrue(result.extendCal.isCalendar);
// normal event
assert.isTrue(result.normalCal.event.isEvent);
assert.ok(!result.normalCal.event.isCrazy);
// crazy calendar
assert.isTrue(result.extendCal.event.isEvent);
assert.isTrue(result.extendCal.event.isCrazy);
}
test('#create - no overrides', function() {
result = Factory.create('account');
assert.instanceOf(result, Account, 'result Account');
assert.instanceOf(result.normalCal, Cal, 'normalCal');
assert.instanceOf(result.extendCal, Cal, 'extendCal');
assert.instanceOf(result.normalCal.event, Event, 'normalCal.event');
assert.instanceOf(result.extendCal.event, Event, 'extendCal.event');
hasProps();
});
test('#build - no overrides', function() {
result = Factory.build('account');
assert.isFalse(
result instanceof Account
);
hasProps();
});
test('deep overrides', function() {
result = Factory('account', {
normalCal: {
foo: true,
event: {
nested: true
}
}
});
// we did not kill the defaults
hasProps();
assert.isTrue(result.normalCal.foo);
assert.isTrue(result.normalCal.event.nested);
});
});
});
});

View file

@ -0,0 +1,23 @@
define(function(require, exports, module) {
'use strict';
function page() {
page.routes.push(Array.prototype.slice.call(arguments));
}
module.exports = page;
page.routes = [];
page.show = function(item) {
this.shown = item;
};
page.start = function() {
this.started = true;
};
page.stop = function() {
this.started = false;
};
});

View file

@ -0,0 +1,28 @@
define(function(require, exports, module) {
'use strict';
module.exports = function mochaPromise(mochaFn, description, callback) {
if (typeof description === 'function') {
callback = description;
description = null;
}
function execute(done) {
var promise;
try {
promise = callback.call();
} catch (error) {
return done(error);
}
promise.then(() => done()).catch(done);
}
if (description) {
mochaFn(description, execute);
} else {
mochaFn(execute);
}
};
});

View file

@ -0,0 +1,54 @@
define(function(require, exports) {
'use strict';
var _id = 0;
var alarms = [];
var mozAlarms;
exports.setup = function() {
mozAlarms = navigator.mozAlarms;
navigator.mozAlarms = exports;
};
exports.teardown = function() {
removeAll();
navigator.mozAlarms = mozAlarms;
};
exports.add = function(date, honorTimezone, data) {
var alarmId = _id++;
alarms.push({
alarmId: alarmId,
date: date,
honorTimezone: honorTimezone,
data: data
});
return resolve(alarmId);
};
exports.getAll = function() {
return resolve(alarms);
};
exports.remove = function(alarmId) {
alarms = alarms.filter(alarm => alarm.alarmId !== alarmId);
};
function removeAll() {
alarms = [];
}
function resolve(result) {
var request = { onsuccess: null, onerror: null };
var requestContext = {};
requestContext.result = result;
setTimeout(() => {
return request.onsuccess &&
request.onsuccess.call(requestContext, result);
}, 10);
return request;
}
});

View file

@ -0,0 +1,213 @@
define(function(require, exports, module) {
'use strict';
var Parent = require('provider/abstract');
var nextTick = require('common/next_tick');
function accountGeneric(mockName) {
return function(account, callback) {
// next tick is scheduled before _resolveStage intentionally
nextTick(function() {
callback.apply(
null,
this._resolveStaged(mockName, account) || [null, {}]
);
}.bind(this));
};
}
function accountStaging(mockName) {
return function() {
var args = Array.slice(arguments);
var user = args.shift();
function matcher(object) {
return object.user === user;
}
return this._stage(mockName, matcher, args);
};
}
var stageEvents = {
onbefore: function() {},
onafter: function() {}
};
function Mock() {
Parent.apply(this, arguments);
// mock call storage
this._stageObjects = Object.create(null);
}
module.exports = Mock;
Mock.prototype = {
__proto__: Parent.prototype,
// opt-into sync by default
canSync: true,
_stage: function(name, matcher, args) {
if (!(this._stageObjects[name])) {
this._stageObjects[name] = [];
}
var handler = Object.create(stageEvents);
this._stageObjects[name].push({
matches: matcher,
args: args,
handler: handler
});
return handler;
},
/**
* Used to find staged objects.
* The found object must be saved as
* this method will also remove any found item.
*
* Stops at first found item that matches condition.
*
* var stagedValue = this._resolveStaged('type', input) || someDefault;
*
*/
_resolveStaged: function(name, input) {
var list = this._stageObjects[name];
if (!list) {
return null;
}
var i = 0;
var len = list.length;
for (; i < len; i++) {
if (list[i].matches(input)) {
// remove and return args
var item = list.splice(i, 1)[0];
var args = item.args;
var handler = item.handler;
handler.onbefore(args);
nextTick(handler.onafter.bind(null, args));
return args;
}
}
return null;
},
/**
* Stage a getAccount call.
*
* @param {String} user name to stage information for.
* @param {Object|Null} err given to callback.
* @param {Object|Null} object given to callback.
*/
stageGetAccount: accountStaging('getAccount'),
stageFindCalendars: accountStaging('findCalendars'),
stageSyncEvents: function(user, calendarRemoteId, err) {
err = err || null;
function matcher(args) {
return (
args[0].user === user &&
args[1].remote.id === calendarRemoteId
);
}
return this._stage('syncEvents', matcher, err);
},
stageEventCapabilities: function() {
var args = Array.slice(arguments);
var id = args.shift();
function matcher(event) {
return event._id === id;
}
return this._stage('eventCapabilities', matcher, args);
},
stageCalendarCapabilities: function() {
var args = Array.slice(arguments);
var id = args.shift();
function matcher(calendar) {
return calendar._id === id;
}
return this._stage('calendarCapabilities', matcher, args);
},
/**
* Stage findCalendars call.
*
*
* provider.stageFindCalendars(
* accountModel.user,
* err || null,
* {
* remoteId: { id: 'remoteId', ... },
* ...
* }
* );
*/
findCalendars: accountGeneric('findCalendars'),
getAccount: accountGeneric('getAccount'),
syncEvents: function(account, calendar, callback) {
// first so this tick is scheduled first
nextTick(function() {
callback(
this._resolveStaged('syncEvents', [account, calendar])
);
}.bind(this));
},
calendarCapabilities: function(calendar) {
var defaults = {
canUpdateEvent: true,
canCreateEvent: true,
canDeleteEvent: true
};
var args =
this._resolveStaged('calendarCapabilities', calendar) || [];
var overrides = args[0] || {};
for (var key in overrides) {
defaults[key] = overrides[key];
}
return defaults;
},
eventCapabilities: function(event, callback) {
var defaults = {
canUpdate: true,
canCreate: true,
canDelete: true
};
nextTick(function() {
var args = this._resolveStaged('eventCapabilities', event) || [];
var err = args[0] || null;
var overrides = args[1] || {};
for (var key in overrides) {
defaults[key] = overrides[key];
}
callback(err, defaults);
}.bind(this));
}
};
});

View file

@ -0,0 +1,33 @@
define(function(require, exports) {
'use strict';
var requestWakeLock;
exports.setup = function() {
requestWakeLock = navigator.requestWakeLock;
navigator.requestWakeLock = fakeRequestWakeLock;
};
exports.teardown = function() {
navigator.requestWakeLock = requestWakeLock;
locks = exports.locks = [];
};
var locks = exports.locks = [];
function fakeRequestWakeLock(type) {
var lock = createFakeLock(type);
locks.push(lock);
return lock;
}
function createFakeLock(type) {
return {
type: type,
unlocked: false,
unlock: function() {
this.unlocked = true;
}
};
}
});

View file

@ -0,0 +1,33 @@
define(function(require, exports, module) {
'use strict';
function View(options) {
var self = this;
var key;
if (typeof(options) === 'undefined') {
options = {};
}
for (key in options) {
if (options.hasOwnProperty(key)) {
this[key] = options[key];
}
}
this.called = 1;
this.args = arguments;
this.onactive = function() {
self.activeWith = arguments;
self.active = true;
};
this.oninactive = function() {
self.inactiveWith = arguments;
self.active = false;
};
}
module.exports = View;
});

View file

@ -0,0 +1,17 @@
define(function(require, exports, module) {
'use strict';
/** Deprecated! */
module.exports = function(name, callback) {
suite(name, function() {
suiteSetup(function(done) {
require([name], function() {
done();
});
});
callback();
});
};
});

View file

@ -0,0 +1,93 @@
define(function(require, exports, module) {
'use strict';
var asyncRequire = require('common/async_require');
var chai = require('ext/chai');
var chaiAsPromised = require('ext/chai-as-promised');
var co = require('ext/co');
module.exports = function testLoader(path) {
return co(function *() {
console.log(`Will load test ${path}`);
l10nLink('/locales/calendar.{locale}.properties');
l10nLink('/shared/locales/date/date.{locale}.properties');
l10nMeta('en-US', ['en-US']);
yield loadL10n();
var testSupport = yield asyncRequire('test/support/calendar');
testSupport.core();
// TODO(gaye): No more window/global stuff...
window.testSupport = window.testSupport || {};
window.testSupport.calendar = testSupport;
chai.use(chaiAsPromised);
extendChai();
window.assert = chai.assert;
window.expect = chai.expect;
window.should = chai.Should();
yield asyncRequire(path);
});
};
function *loadL10n() {
yield asyncRequire('shared/l10n');
// Massive hack to trick l10n to load
// TODO: upstream a fix to l10n.js
document.dispatchEvent(new Event('DOMContentLoaded'));
var readyState = navigator.mozL10n.readyState;
switch (readyState) {
case 'complete':
case 'interactive':
return Promise.resolve();
}
return new Promise(resolve => window.addEventListener('localized', resolve));
}
function l10nLink(href) {
var link = document.createElement('link');
link.setAttribute('href', href);
link.setAttribute('rel', 'localization');
document.head.appendChild(link);
}
function l10nMeta(defaultLanguage, availableLanguages) {
var metaDL = document.createElement('meta');
metaDL.setAttribute('name', 'defaultLanguage');
metaDL.setAttribute('content', defaultLanguage);
var metaAL = document.createElement('meta');
metaAL.setAttribute('name', 'availableLanguages');
metaAL.setAttribute('content', availableLanguages.join(', '));
document.head.appendChild(metaDL);
document.head.appendChild(metaAL);
}
function extendChai() {
// XXX: this is a lame way to do this
// in reality we need to fix the above upstream
// and leverage new chai 1x methods
chai.assert.hasProperties = function(given, props, msg) {
msg = (typeof(msg) === 'undefined') ? '' : msg + ': ';
if (props instanceof Array) {
props.forEach(function(prop) {
assert.ok(
(prop in given),
msg + 'given should have "' + prop + '" property'
);
});
} else {
for (var key in props) {
assert.deepEqual(
given[key],
props[key],
msg + ' property equality for (' + key + ') '
);
}
}
};
}
});

View file

@ -0,0 +1,17 @@
define(function(require, exports, module) {
'use strict';
var denodeify = require('common/promise').denodeify;
function waitFor(test, callback) {
var result = test();
if (result) {
return callback();
}
setTimeout(() => waitFor(test, callback), 200);
}
module.exports = denodeify(waitFor);
});