Commit 5b9404ec authored by Robert Knight's avatar Robert Knight

Remove document type specific details from Guest tests

The Guest implementation no longer has any logic which is specific to a
particular document type (PDF, HTML etc.). These details are now all
handled by the Integration implementation returned by
`createIntegration`.

This commit refactors the Guest tests to use a single Integration fake
instead of using different fakes to simulate HTML and PDF documents.
parent d567db8c
...@@ -39,9 +39,8 @@ describe('Guest', () => { ...@@ -39,9 +39,8 @@ describe('Guest', () => {
let fakeCrossFrame; let fakeCrossFrame;
let fakeCreateIntegration; let fakeCreateIntegration;
let fakeHTMLIntegration; let fakeIntegration;
let fakePDFIntegration;
let guests; let guests;
const createGuest = (config = {}) => { const createGuest = (config = {}) => {
...@@ -79,29 +78,21 @@ describe('Guest', () => { ...@@ -79,29 +78,21 @@ describe('Guest', () => {
}; };
CrossFrame = sandbox.stub().returns(fakeCrossFrame); CrossFrame = sandbox.stub().returns(fakeCrossFrame);
fakeHTMLIntegration = { fakeIntegration = {
anchor: sinon.stub(), anchor: sinon.stub(),
contentContainer: sinon.stub().returns({}), contentContainer: sinon.stub().returns({}),
describe: sinon.stub(), describe: sinon.stub(),
destroy: sinon.stub(), destroy: sinon.stub(),
fitSideBySide: sinon.stub(),
getMetadata: sinon.stub().resolves({ title: 'Test title' }),
scrollToAnchor: sinon.stub().resolves(),
uri: sinon.stub().resolves('https://example.com/test.html'),
};
fakePDFIntegration = {
contentContainer: sinon.stub().returns({}),
destroy: sinon.stub(),
fitSideBySide: sinon.stub().returns(false), fitSideBySide: sinon.stub().returns(false),
getMetadata: sinon getMetadata: sinon.stub().resolves({
.stub() title: 'Test title',
.resolves({ documentFingerprint: 'test-fingerprint' }), documentFingerprint: 'test-fingerprint',
}),
scrollToAnchor: sinon.stub().resolves(), scrollToAnchor: sinon.stub().resolves(),
uri: sinon.stub().resolves('https://example.com/test.pdf'), uri: sinon.stub().resolves('https://example.com/test.pdf'),
}; };
fakeCreateIntegration = sinon.stub().returns(fakeHTMLIntegration); fakeCreateIntegration = sinon.stub().returns(fakeIntegration);
class FakeSelectionObserver { class FakeSelectionObserver {
constructor(callback) { constructor(callback) {
...@@ -287,8 +278,8 @@ describe('Guest', () => { ...@@ -287,8 +278,8 @@ describe('Guest', () => {
emitGuestEvent('scrollToAnnotation', 'tag1'); emitGuestEvent('scrollToAnnotation', 'tag1');
assert.called(fakeHTMLIntegration.scrollToAnchor); assert.called(fakeIntegration.scrollToAnchor);
assert.calledWith(fakeHTMLIntegration.scrollToAnchor, guest.anchors[0]); assert.calledWith(fakeIntegration.scrollToAnchor, guest.anchors[0]);
}); });
it('emits a "scrolltorange" DOM event', () => { it('emits a "scrolltorange" DOM event', () => {
...@@ -330,7 +321,7 @@ describe('Guest', () => { ...@@ -330,7 +321,7 @@ describe('Guest', () => {
emitGuestEvent('scrollToAnnotation', 'tag1'); emitGuestEvent('scrollToAnnotation', 'tag1');
assert.notCalled(fakeHTMLIntegration.scrollToAnchor); assert.notCalled(fakeIntegration.scrollToAnchor);
}); });
it('does nothing if the anchor has no highlights', () => { it('does nothing if the anchor has no highlights', () => {
...@@ -339,7 +330,7 @@ describe('Guest', () => { ...@@ -339,7 +330,7 @@ describe('Guest', () => {
guest.anchors = [{ annotation: { $tag: 'tag1' } }]; guest.anchors = [{ annotation: { $tag: 'tag1' } }];
emitGuestEvent('scrollToAnnotation', 'tag1'); emitGuestEvent('scrollToAnnotation', 'tag1');
assert.notCalled(fakeHTMLIntegration.scrollToAnchor); assert.notCalled(fakeIntegration.scrollToAnchor);
}); });
it("does nothing if the anchor's range cannot be resolved", () => { it("does nothing if the anchor's range cannot be resolved", () => {
...@@ -360,7 +351,7 @@ describe('Guest', () => { ...@@ -360,7 +351,7 @@ describe('Guest', () => {
emitGuestEvent('scrollToAnnotation', 'tag1'); emitGuestEvent('scrollToAnnotation', 'tag1');
assert.notCalled(eventEmitted); assert.notCalled(eventEmitted);
assert.notCalled(fakeHTMLIntegration.scrollToAnchor); assert.notCalled(fakeIntegration.scrollToAnchor);
}); });
}); });
...@@ -385,28 +376,11 @@ describe('Guest', () => { ...@@ -385,28 +376,11 @@ describe('Guest', () => {
}; };
} }
context('in an HTML document', () => { it('calls the callback with document URL and metadata', done => {
it('calls the callback with HTML URL and metadata', done => {
fakeHTMLIntegration.uri.resolves('https://example.com/');
const metadata = { title: 'Example site' };
fakeHTMLIntegration.getMetadata.resolves(metadata);
guest = createGuest();
emitGuestEvent(
'getDocumentInfo',
createCallback('https://example.com/', metadata, done)
);
});
});
context('in a PDF document', () => {
it('calls the callback with PDF URL and metadata', done => {
fakeCreateIntegration.returns(fakePDFIntegration);
guest = createGuest(); guest = createGuest();
const metadata = { title: 'hi' }; const metadata = { title: 'hi' };
fakePDFIntegration.getMetadata.resolves(metadata); fakeIntegration.getMetadata.resolves(metadata);
emitGuestEvent( emitGuestEvent(
'getDocumentInfo', 'getDocumentInfo',
...@@ -414,7 +388,6 @@ describe('Guest', () => { ...@@ -414,7 +388,6 @@ describe('Guest', () => {
); );
}); });
}); });
});
describe('on "setVisibleHighlights" event', () => { describe('on "setVisibleHighlights" event', () => {
it('sets visibility of highlights in document', () => { it('sets visibility of highlights in document', () => {
...@@ -476,7 +449,7 @@ describe('Guest', () => { ...@@ -476,7 +449,7 @@ describe('Guest', () => {
it('does not hide sidebar if side-by-side mode is active', () => { it('does not hide sidebar if side-by-side mode is active', () => {
for (let event of ['mousedown', 'touchstart']) { for (let event of ['mousedown', 'touchstart']) {
// Activate side-by-side mode // Activate side-by-side mode
fakeHTMLIntegration.fitSideBySide.returns(true); fakeIntegration.fitSideBySide.returns(true);
guest.fitSideBySide({ expanded: true, width: 100 }); guest.fitSideBySide({ expanded: true, width: 100 });
rootElement.dispatchEvent(new Event(event)); rootElement.dispatchEvent(new Event(event));
...@@ -716,7 +689,7 @@ describe('Guest', () => { ...@@ -716,7 +689,7 @@ describe('Guest', () => {
guest.scrollToAnchor(anchor); guest.scrollToAnchor(anchor);
assert.calledWith(fakeHTMLIntegration.scrollToAnchor, anchor); assert.calledWith(fakeIntegration.scrollToAnchor, anchor);
}); });
}); });
...@@ -728,16 +701,14 @@ describe('Guest', () => { ...@@ -728,16 +701,14 @@ describe('Guest', () => {
}); });
it('preserves the components of the URI other than the fragment', () => { it('preserves the components of the URI other than the fragment', () => {
fakeHTMLIntegration.uri.resolves('http://foobar.com/things?id=42'); fakeIntegration.uri.resolves('http://foobar.com/things?id=42');
return guest return guest
.getDocumentInfo() .getDocumentInfo()
.then(({ uri }) => assert.equal(uri, 'http://foobar.com/things?id=42')); .then(({ uri }) => assert.equal(uri, 'http://foobar.com/things?id=42'));
}); });
it('removes the fragment identifier from URIs', () => { it('removes the fragment identifier from URIs', () => {
fakeHTMLIntegration.uri.resolves( fakeIntegration.uri.resolves('http://foobar.com/things?id=42#ignoreme');
'http://foobar.com/things?id=42#ignoreme'
);
return guest return guest
.getDocumentInfo() .getDocumentInfo()
.then(({ uri }) => assert.equal(uri, 'http://foobar.com/things?id=42')); .then(({ uri }) => assert.equal(uri, 'http://foobar.com/things?id=42'));
...@@ -745,13 +716,13 @@ describe('Guest', () => { ...@@ -745,13 +716,13 @@ describe('Guest', () => {
it('rejects if getting the URL fails', async () => { it('rejects if getting the URL fails', async () => {
const guest = createGuest(); const guest = createGuest();
fakeHTMLIntegration.uri.rejects(new Error('Failed to get URI')); fakeIntegration.uri.rejects(new Error('Failed to get URI'));
await assert.rejects(guest.getDocumentInfo(), 'Failed to get URI'); await assert.rejects(guest.getDocumentInfo(), 'Failed to get URI');
}); });
it('rejects if getting the document metadata fails', async () => { it('rejects if getting the document metadata fails', async () => {
const guest = createGuest(); const guest = createGuest();
fakeHTMLIntegration.getMetadata.rejects(new Error('Failed to get URI')); fakeIntegration.getMetadata.rejects(new Error('Failed to get URI'));
await assert.rejects(guest.getDocumentInfo(), 'Failed to get URI'); await assert.rejects(guest.getDocumentInfo(), 'Failed to get URI');
}); });
}); });
...@@ -762,10 +733,10 @@ describe('Guest', () => { ...@@ -762,10 +733,10 @@ describe('Guest', () => {
const annotation = await guest.createAnnotation(); const annotation = await guest.createAnnotation();
assert.equal(annotation.uri, await fakeHTMLIntegration.uri()); assert.equal(annotation.uri, await fakeIntegration.uri());
assert.deepEqual( assert.deepEqual(
annotation.document, annotation.document,
await fakeHTMLIntegration.getMetadata() await fakeIntegration.getMetadata()
); );
}); });
...@@ -776,15 +747,15 @@ describe('Guest', () => { ...@@ -776,15 +747,15 @@ describe('Guest', () => {
const selectorA = { type: 'TextPositionSelector', start: 0, end: 10 }; const selectorA = { type: 'TextPositionSelector', start: 0, end: 10 };
const selectorB = { type: 'TextQuoteSelector', exact: 'foobar' }; const selectorB = { type: 'TextQuoteSelector', exact: 'foobar' };
fakeHTMLIntegration.anchor.resolves({}); fakeIntegration.anchor.resolves({});
fakeHTMLIntegration.describe.returns([selectorA, selectorB]); fakeIntegration.describe.returns([selectorA, selectorB]);
const annotation = await guest.createAnnotation({}); const annotation = await guest.createAnnotation({});
assert.calledWith(fakeHTMLIntegration.describe, guest.element, fakeRange); assert.calledWith(fakeIntegration.describe, guest.element, fakeRange);
assert.deepEqual(annotation.target, [ assert.deepEqual(annotation.target, [
{ {
source: await fakeHTMLIntegration.uri(), source: await fakeIntegration.uri(),
selector: [selectorA, selectorB], selector: [selectorA, selectorB],
}, },
]); ]);
...@@ -880,7 +851,7 @@ describe('Guest', () => { ...@@ -880,7 +851,7 @@ describe('Guest', () => {
const annotation = { const annotation = {
target: [{ selector: [{ type: 'TextQuoteSelector', exact: 'hello' }] }], target: [{ selector: [{ type: 'TextQuoteSelector', exact: 'hello' }] }],
}; };
fakeHTMLIntegration.anchor.returns(Promise.resolve(range)); fakeIntegration.anchor.returns(Promise.resolve(range));
return guest return guest
.anchor(annotation) .anchor(annotation)
...@@ -895,7 +866,7 @@ describe('Guest', () => { ...@@ -895,7 +866,7 @@ describe('Guest', () => {
{ selector: [{ type: 'TextQuoteSelector', exact: 'hello' }] }, { selector: [{ type: 'TextQuoteSelector', exact: 'hello' }] },
], ],
}; };
fakeHTMLIntegration.anchor fakeIntegration.anchor
.onFirstCall() .onFirstCall()
.returns(Promise.reject(new Error('Failed to anchor'))) .returns(Promise.reject(new Error('Failed to anchor')))
.onSecondCall() .onSecondCall()
...@@ -913,7 +884,7 @@ describe('Guest', () => { ...@@ -913,7 +884,7 @@ describe('Guest', () => {
{ selector: [{ type: 'TextQuoteSelector', exact: 'notinhere' }] }, { selector: [{ type: 'TextQuoteSelector', exact: 'notinhere' }] },
], ],
}; };
fakeHTMLIntegration.anchor.returns( fakeIntegration.anchor.returns(
Promise.reject(new Error('Failed to anchor')) Promise.reject(new Error('Failed to anchor'))
); );
...@@ -930,7 +901,7 @@ describe('Guest', () => { ...@@ -930,7 +901,7 @@ describe('Guest', () => {
{ selector: [{ type: 'TextQuoteSelector', exact: 'neitherami' }] }, { selector: [{ type: 'TextQuoteSelector', exact: 'neitherami' }] },
], ],
}; };
fakeHTMLIntegration.anchor.returns( fakeIntegration.anchor.returns(
Promise.reject(new Error('Failed to anchor')) Promise.reject(new Error('Failed to anchor'))
); );
...@@ -948,7 +919,7 @@ describe('Guest', () => { ...@@ -948,7 +919,7 @@ describe('Guest', () => {
}; };
// This shouldn't be called, but if it is, we successfully anchor so that // This shouldn't be called, but if it is, we successfully anchor so that
// this test is guaranteed to fail. // this test is guaranteed to fail.
fakeHTMLIntegration.anchor.returns(Promise.resolve(range)); fakeIntegration.anchor.returns(Promise.resolve(range));
return guest return guest
.anchor(annotation) .anchor(annotation)
...@@ -965,7 +936,7 @@ describe('Guest', () => { ...@@ -965,7 +936,7 @@ describe('Guest', () => {
return guest return guest
.anchor(annotation) .anchor(annotation)
.then(() => assert.notCalled(fakeHTMLIntegration.anchor)); .then(() => assert.notCalled(fakeIntegration.anchor));
}); });
it('syncs annotations to the sidebar', () => { it('syncs annotations to the sidebar', () => {
...@@ -990,7 +961,7 @@ describe('Guest', () => { ...@@ -990,7 +961,7 @@ describe('Guest', () => {
it('returns a promise of the anchors for the annotation', () => { it('returns a promise of the anchors for the annotation', () => {
const guest = createGuest(); const guest = createGuest();
const highlights = [document.createElement('span')]; const highlights = [document.createElement('span')];
fakeHTMLIntegration.anchor.returns(Promise.resolve(range)); fakeIntegration.anchor.returns(Promise.resolve(range));
highlighter.highlightRange.returns(highlights); highlighter.highlightRange.returns(highlights);
const target = { const target = {
selector: [{ type: 'TextQuoteSelector', exact: 'hello' }], selector: [{ type: 'TextQuoteSelector', exact: 'hello' }],
...@@ -1003,7 +974,7 @@ describe('Guest', () => { ...@@ -1003,7 +974,7 @@ describe('Guest', () => {
it('adds the anchor to the "anchors" instance property"', () => { it('adds the anchor to the "anchors" instance property"', () => {
const guest = createGuest(); const guest = createGuest();
const highlights = [document.createElement('span')]; const highlights = [document.createElement('span')];
fakeHTMLIntegration.anchor.returns(Promise.resolve(range)); fakeIntegration.anchor.returns(Promise.resolve(range));
highlighter.highlightRange.returns(highlights); highlighter.highlightRange.returns(highlights);
const target = { const target = {
selector: [{ type: 'TextQuoteSelector', exact: 'hello' }], selector: [{ type: 'TextQuoteSelector', exact: 'hello' }],
...@@ -1036,7 +1007,7 @@ describe('Guest', () => { ...@@ -1036,7 +1007,7 @@ describe('Guest', () => {
it('focuses the new highlights if the annotation is already focused', async () => { it('focuses the new highlights if the annotation is already focused', async () => {
const guest = createGuest(); const guest = createGuest();
const highlights = [document.createElement('span')]; const highlights = [document.createElement('span')];
fakeHTMLIntegration.anchor.resolves(range); fakeIntegration.anchor.resolves(range);
highlighter.highlightRange.returns(highlights); highlighter.highlightRange.returns(highlights);
const target = { const target = {
selector: [{ type: 'TextQuoteSelector', exact: 'hello' }], selector: [{ type: 'TextQuoteSelector', exact: 'hello' }],
...@@ -1127,11 +1098,10 @@ describe('Guest', () => { ...@@ -1127,11 +1098,10 @@ describe('Guest', () => {
assert.calledOnce(FakeAdder.instance.destroy); assert.calledOnce(FakeAdder.instance.destroy);
}); });
it('cleans up PDF integration', () => { it('cleans up integration', () => {
fakeCreateIntegration.returns(fakePDFIntegration);
const guest = createGuest(); const guest = createGuest();
guest.destroy(); guest.destroy();
assert.calledOnce(fakePDFIntegration.destroy); assert.calledOnce(fakeIntegration.destroy);
}); });
it('removes all highlights', () => { it('removes all highlights', () => {
...@@ -1142,58 +1112,37 @@ describe('Guest', () => { ...@@ -1142,58 +1112,37 @@ describe('Guest', () => {
}); });
describe('#contentContainer', () => { describe('#contentContainer', () => {
it('returns root HTML element in HTML document', () => { it('returns document content container', () => {
const guest = createGuest();
assert.equal(
guest.contentContainer(),
fakeHTMLIntegration.contentContainer()
);
});
it('returns PDF viewer content container in PDF documents', () => {
fakeCreateIntegration.returns(fakePDFIntegration);
const guest = createGuest(); const guest = createGuest();
assert.equal( assert.equal(
guest.contentContainer(), guest.contentContainer(),
fakePDFIntegration.contentContainer() fakeIntegration.contentContainer()
); );
}); });
}); });
describe('#fitSideBySide', () => { describe('#fitSideBySide', () => {
['html', 'pdf'].forEach(documentType => {
context(`in a ${documentType} document`, () => {
let integration;
beforeEach(() => {
integration =
documentType === 'html' ? fakeHTMLIntegration : fakePDFIntegration;
fakeCreateIntegration.returns(integration);
});
it('attempts to fit content alongside sidebar', () => { it('attempts to fit content alongside sidebar', () => {
const guest = createGuest({ documentType }); const guest = createGuest();
integration.fitSideBySide.returns(false); fakeIntegration.fitSideBySide.returns(false);
const layout = { expanded: true, width: 100 }; const layout = { expanded: true, width: 100 };
guest.fitSideBySide(layout); guest.fitSideBySide(layout);
assert.calledWith(integration.fitSideBySide, layout); assert.calledWith(fakeIntegration.fitSideBySide, layout);
}); });
it('enables closing sidebar on document click if side-by-side is not activated', () => { it('enables closing sidebar on document click if side-by-side is not activated', () => {
const guest = createGuest({ documentType }); const guest = createGuest();
integration.fitSideBySide.returns(false); fakeIntegration.fitSideBySide.returns(false);
const layout = { expanded: true, width: 100 }; const layout = { expanded: true, width: 100 };
guest.fitSideBySide(layout); guest.fitSideBySide(layout);
assert.isFalse(guest.sideBySideActive); assert.isFalse(guest.sideBySideActive);
integration.fitSideBySide.returns(true); fakeIntegration.fitSideBySide.returns(true);
guest.fitSideBySide(layout); guest.fitSideBySide(layout);
assert.isTrue(guest.sideBySideActive); assert.isTrue(guest.sideBySideActive);
}); });
}); });
});
});
}); });
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