Commit 011eb2bd authored by Eduardo Sanz García's avatar Eduardo Sanz García Committed by Eduardo

Fix and improve test

In addition to cover the changes in the previous commit I have improved
the test in this way:

* like in frame-sync, segregate bridges according to the different
  channels and create utility functions to test the communication in
  those specific channels.
* simplify a few test by relying on `emit[frame]Event` functions
* remove mocking a public method
parent a5613f9b
...@@ -35,7 +35,8 @@ describe('Guest', () => { ...@@ -35,7 +35,8 @@ describe('Guest', () => {
let notifySelectionChanged; let notifySelectionChanged;
let rangeUtil; let rangeUtil;
let fakeBridge; let FakeBridge;
let fakeBridges;
let fakeIntegration; let fakeIntegration;
let FakeHypothesisInjector; let FakeHypothesisInjector;
let fakeHypothesisInjector; let fakeHypothesisInjector;
...@@ -48,8 +49,28 @@ describe('Guest', () => { ...@@ -48,8 +49,28 @@ describe('Guest', () => {
return guest; return guest;
}; };
// Helpers for getting the channels used for guest <-> host/sidebar communication.
// These currently rely on knowing the implementation detail of which order
// the channels are created in.
const hostBridge = () => {
return fakeBridges[0];
};
const sidebarBridge = () => {
return fakeBridges[1];
};
const emitHostEvent = (event, ...args) => {
for (let [evt, fn] of hostBridge().on.args) {
if (event === evt) {
fn(...args);
}
}
};
const emitSidebarEvent = (event, ...args) => { const emitSidebarEvent = (event, ...args) => {
for (let [evt, fn] of fakeBridge.on.args) { for (let [evt, fn] of sidebarBridge().on.args) {
if (event === evt) { if (event === evt) {
fn(...args); fn(...args);
} }
...@@ -78,12 +99,18 @@ describe('Guest', () => { ...@@ -78,12 +99,18 @@ describe('Guest', () => {
FakeAdder.instance = null; FakeAdder.instance = null;
fakeBridge = { fakeBridges = [];
FakeBridge = sinon.stub().callsFake(() => {
const bridge = {
call: sinon.stub(), call: sinon.stub(),
createChannel: sinon.stub(), createChannel: sinon.stub(),
destroy: sinon.stub(), destroy: sinon.stub(),
on: sinon.stub(), on: sinon.stub(),
onConnect: sinon.stub(),
}; };
fakeBridges.push(bridge);
return bridge;
});
fakeIntegration = { fakeIntegration = {
anchor: sinon.stub(), anchor: sinon.stub(),
...@@ -119,7 +146,7 @@ describe('Guest', () => { ...@@ -119,7 +146,7 @@ describe('Guest', () => {
} }
$imports.$mock({ $imports.$mock({
'../shared/bridge': { Bridge: sinon.stub().returns(fakeBridge) }, '../shared/bridge': { Bridge: FakeBridge },
'../shared/port-finder': { '../shared/port-finder': {
PortFinder: sinon.stub().returns(fakePortFinder), PortFinder: sinon.stub().returns(fakePortFinder),
}, },
...@@ -145,6 +172,28 @@ describe('Guest', () => { ...@@ -145,6 +172,28 @@ describe('Guest', () => {
$imports.$restore(); $imports.$restore();
}); });
describe('events from host frame', () => {
describe('on "sidebarLayoutChanged" event', () => {
it('calls fitSideBySide if `Guest` is the main annotatable frame', () => {
createGuest();
const dummyLayout = {};
emitHostEvent('sidebarLayoutChanged', dummyLayout);
assert.calledWith(fakeIntegration.fitSideBySide, dummyLayout);
});
it('does not calls fitSideBySide if `Guest` is not the main annotatable frame', () => {
createGuest({ subFrameIdentifier: 'dummy' });
const dummyLayout = {};
emitHostEvent('sidebarLayoutChanged', dummyLayout);
assert.notCalled(fakeIntegration.fitSideBySide);
});
});
});
describe('events from sidebar frame', () => { describe('events from sidebar frame', () => {
describe('on "focusAnnotations" event', () => { describe('on "focusAnnotations" event', () => {
it('focuses any annotations with a matching tag', () => { it('focuses any annotations with a matching tag', () => {
...@@ -349,12 +398,12 @@ describe('Guest', () => { ...@@ -349,12 +398,12 @@ describe('Guest', () => {
await delay(0); await delay(0);
assert.calledWith( assert.calledWith(
fakeBridge.call, sidebarBridge().call,
'syncAnchoringStatus', 'syncAnchoringStatus',
sinon.match({ target: [], uri: 'uri', $tag: 'tag1' }) sinon.match({ target: [], uri: 'uri', $tag: 'tag1' })
); );
assert.calledWith( assert.calledWith(
fakeBridge.call, sidebarBridge().call,
'syncAnchoringStatus', 'syncAnchoringStatus',
sinon.match({ target: [], uri: 'uri', $tag: 'tag2' }) sinon.match({ target: [], uri: 'uri', $tag: 'tag2' })
); );
...@@ -367,7 +416,7 @@ describe('Guest', () => { ...@@ -367,7 +416,7 @@ describe('Guest', () => {
emitSidebarEvent('deleteAnnotation', 'tag1'); emitSidebarEvent('deleteAnnotation', 'tag1');
assert.deepEqual(fakeBridge.call.lastCall.args, ['anchorsChanged']); assert.deepEqual(hostBridge().call.lastCall.args, ['anchorsChanged']);
}); });
}); });
}); });
...@@ -403,8 +452,8 @@ describe('Guest', () => { ...@@ -403,8 +452,8 @@ describe('Guest', () => {
it('hides sidebar on user "mousedown" or "touchstart" events in the document', () => { it('hides sidebar on user "mousedown" or "touchstart" events in the document', () => {
for (let event of ['mousedown', 'touchstart']) { for (let event of ['mousedown', 'touchstart']) {
rootElement.dispatchEvent(new Event(event)); rootElement.dispatchEvent(new Event(event));
assert.calledWith(fakeBridge.call, 'closeSidebar'); assert.calledWith(sidebarBridge().call, 'closeSidebar');
fakeBridge.call.resetHistory(); sidebarBridge().call.resetHistory();
} }
}); });
...@@ -416,8 +465,8 @@ describe('Guest', () => { ...@@ -416,8 +465,8 @@ describe('Guest', () => {
rootElement.dispatchEvent(new Event(event)); rootElement.dispatchEvent(new Event(event));
assert.notCalled(fakeBridge.call); assert.notCalled(sidebarBridge().call);
fakeBridge.call.resetHistory(); sidebarBridge().call.resetHistory();
} }
}); });
...@@ -447,20 +496,20 @@ describe('Guest', () => { ...@@ -447,20 +496,20 @@ describe('Guest', () => {
// Hover the highlight // Hover the highlight
fakeHighlight.dispatchEvent(new Event('mouseover', { bubbles: true })); fakeHighlight.dispatchEvent(new Event('mouseover', { bubbles: true }));
assert.calledWith(highlighter.getHighlightsContainingNode, fakeHighlight); assert.calledWith(highlighter.getHighlightsContainingNode, fakeHighlight);
assert.calledWith(fakeBridge.call, 'focusAnnotations', [ assert.calledWith(sidebarBridge().call, 'focusAnnotations', [
'highlight-ann-tag', 'highlight-ann-tag',
]); ]);
// Un-hover the highlight // Un-hover the highlight
fakeHighlight.dispatchEvent(new Event('mouseout', { bubbles: true })); fakeHighlight.dispatchEvent(new Event('mouseout', { bubbles: true }));
assert.calledWith(fakeBridge.call, 'focusAnnotations', []); assert.calledWith(sidebarBridge().call, 'focusAnnotations', []);
}); });
it('does not focus annotations in the sidebar when a non-highlight element is hovered', () => { it('does not focus annotations in the sidebar when a non-highlight element is hovered', () => {
rootElement.dispatchEvent(new Event('mouseover', { bubbles: true })); rootElement.dispatchEvent(new Event('mouseover', { bubbles: true }));
assert.calledWith(highlighter.getHighlightsContainingNode, rootElement); assert.calledWith(highlighter.getHighlightsContainingNode, rootElement);
assert.notCalled(fakeBridge.call); assert.notCalled(sidebarBridge().call);
}); });
it('does not focus or select annotations in the sidebar if highlights are hidden', () => { it('does not focus or select annotations in the sidebar if highlights are hidden', () => {
...@@ -470,16 +519,16 @@ describe('Guest', () => { ...@@ -470,16 +519,16 @@ describe('Guest', () => {
fakeHighlight.dispatchEvent(new Event('mouseup', { bubbles: true })); fakeHighlight.dispatchEvent(new Event('mouseup', { bubbles: true }));
assert.calledWith(highlighter.getHighlightsContainingNode, fakeHighlight); assert.calledWith(highlighter.getHighlightsContainingNode, fakeHighlight);
assert.notCalled(fakeBridge.call); assert.notCalled(sidebarBridge().call);
}); });
it('selects annotations in the sidebar when clicking on a highlight', () => { it('selects annotations in the sidebar when clicking on a highlight', () => {
fakeHighlight.dispatchEvent(new Event('mouseup', { bubbles: true })); fakeHighlight.dispatchEvent(new Event('mouseup', { bubbles: true }));
assert.calledWith(fakeBridge.call, 'showAnnotations', [ assert.calledWith(sidebarBridge().call, 'showAnnotations', [
'highlight-ann-tag', 'highlight-ann-tag',
]); ]);
assert.calledWith(fakeBridge.call, 'openSidebar'); assert.calledWith(sidebarBridge().call, 'openSidebar');
}); });
it('toggles selected annotations in the sidebar when Ctrl/Cmd-clicking a highlight', () => { it('toggles selected annotations in the sidebar when Ctrl/Cmd-clicking a highlight', () => {
...@@ -487,10 +536,10 @@ describe('Guest', () => { ...@@ -487,10 +536,10 @@ describe('Guest', () => {
new MouseEvent('mouseup', { bubbles: true, ctrlKey: true }) new MouseEvent('mouseup', { bubbles: true, ctrlKey: true })
); );
assert.calledWith(fakeBridge.call, 'toggleAnnotationSelection', [ assert.calledWith(sidebarBridge().call, 'toggleAnnotationSelection', [
'highlight-ann-tag', 'highlight-ann-tag',
]); ]);
assert.calledWith(fakeBridge.call, 'openSidebar'); assert.calledWith(sidebarBridge().call, 'openSidebar');
}); });
}); });
...@@ -572,7 +621,7 @@ describe('Guest', () => { ...@@ -572,7 +621,7 @@ describe('Guest', () => {
simulateSelectionWithText(); simulateSelectionWithText();
assert.calledWith(fakeBridge.call, 'textSelectedIn', null); assert.calledWith(hostBridge().call, 'textSelectedIn', null);
}); });
it('calls "textSelectedIn" RPC method with the subFrameIdentifier as argument if selection is non-empty', () => { it('calls "textSelectedIn" RPC method with the subFrameIdentifier as argument if selection is non-empty', () => {
...@@ -581,7 +630,11 @@ describe('Guest', () => { ...@@ -581,7 +630,11 @@ describe('Guest', () => {
simulateSelectionWithText(); simulateSelectionWithText();
assert.calledWith(fakeBridge.call, 'textSelectedIn', subFrameIdentifier); assert.calledWith(
hostBridge().call,
'textSelectedIn',
subFrameIdentifier
);
}); });
it('calls "textUnselectedIn" RPC method with argument "null" if selection is empty', () => { it('calls "textUnselectedIn" RPC method with argument "null" if selection is empty', () => {
...@@ -589,7 +642,7 @@ describe('Guest', () => { ...@@ -589,7 +642,7 @@ describe('Guest', () => {
simulateSelectionWithoutText(); simulateSelectionWithoutText();
assert.calledWith(fakeBridge.call, 'textUnselectedIn', null); assert.calledWith(hostBridge().call, 'textUnselectedIn', null);
}); });
it('calls "textUnselectedIn" RPC method with the subFrameIdentifier as argument if selection is empty', () => { it('calls "textUnselectedIn" RPC method with the subFrameIdentifier as argument if selection is empty', () => {
...@@ -599,7 +652,7 @@ describe('Guest', () => { ...@@ -599,7 +652,7 @@ describe('Guest', () => {
simulateSelectionWithoutText(); simulateSelectionWithoutText();
assert.calledWith( assert.calledWith(
fakeBridge.call, hostBridge().call,
'textUnselectedIn', 'textUnselectedIn',
subFrameIdentifier subFrameIdentifier
); );
...@@ -610,35 +663,29 @@ describe('Guest', () => { ...@@ -610,35 +663,29 @@ describe('Guest', () => {
sandbox.stub(document, 'getSelection').returns({ removeAllRanges }); sandbox.stub(document, 'getSelection').returns({ removeAllRanges });
const guest = createGuest(); const guest = createGuest();
guest.selectedRanges = [1]; guest.selectedRanges = [1];
const handler = fakeBridge.on
.getCalls()
.find(call => call.args[0] === 'clearSelectionExceptIn').args[1];
simulateSelectionWithText(); simulateSelectionWithText();
fakeBridge.call.resetHistory(); hostBridge().call.resetHistory();
handler('subframe identifier'); emitHostEvent('clearSelectionExceptIn', 'subframe identifier');
assert.calledOnce(removeAllRanges); assert.calledOnce(removeAllRanges);
notifySelectionChanged(null); // removing the text selection triggers the selection observer notifySelectionChanged(null); // removing the text selection triggers the selection observer
assert.equal(guest.selectedRanges.length, 0); assert.equal(guest.selectedRanges.length, 0);
assert.notCalled(fakeBridge.call); assert.notCalled(hostBridge().call);
// On next selection clear it should be inform the host. // On next selection clear it should be inform the host.
notifySelectionChanged(null); notifySelectionChanged(null);
assert.calledOnce(fakeBridge.call); assert.calledOnce(hostBridge().call);
assert.calledWithExactly(fakeBridge.call, 'textUnselectedIn', null); assert.calledWithExactly(hostBridge().call, 'textUnselectedIn', null);
}); });
it("doesn't unselect text if frame identifier matches", () => { it("doesn't unselect text if frame identifier matches", () => {
const guest = createGuest(); const guest = createGuest();
guest.selectedRanges = [1]; guest.selectedRanges = [1];
const handler = fakeBridge.on
.getCalls()
.find(call => call.args[0] === 'clearSelectionExceptIn').args[1];
simulateSelectionWithText(); simulateSelectionWithText();
handler(null); // it matches the frameIdentifier in the host frame emitHostEvent('clearSelectionExceptIn', null);
assert.equal(guest.selectedRanges.length, 1); assert.equal(guest.selectedRanges.length, 1);
}); });
...@@ -652,7 +699,7 @@ describe('Guest', () => { ...@@ -652,7 +699,7 @@ describe('Guest', () => {
await FakeAdder.instance.options.onAnnotate(); await FakeAdder.instance.options.onAnnotate();
assert.calledWith(fakeBridge.call, 'createAnnotation'); assert.calledWith(sidebarBridge().call, 'createAnnotation');
}); });
it('creates a new highlight if "Highlight" is clicked', async () => { it('creates a new highlight if "Highlight" is clicked', async () => {
...@@ -661,7 +708,7 @@ describe('Guest', () => { ...@@ -661,7 +708,7 @@ describe('Guest', () => {
await FakeAdder.instance.options.onHighlight(); await FakeAdder.instance.options.onHighlight();
assert.calledWith( assert.calledWith(
fakeBridge.call, sidebarBridge().call,
'createAnnotation', 'createAnnotation',
sinon.match({ $highlight: true }) sinon.match({ $highlight: true })
); );
...@@ -672,8 +719,8 @@ describe('Guest', () => { ...@@ -672,8 +719,8 @@ describe('Guest', () => {
FakeAdder.instance.options.onShowAnnotations([{ $tag: 'ann1' }]); FakeAdder.instance.options.onShowAnnotations([{ $tag: 'ann1' }]);
assert.calledWith(fakeBridge.call, 'openSidebar'); assert.calledWith(sidebarBridge().call, 'openSidebar');
assert.calledWith(fakeBridge.call, 'showAnnotations', ['ann1']); assert.calledWith(sidebarBridge().call, 'showAnnotations', ['ann1']);
}); });
}); });
...@@ -684,7 +731,10 @@ describe('Guest', () => { ...@@ -684,7 +731,10 @@ describe('Guest', () => {
guest.selectAnnotations(annotations); guest.selectAnnotations(annotations);
assert.calledWith(fakeBridge.call, 'showAnnotations', ['ann1', 'ann2']); assert.calledWith(sidebarBridge().call, 'showAnnotations', [
'ann1',
'ann2',
]);
}); });
it('toggles the annotations if `toggle` is true', () => { it('toggles the annotations if `toggle` is true', () => {
...@@ -693,7 +743,7 @@ describe('Guest', () => { ...@@ -693,7 +743,7 @@ describe('Guest', () => {
guest.selectAnnotations(annotations, true /* toggle */); guest.selectAnnotations(annotations, true /* toggle */);
assert.calledWith(fakeBridge.call, 'toggleAnnotationSelection', [ assert.calledWith(sidebarBridge().call, 'toggleAnnotationSelection', [
'ann1', 'ann1',
'ann2', 'ann2',
]); ]);
...@@ -704,7 +754,7 @@ describe('Guest', () => { ...@@ -704,7 +754,7 @@ describe('Guest', () => {
guest.selectAnnotations([]); guest.selectAnnotations([]);
assert.calledWith(fakeBridge.call, 'openSidebar'); assert.calledWith(sidebarBridge().call, 'openSidebar');
}); });
}); });
...@@ -754,18 +804,18 @@ describe('Guest', () => { ...@@ -754,18 +804,18 @@ describe('Guest', () => {
}); });
describe('#createAnnotation', () => { describe('#createAnnotation', () => {
it('creates an annotation if host calls "createAnnotationIn" RPC method', () => { it('creates an annotation if host calls "createAnnotationIn" RPC method', async () => {
const guest = createGuest(); createGuest();
sinon.stub(guest, 'createAnnotation');
const handler = fakeBridge.on
.getCalls()
.find(call => call.args[0] === 'createAnnotationIn').args[1];
handler('dummy'); emitHostEvent('createAnnotationIn', 'dummy');
assert.notCalled(guest.createAnnotation); await delay(0);
handler(null); assert.notCalled(sidebarBridge().call);
assert.calledOnce(guest.createAnnotation);
emitHostEvent('createAnnotationIn', null);
await delay(0);
assert.calledWith(sidebarBridge().call, 'createAnnotation');
}); });
it('adds document metadata to the annotation', async () => { it('adds document metadata to the annotation', async () => {
...@@ -836,7 +886,7 @@ describe('Guest', () => { ...@@ -836,7 +886,7 @@ describe('Guest', () => {
const annotation = await guest.createAnnotation(); const annotation = await guest.createAnnotation();
assert.calledWith(fakeBridge.call, 'createAnnotation', annotation); assert.calledWith(sidebarBridge().call, 'createAnnotation', annotation);
}); });
}); });
...@@ -981,7 +1031,11 @@ describe('Guest', () => { ...@@ -981,7 +1031,11 @@ describe('Guest', () => {
const guest = createGuest(); const guest = createGuest();
const annotation = {}; const annotation = {};
return guest.anchor(annotation).then(() => { return guest.anchor(annotation).then(() => {
assert.calledWith(fakeBridge.call, 'syncAnchoringStatus', annotation); assert.calledWith(
sidebarBridge().call,
'syncAnchoringStatus',
annotation
);
}); });
}); });
...@@ -991,7 +1045,7 @@ describe('Guest', () => { ...@@ -991,7 +1045,7 @@ describe('Guest', () => {
await guest.anchor(annotation); await guest.anchor(annotation);
assert.match(fakeBridge.call.lastCall.args, [ assert.match(sidebarBridge().call.lastCall.args, [
'syncAnchoringStatus', 'syncAnchoringStatus',
annotation, annotation,
]); ]);
...@@ -1054,7 +1108,7 @@ describe('Guest', () => { ...@@ -1054,7 +1108,7 @@ describe('Guest', () => {
const annotation = { $tag: 'tag1', target: [target] }; const annotation = { $tag: 'tag1', target: [target] };
// Focus the annotation (in the sidebar) before it is anchored in the page. // Focus the annotation (in the sidebar) before it is anchored in the page.
const [, focusAnnotationsCallback] = fakeBridge.on.args.find( const [, focusAnnotationsCallback] = sidebarBridge().on.args.find(
args => args[0] === 'focusAnnotations' args => args[0] === 'focusAnnotations'
); );
focusAnnotationsCallback([annotation.$tag]); focusAnnotationsCallback([annotation.$tag]);
...@@ -1136,7 +1190,7 @@ describe('Guest', () => { ...@@ -1136,7 +1190,7 @@ describe('Guest', () => {
guest.detach(anchor.annotation.$tag); guest.detach(anchor.annotation.$tag);
assert.deepEqual(fakeBridge.call.lastCall.args, ['anchorsChanged']); assert.deepEqual(hostBridge().call.lastCall.args, ['anchorsChanged']);
}); });
}); });
...@@ -1144,7 +1198,7 @@ describe('Guest', () => { ...@@ -1144,7 +1198,7 @@ describe('Guest', () => {
it('disconnects from sidebar events', () => { it('disconnects from sidebar events', () => {
const guest = createGuest(); const guest = createGuest();
guest.destroy(); guest.destroy();
assert.calledOnce(fakeBridge.destroy); assert.calledOnce(sidebarBridge().destroy);
}); });
it('removes the adder toolbar', () => { it('removes the adder toolbar', () => {
...@@ -1169,7 +1223,7 @@ describe('Guest', () => { ...@@ -1169,7 +1223,7 @@ describe('Guest', () => {
it('disconnects from sidebar', () => { it('disconnects from sidebar', () => {
const guest = createGuest(); const guest = createGuest();
guest.destroy(); guest.destroy();
assert.called(fakeBridge.destroy); assert.called(sidebarBridge().destroy);
}); });
it('notifies host frame that guest has been unloaded', () => { it('notifies host frame that guest has been unloaded', () => {
...@@ -1216,7 +1270,7 @@ describe('Guest', () => { ...@@ -1216,7 +1270,7 @@ describe('Guest', () => {
await delay(0); await delay(0);
assert.calledWith(fakeBridge.createChannel, port1); assert.calledWith(sidebarBridge().createChannel, port1);
}); });
describe('#contentContainer', () => { describe('#contentContainer', () => {
......
...@@ -18,7 +18,8 @@ describe('Sidebar', () => { ...@@ -18,7 +18,8 @@ describe('Sidebar', () => {
let containers; let containers;
let sidebars; let sidebars;
let fakeBridge; let FakeBridge;
let fakeBridges;
let FakeBucketBar; let FakeBucketBar;
let fakeBucketBar; let fakeBucketBar;
let fakeGuest; let fakeGuest;
...@@ -34,13 +35,44 @@ describe('Sidebar', () => { ...@@ -34,13 +35,44 @@ describe('Sidebar', () => {
window.requestAnimationFrame.restore(); window.requestAnimationFrame.restore();
}); });
// Helpers for getting the channels used for host <-> guest/sidebar communication.
// These currently rely on knowing the implementation detail of which order
// the channels are created in.
const guestBridge = () => {
return fakeBridges[0];
};
const sidebarBridge = () => {
return fakeBridges[1];
};
const emitGuestEvent = (event, ...args) => {
const result = [];
for (let [evt, fn] of guestBridge().on.args) {
if (event === evt) {
result.push(fn(...args));
}
}
return result;
};
const emitSidebarEvent = (event, ...args) => {
const result = [];
for (let [evt, fn] of sidebarBridge().on.args) {
if (event === evt) {
result.push(fn(...args));
}
}
return result;
};
/** /**
* Simulate the sidebar application connecting with the host frame. This happens * Simulate the sidebar application connecting with the host frame. This happens
* when the sidebar has loaded and is ready. * when the sidebar has loaded and is ready.
*/ */
const connectSidebarApp = () => { const connectSidebarApp = () => {
const callback = fakeBridge.onConnect.getCall(0).args[0]; const callback = sidebarBridge().onConnect.getCall(0).args[0];
callback(); callback();
}; };
...@@ -77,13 +109,18 @@ describe('Sidebar', () => { ...@@ -77,13 +109,18 @@ describe('Sidebar', () => {
sidebars = []; sidebars = [];
containers = []; containers = [];
fakeBridge = { fakeBridges = [];
FakeBridge = sinon.stub().callsFake(() => {
const bridge = {
call: sinon.stub(), call: sinon.stub(),
createChannel: sinon.stub(), createChannel: sinon.stub(),
destroy: sinon.stub(),
on: sinon.stub(), on: sinon.stub(),
onConnect: sinon.stub(), onConnect: sinon.stub(),
destroy: sinon.stub(),
}; };
fakeBridges.push(bridge);
return bridge;
});
fakeBucketBar = { fakeBucketBar = {
destroy: sinon.stub(), destroy: sinon.stub(),
...@@ -93,11 +130,7 @@ describe('Sidebar', () => { ...@@ -93,11 +130,7 @@ describe('Sidebar', () => {
class FakeGuest { class FakeGuest {
constructor() { constructor() {
this.element = document.createElement('div');
this.contentContainer = sinon.stub().returns(document.body); this.contentContainer = sinon.stub().returns(document.body);
this.createAnnotation = sinon.stub();
this.fitSideBySide = sinon.stub();
this.setHighlightsVisible = sinon.stub();
} }
} }
fakeGuest = new FakeGuest(); fakeGuest = new FakeGuest();
...@@ -121,7 +154,7 @@ describe('Sidebar', () => { ...@@ -121,7 +154,7 @@ describe('Sidebar', () => {
}); });
$imports.$mock({ $imports.$mock({
'../shared/bridge': { Bridge: sinon.stub().returns(fakeBridge) }, '../shared/bridge': { Bridge: FakeBridge },
'../shared/frame-error-capture': { sendErrorsTo: fakeSendErrorsTo }, '../shared/frame-error-capture': { sendErrorsTo: fakeSendErrorsTo },
'./bucket-bar': { default: FakeBucketBar }, './bucket-bar': { default: FakeBucketBar },
'./config/app': { createAppConfig: fakeCreateAppConfig }, './config/app': { createAppConfig: fakeCreateAppConfig },
...@@ -192,7 +225,7 @@ describe('Sidebar', () => { ...@@ -192,7 +225,7 @@ describe('Sidebar', () => {
}); });
window.dispatchEvent(event); window.dispatchEvent(event);
assert.calledWith(fakeBridge.call, 'frameDestroyed', 'frame-id'); assert.calledWith(sidebarBridge().call, 'frameDestroyed', 'frame-id');
}); });
function getConfigString(sidebar) { function getConfigString(sidebar) {
...@@ -237,36 +270,33 @@ describe('Sidebar', () => { ...@@ -237,36 +270,33 @@ describe('Sidebar', () => {
FakeToolbarController.args[0][1].createAnnotation(); FakeToolbarController.args[0][1].createAnnotation();
assert.calledWith(fakeBridge.call, 'createAnnotationIn', null); assert.calledWith(guestBridge().call, 'createAnnotationIn', null);
}); });
it('creates an annotation in frame with selection when toolbar button is clicked', () => { it('creates an annotation in frame with selection when toolbar button is clicked', () => {
createSidebar({}); createSidebar({});
// Make a text selection in another frame
const handler = fakeBridge.on
.getCalls()
.find(call => call.args[0] === 'textSelectedIn').args[1];
const frameIdentifier = 'subframe identifier'; const frameIdentifier = 'subframe identifier';
handler(frameIdentifier); emitGuestEvent('textSelectedIn', frameIdentifier);
FakeToolbarController.args[0][1].createAnnotation(); FakeToolbarController.args[0][1].createAnnotation();
assert.calledWith(fakeBridge.call, 'createAnnotationIn', frameIdentifier); assert.calledWith(
guestBridge().call,
'createAnnotationIn',
frameIdentifier
);
}); });
it('toggles create annotation button to "Annotation" when selection becomes non-empty', () => { it('toggles create annotation button to "Annotation" when selection becomes non-empty', () => {
const sidebar = createSidebar(); const sidebar = createSidebar();
const frameIdentifier = 'subframe identifier'; const frameIdentifier = 'subframe identifier';
const handler = fakeBridge.on emitGuestEvent('textSelectedIn', frameIdentifier);
.getCalls()
.find(call => call.args[0] === 'textSelectedIn').args[1];
handler(frameIdentifier);
assert.equal(sidebar.toolbar.newAnnotationType, 'annotation'); assert.equal(sidebar.toolbar.newAnnotationType, 'annotation');
assert.calledWith( assert.calledWith(
fakeBridge.call, guestBridge().call,
'clearSelectionExceptIn', 'clearSelectionExceptIn',
frameIdentifier frameIdentifier
); );
...@@ -276,36 +306,23 @@ describe('Sidebar', () => { ...@@ -276,36 +306,23 @@ describe('Sidebar', () => {
const sidebar = createSidebar(); const sidebar = createSidebar();
const frameIdentifier = null; const frameIdentifier = null;
const handler = fakeBridge.on emitGuestEvent('textUnselectedIn', frameIdentifier);
.getCalls()
.find(call => call.args[0] === 'textUnselectedIn').args[1];
handler(frameIdentifier);
assert.equal(sidebar.toolbar.newAnnotationType, 'note'); assert.equal(sidebar.toolbar.newAnnotationType, 'note');
assert.calledWith( assert.calledWith(
fakeBridge.call, guestBridge().call,
'clearSelectionExceptIn', 'clearSelectionExceptIn',
frameIdentifier frameIdentifier
); );
}); });
}); });
describe('sidebar RPC call handlers', () => { describe('events from sidebar frame', () => {
const emitEvent = (event, ...args) => {
const result = [];
for (let [evt, fn] of fakeBridge.on.args) {
if (event === evt) {
result.push(fn(...args));
}
}
return result;
};
describe('on "showHighlights" event', () => { describe('on "showHighlights" event', () => {
it('makes all highlights visible', () => { it('makes all highlights visible', () => {
createSidebar(); createSidebar();
assert.isFalse(fakeToolbar.highlightsVisible); assert.isFalse(fakeToolbar.highlightsVisible);
emitEvent('showHighlights'); emitSidebarEvent('showHighlights');
assert.isTrue(fakeToolbar.highlightsVisible); assert.isTrue(fakeToolbar.highlightsVisible);
}); });
}); });
...@@ -314,7 +331,7 @@ describe('Sidebar', () => { ...@@ -314,7 +331,7 @@ describe('Sidebar', () => {
it('opens the frame', () => { it('opens the frame', () => {
const target = sandbox.stub(Sidebar.prototype, 'open'); const target = sandbox.stub(Sidebar.prototype, 'open');
createSidebar(); createSidebar();
emitEvent('openSidebar'); emitSidebarEvent('openSidebar');
assert.called(target); assert.called(target);
})); }));
...@@ -322,7 +339,7 @@ describe('Sidebar', () => { ...@@ -322,7 +339,7 @@ describe('Sidebar', () => {
it('closes the frame', () => { it('closes the frame', () => {
const target = sandbox.stub(Sidebar.prototype, 'close'); const target = sandbox.stub(Sidebar.prototype, 'close');
createSidebar(); createSidebar();
emitEvent('closeSidebar'); emitSidebarEvent('closeSidebar');
assert.called(target); assert.called(target);
})); }));
...@@ -331,7 +348,7 @@ describe('Sidebar', () => { ...@@ -331,7 +348,7 @@ describe('Sidebar', () => {
const sidebar = createSidebar(); const sidebar = createSidebar();
sinon.stub(sidebar, 'hide').callThrough(); sinon.stub(sidebar, 'hide').callThrough();
sinon.stub(sidebar._emitter, 'publish'); sinon.stub(sidebar._emitter, 'publish');
emitEvent('openNotebook', 'mygroup'); emitSidebarEvent('openNotebook', 'mygroup');
assert.calledWith(sidebar._emitter.publish, 'openNotebook', 'mygroup'); assert.calledWith(sidebar._emitter.publish, 'openNotebook', 'mygroup');
assert.calledOnce(sidebar.hide); assert.calledOnce(sidebar.hide);
assert.notEqual(sidebar.iframeContainer.style.visibility, 'hidden'); assert.notEqual(sidebar.iframeContainer.style.visibility, 'hidden');
...@@ -353,7 +370,7 @@ describe('Sidebar', () => { ...@@ -353,7 +370,7 @@ describe('Sidebar', () => {
const onLoginRequest = sandbox.stub(); const onLoginRequest = sandbox.stub();
createSidebar({ services: [{ onLoginRequest }] }); createSidebar({ services: [{ onLoginRequest }] });
emitEvent('loginRequested'); emitSidebarEvent('loginRequested');
assert.called(onLoginRequest); assert.called(onLoginRequest);
}); });
...@@ -373,7 +390,7 @@ describe('Sidebar', () => { ...@@ -373,7 +390,7 @@ describe('Sidebar', () => {
], ],
}); });
emitEvent('loginRequested'); emitSidebarEvent('loginRequested');
assert.called(firstOnLogin); assert.called(firstOnLogin);
assert.notCalled(secondOnLogin); assert.notCalled(secondOnLogin);
...@@ -393,7 +410,7 @@ describe('Sidebar', () => { ...@@ -393,7 +410,7 @@ describe('Sidebar', () => {
], ],
}); });
emitEvent('loginRequested'); emitSidebarEvent('loginRequested');
assert.notCalled(secondOnLogin); assert.notCalled(secondOnLogin);
assert.notCalled(thirdOnLogin); assert.notCalled(thirdOnLogin);
...@@ -401,17 +418,17 @@ describe('Sidebar', () => { ...@@ -401,17 +418,17 @@ describe('Sidebar', () => {
it('does not crash if there is no services', () => { it('does not crash if there is no services', () => {
createSidebar(); // No config.services createSidebar(); // No config.services
emitEvent('loginRequested'); emitSidebarEvent('loginRequested');
}); });
it('does not crash if services is an empty array', () => { it('does not crash if services is an empty array', () => {
createSidebar({ services: [] }); createSidebar({ services: [] });
emitEvent('loginRequested'); emitSidebarEvent('loginRequested');
}); });
it('does not crash if the first service has no onLoginRequest', () => { it('does not crash if the first service has no onLoginRequest', () => {
createSidebar({ services: [{}] }); createSidebar({ services: [{}] });
emitEvent('loginRequested'); emitSidebarEvent('loginRequested');
}); });
}); });
...@@ -420,7 +437,7 @@ describe('Sidebar', () => { ...@@ -420,7 +437,7 @@ describe('Sidebar', () => {
const onLogoutRequest = sandbox.stub(); const onLogoutRequest = sandbox.stub();
createSidebar({ services: [{ onLogoutRequest }] }); createSidebar({ services: [{ onLogoutRequest }] });
emitEvent('logoutRequested'); emitSidebarEvent('logoutRequested');
assert.called(onLogoutRequest); assert.called(onLogoutRequest);
})); }));
...@@ -430,7 +447,7 @@ describe('Sidebar', () => { ...@@ -430,7 +447,7 @@ describe('Sidebar', () => {
const onSignupRequest = sandbox.stub(); const onSignupRequest = sandbox.stub();
createSidebar({ services: [{ onSignupRequest }] }); createSidebar({ services: [{ onSignupRequest }] });
emitEvent('signupRequested'); emitSidebarEvent('signupRequested');
assert.called(onSignupRequest); assert.called(onSignupRequest);
})); }));
...@@ -440,7 +457,7 @@ describe('Sidebar', () => { ...@@ -440,7 +457,7 @@ describe('Sidebar', () => {
const onProfileRequest = sandbox.stub(); const onProfileRequest = sandbox.stub();
createSidebar({ services: [{ onProfileRequest }] }); createSidebar({ services: [{ onProfileRequest }] });
emitEvent('profileRequested'); emitSidebarEvent('profileRequested');
assert.called(onProfileRequest); assert.called(onProfileRequest);
})); }));
...@@ -450,16 +467,18 @@ describe('Sidebar', () => { ...@@ -450,16 +467,18 @@ describe('Sidebar', () => {
const onHelpRequest = sandbox.stub(); const onHelpRequest = sandbox.stub();
createSidebar({ services: [{ onHelpRequest }] }); createSidebar({ services: [{ onHelpRequest }] });
emitEvent('helpRequested'); emitSidebarEvent('helpRequested');
assert.called(onHelpRequest); assert.called(onHelpRequest);
})); }));
});
describe('events from the guest frames', () => {
describe('on "anchorsChanged" event', () => { describe('on "anchorsChanged" event', () => {
it('updates the bucket bar', () => { it('updates the bucket bar', () => {
const sidebar = createSidebar(); const sidebar = createSidebar();
emitEvent('anchorsChanged'); emitGuestEvent('anchorsChanged');
assert.calledOnce(sidebar.bucketBar.update); assert.calledOnce(sidebar.bucketBar.update);
}); });
...@@ -599,7 +618,7 @@ describe('Sidebar', () => { ...@@ -599,7 +618,7 @@ describe('Sidebar', () => {
const { port1 } = new MessageChannel(); const { port1 } = new MessageChannel();
sidebar.onFrameConnected('dummy', port1); sidebar.onFrameConnected('dummy', port1);
assert.notCalled(fakeBridge.createChannel); assert.notCalled(sidebarBridge().createChannel);
}); });
it('create RPC channels for recognized source frames', () => { it('create RPC channels for recognized source frames', () => {
...@@ -607,7 +626,7 @@ describe('Sidebar', () => { ...@@ -607,7 +626,7 @@ describe('Sidebar', () => {
const { port1 } = new MessageChannel(); const { port1 } = new MessageChannel();
sidebar.onFrameConnected('sidebar', port1); sidebar.onFrameConnected('sidebar', port1);
assert.calledWith(fakeBridge.createChannel, port1); assert.calledWith(sidebarBridge().createChannel, port1);
}); });
}); });
...@@ -615,13 +634,13 @@ describe('Sidebar', () => { ...@@ -615,13 +634,13 @@ describe('Sidebar', () => {
it('shows highlights if "showHighlights" is set to "whenSidebarOpen"', () => { it('shows highlights if "showHighlights" is set to "whenSidebarOpen"', () => {
const sidebar = createSidebar({ showHighlights: 'whenSidebarOpen' }); const sidebar = createSidebar({ showHighlights: 'whenSidebarOpen' });
sidebar.open(); sidebar.open();
assert.calledWith(fakeBridge.call, 'setHighlightsVisible', true); assert.calledWith(sidebarBridge().call, 'setHighlightsVisible', true);
}); });
it('does not show highlights otherwise', () => { it('does not show highlights otherwise', () => {
const sidebar = createSidebar({ showHighlights: 'never' }); const sidebar = createSidebar({ showHighlights: 'never' });
sidebar.open(); sidebar.open();
assert.neverCalledWith(fakeBridge.call, 'setHighlightsVisible'); assert.neverCalledWith(sidebarBridge().call, 'setHighlightsVisible');
}); });
it('updates the `sidebarOpen` property of the toolbar', () => { it('updates the `sidebarOpen` property of the toolbar', () => {
...@@ -638,7 +657,7 @@ describe('Sidebar', () => { ...@@ -638,7 +657,7 @@ describe('Sidebar', () => {
sidebar.open(); sidebar.open();
sidebar.close(); sidebar.close();
assert.calledWith(fakeBridge.call, 'setHighlightsVisible', false); assert.calledWith(sidebarBridge().call, 'setHighlightsVisible', false);
}); });
it('updates the `sidebarOpen` property of the toolbar', () => { it('updates the `sidebarOpen` property of the toolbar', () => {
...@@ -657,7 +676,7 @@ describe('Sidebar', () => { ...@@ -657,7 +676,7 @@ describe('Sidebar', () => {
const { port1 } = new MessageChannel(); const { port1 } = new MessageChannel();
sidebar.onFrameConnected('guest', port1); sidebar.onFrameConnected('guest', port1);
assert.calledWith(fakeBridge.createChannel, port1); assert.calledWith(guestBridge().createChannel, port1);
}); });
}); });
...@@ -665,10 +684,10 @@ describe('Sidebar', () => { ...@@ -665,10 +684,10 @@ describe('Sidebar', () => {
it('requests sidebar to set highlight visibility in guest frames', () => { it('requests sidebar to set highlight visibility in guest frames', () => {
const sidebar = createSidebar(); const sidebar = createSidebar();
sidebar.setHighlightsVisible(true); sidebar.setHighlightsVisible(true);
assert.calledWith(fakeBridge.call, 'setHighlightsVisible', true); assert.calledWith(sidebarBridge().call, 'setHighlightsVisible', true);
sidebar.setHighlightsVisible(false); sidebar.setHighlightsVisible(false);
assert.calledWith(fakeBridge.call, 'setHighlightsVisible', false); assert.calledWith(sidebarBridge().call, 'setHighlightsVisible', false);
}); });
it('toggles "Show highlights" control in toolbar', () => { it('toggles "Show highlights" control in toolbar', () => {
...@@ -774,51 +793,27 @@ describe('Sidebar', () => { ...@@ -774,51 +793,27 @@ describe('Sidebar', () => {
frame.remove(); frame.remove();
}); });
it('notifies when sidebar changes expanded state', () => { it('calls the "sidebarLayoutChanged" RPC method when sidebar changes expanded state', () => {
sinon.stub(sidebar._emitter, 'publish'); guestBridge().call.resetHistory();
sidebar.open(); sidebar.open();
assert.calledOnce(layoutChangeHandlerSpy); assert.calledOnce(guestBridge().call);
assert.calledWith( assert.calledWith(
sidebar._emitter.publish, guestBridge().call,
'sidebarLayoutChanged', 'sidebarLayoutChanged',
sinon.match.any sinon.match.any
); );
assert.calledOnce(sidebar._emitter.publish); assertLayoutValues(guestBridge().call.lastCall.args[1], {
assertLayoutValues(layoutChangeHandlerSpy.lastCall.args[0], {
expanded: true, expanded: true,
}); });
sidebar.close(); sidebar.close();
assert.calledTwice(layoutChangeHandlerSpy); assert.calledTwice(guestBridge().call);
assert.calledTwice(sidebar._emitter.publish); assertLayoutValues(guestBridge().call.lastCall.args[1], {
assertLayoutValues(layoutChangeHandlerSpy.lastCall.args[0], {
expanded: false, expanded: false,
width: fakeToolbar.getWidth(), width: fakeToolbar.getWidth(),
}); });
}); });
it('attempts to fit the content alongside the sidebar', () => {
fakeGuest.fitSideBySide.resetHistory();
sidebar.open();
assert.calledWith(
fakeGuest.fitSideBySide,
sinon.match({
expanded: true,
width: DEFAULT_WIDTH + fakeToolbar.getWidth(),
})
);
fakeGuest.fitSideBySide.resetHistory();
sidebar.close();
assert.calledWith(
fakeGuest.fitSideBySide,
sinon.match({
expanded: false,
width: fakeToolbar.getWidth(),
})
);
});
it('notifies when sidebar is panned left', () => { it('notifies when sidebar is panned left', () => {
sidebar._gestureState = { initial: -DEFAULT_WIDTH }; sidebar._gestureState = { initial: -DEFAULT_WIDTH };
sidebar._onPan({ type: 'panleft', deltaX: -50 }); sidebar._onPan({ type: 'panleft', deltaX: -50 });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment