VulpesOS/gaia/apps/sharedtest/test/unit/sync/bootstrap_test.js
OverSu b38dea0597 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.
2026-09-30 23:13:03 +02:00

324 lines
9.4 KiB
JavaScript
Executable file

/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
/* global
Bootstrap,
BootstrapFixture,
DataAdapters,
ERROR_SYNC_APP_SYNC_IN_PROGRESS,
ERROR_SYNC_INVALID_REQUEST_OPTIONS,
MocksHelper,
MockIACPort,
MockLazyLoader,
MockSyncEngine
*/
require('/shared/js/sync/errors.js');
require('/shared/test/unit/mocks/mock_lazy_loader.js');
requireApp('system/test/unit/mock_iac_handler.js');
requireApp('sharedtest/test/unit/sync/fixtures/bootstrap.js');
requireApp('sharedtest/test/unit/sync/sync-engine-mock.js');
var mocksForBootstrap = new MocksHelper([
'IACHandler',
'IACPort',
'LazyLoader',
'SyncEngine'
]).init();
suite('Bootstrap', function() {
mocksForBootstrap.attachTestHelpers();
suite('when script is loaded', function() {
var addEventListenerSpy;
suiteSetup(function(done) {
addEventListenerSpy = sinon.spy(window, 'addEventListener');
// The other suites rely on this suite running first for bootstrap.js
// to be loaded.
require('/shared/js/sync/bootstrap.js', done);
});
suiteTeardown(function() {
addEventListenerSpy.restore();
});
test('DataAdapters global is exposed', function() {
expect(DataAdapters).to.be.an('object');
});
test('IAC event listener is set', function() {
expect(addEventListenerSpy.called).to.equal(true);
expect(addEventListenerSpy.args[0][0]).to.equal(
'iac-gaia::sync::request'
);
});
});
suite('Bootstrap.handleSyncRequest', function() {
function run(shouldFail = false) {
MockSyncEngine.shouldFail = shouldFail;
return Bootstrap.handleSyncRequest({
assertion: 'test-assertion',
keys: { kA: 'test-kA', kB: 'test-kB' },
collections: {
'test-collection': {}
},
URL: 'test-URL'
});
}
function buildRequest() {
return {
URL: 'is a string',
assertion: 'is a string',
keys: {
kA: 'is a string',
kB: 'is a string'
},
collections: {
foo: {}
}
};
}
test('checks request is an object', function(done) {
var spy = this.sinon.spy(MockLazyLoader, 'load');
expect(Bootstrap.handleSyncRequest()).to.be
.rejectedWith(ERROR_SYNC_INVALID_REQUEST_OPTIONS)
.and.notify(function(err) {
expect(spy.args[0][0]).to.equal('shared/js/sync/errors.js');
done(err);
});
});
test('checks request.URL is a string', function(done) {
var spy = this.sinon.spy(MockLazyLoader, 'load');
var request = buildRequest();
delete request.URL;
expect(Bootstrap.handleSyncRequest()).to.be
.rejectedWith(ERROR_SYNC_INVALID_REQUEST_OPTIONS)
.and.notify(function(err) {
expect(spy.args[0][0]).to.equal('shared/js/sync/errors.js');
done(err);
});
});
test('checks request.assertion is a string', function(done) {
var spy = this.sinon.spy(MockLazyLoader, 'load');
var request = buildRequest();
delete request.assertion;
expect(Bootstrap.handleSyncRequest()).to.be
.rejectedWith(ERROR_SYNC_INVALID_REQUEST_OPTIONS)
.and.notify(function(err) {
expect(spy.args[0][0]).to.equal('shared/js/sync/errors.js');
done(err);
});
});
test('checks request.keys.kB is a string', function(done) {
var spy = this.sinon.spy(MockLazyLoader, 'load');
var request = buildRequest();
delete request.keys.kB;
expect(Bootstrap.handleSyncRequest()).to.be
.rejectedWith(ERROR_SYNC_INVALID_REQUEST_OPTIONS)
.and.notify(function(err) {
expect(spy.args[0][0]).to.equal('shared/js/sync/errors.js');
done(err);
});
});
test('checks request.collections is an object (not Array)', function(done) {
var spy = this.sinon.spy(MockLazyLoader, 'load');
var request = buildRequest();
request.collections = [ 'foo' ];
expect(Bootstrap.handleSyncRequest()).to.be
.rejectedWith(ERROR_SYNC_INVALID_REQUEST_OPTIONS)
.and.notify(function(err) {
expect(spy.args[0][0]).to.equal('shared/js/sync/errors.js');
done(err);
});
});
test('loads main scripts', function(done) {
var spy = this.sinon.spy(MockLazyLoader, 'load');
run().then(function() {
expect(spy.args[0][0]).to.deep.equal(BootstrapFixture.mainScripts);
done();
});
});
test('loads DataAdapter scripts', function(done) {
var spy = this.sinon.spy(MockLazyLoader, 'load');
run().then(function() {
expect(spy.args[1][0]).to.deep.equal('js/adapters/test-collection.js');
done();
});
});
test('constructs SyncEngine', function(done) {
run().then(() => {
expect(MockSyncEngine.constructorOptions).to.deep.equal({
kB: 'test-kB',
URL: 'test-URL',
assertion: 'test-assertion',
adapters: DataAdapters
});
done();
});
});
test('calls SyncEngine#syncNow', function(done) {
run().then(() => {
expect(MockSyncEngine.syncOptions).to.deep.equal({
'test-collection': {}
});
done();
});
});
test('will report failures', function(done) {
expect(run(true)).to.be.rejectedWith('mock sync failure')
.and.notify(done);
});
test('will run only once at a time', function(done) {
var spy = this.sinon.spy(MockLazyLoader, 'load');
var firstSucceeded = false;
var secondFailed = false;
run().then(() => {
firstSucceeded = true;
if (secondFailed) {
done();
}
});
run().catch(err => {
expect(spy.withArgs('shared/js/sync/errors.js').called).to.equal(true);
expect(err.message).to.equal(ERROR_SYNC_APP_SYNC_IN_PROGRESS);
secondFailed = true;
if (firstSucceeded) {
done();
}
});
});
test('will run again after success', function(done) {
run().then(() => {
expect(run()).to.eventually.equal(undefined).and.notify(done);
});
});
test('will run again after failure', function(done) {
run(true).catch(err => {
expect(err.message).to.equal('mock sync failure');
return run();
}).then(done);
});
});
suite('IAC request', () => {
const IAC_EVENT = 'iac-gaia::sync::request';
var consoleErrorSpy;
var postMessageSpy;
var closeStub;
setup(function() {
consoleErrorSpy = sinon.spy(console, 'error');
postMessageSpy = sinon.spy(MockIACPort, 'postMessage');
closeStub = sinon.stub(window, 'close');
});
teardown(function() {
consoleErrorSpy.restore();
postMessageSpy.restore();
closeStub.restore();
});
test('invalid sync request', function() {
window.dispatchEvent(new CustomEvent(IAC_EVENT));
expect(consoleErrorSpy.called).to.equal(true);
expect(consoleErrorSpy.args[0][0]).to.equal('Wrong IAC request');
expect(postMessageSpy.called).to.equal(false);
expect(closeStub.called).to.equal(true);
});
test('Unknown IAC request', function() {
var id = Date.now();
window.dispatchEvent(new CustomEvent(IAC_EVENT, {
detail: {
name: 'whatever',
id: id
}
}));
expect(consoleErrorSpy.called).to.equal(true);
expect(consoleErrorSpy.args[0][0]).to.equal('Unknown IAC request');
expect(postMessageSpy.called).to.equal(false);
expect(closeStub.called).to.equal(true);
});
test('successful sync request', function(done) {
var id = Date.now();
window.dispatchEvent(new CustomEvent(IAC_EVENT, {
detail: {
name: 'sync',
id: id,
URL: 'url',
assertion: 'assertion',
keys: { kB: 'kB' },
collections: { collection: {} }
}
}));
setTimeout(function() {
expect(consoleErrorSpy.called).to.equal(false);
expect(postMessageSpy.called).to.equal(true);
expect(postMessageSpy.args[0][0]).to.deep.equal({
id: id
});
expect(postMessageSpy.args[0][0].error).to.equal(undefined);
expect(closeStub.called).to.equal(true);
done();
});
});
test('failed sync request', function(done) {
var id = Date.now();
MockSyncEngine.shouldFail = true;
window.dispatchEvent(new CustomEvent(IAC_EVENT, {
detail: {
name: 'sync',
id: id,
URL: 'url',
assertion: 'assertion',
keys: { kB: 'kB' },
collections: { collection: {} }
}
}));
setTimeout(function() {
expect(consoleErrorSpy.called).to.equal(false);
expect(postMessageSpy.called).to.equal(true);
expect(postMessageSpy.args[0][0].id).to.equal(id);
expect(postMessageSpy.args[0][0].error.message)
.to.equal('mock sync failure');
expect(closeStub.called).to.equal(true);
done();
});
});
test('Cancel sync request', function() {
var id = Date.now();
window.dispatchEvent(new CustomEvent(IAC_EVENT, {
detail: {
name: 'cancel',
id: id
}
}));
expect(closeStub.called).to.equal(true);
expect(postMessageSpy.called).to.equal(false);
});
});
});