Commit 7e43bad0 authored by Kyle Keating's avatar Kyle Keating

Remove unroll and convert its use cases to use forEach instead

`unroll()` is not necessary to maintain as it didn't offer any value when writing tests over a simple `forEach()` call over a list of test parameter sets for a common testing function.
parent 380f6de3
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
const html = require('../html'); const html = require('../html');
const toResult = require('../../../shared/test/promise-util').toResult; const toResult = require('../../../shared/test/promise-util').toResult;
const unroll = require('../../../shared/test/util').unroll;
const fixture = require('./html-anchoring-fixture.html'); const fixture = require('./html-anchoring-fixture.html');
/** Return all text node children of `container`. */ /** Return all text node children of `container`. */
...@@ -320,7 +319,7 @@ describe('HTML anchoring', function() { ...@@ -320,7 +319,7 @@ describe('HTML anchoring', function() {
container.remove(); container.remove();
}); });
const testCases = rangeSpecs.map(function(data) { const testCases = rangeSpecs.map(data => {
return { return {
range: { range: {
startContainer: data[0], startContainer: data[0],
...@@ -333,9 +332,8 @@ describe('HTML anchoring', function() { ...@@ -333,9 +332,8 @@ describe('HTML anchoring', function() {
}; };
}); });
unroll( testCases.forEach(testCase => {
'describes and anchors "#description"', it(`describes and anchors ${testCase.description}`, () => {
function(testCase) {
// Resolve the range descriptor to a DOM Range, verify that the expected // Resolve the range descriptor to a DOM Range, verify that the expected
// text was selected. // text was selected.
const range = toRange(container, testCase.range); const range = toRange(container, testCase.range);
...@@ -373,9 +371,8 @@ describe('HTML anchoring', function() { ...@@ -373,9 +371,8 @@ describe('HTML anchoring', function() {
}); });
}); });
return Promise.all(anchored); return Promise.all(anchored);
}, });
testCases });
);
describe('When anchoring fails', function() { describe('When anchoring fails', function() {
const validQuoteSelector = { const validQuoteSelector = {
...@@ -436,9 +433,8 @@ describe('HTML anchoring', function() { ...@@ -436,9 +433,8 @@ describe('HTML anchoring', function() {
frame.remove(); frame.remove();
}); });
unroll( fixtures.forEach(fixture => {
'generates selectors which match the baseline (#name)', it(`generates selectors which match the baseline ${fixture.name}`, () => {
function(fixture) {
let fixtureHtml = fixture.html; let fixtureHtml = fixture.html;
const annotations = fixture.annotations.rows; const annotations = fixture.annotations.rows;
...@@ -471,9 +467,8 @@ describe('HTML anchoring', function() { ...@@ -471,9 +467,8 @@ describe('HTML anchoring', function() {
}); });
}); });
return Promise.all(annotationsChecked); Promise.all(annotationsChecked);
}, });
fixtures });
);
}); });
}); });
'use strict'; 'use strict';
const adder = require('../adder'); const adder = require('../adder');
const unroll = require('../../shared/test/util').unroll;
function rect(left, top, width, height) { function rect(left, top, width, height) {
return { left: left, top: top, width: width, height: height }; return { left: left, top: top, width: width, height: height };
...@@ -57,9 +56,15 @@ describe('annotator.adder', function() { ...@@ -57,9 +56,15 @@ describe('annotator.adder', function() {
} }
context('when Shadow DOM is supported', function() { context('when Shadow DOM is supported', function() {
unroll( [
'creates the adder DOM in a shadow root (using #attachFn)', {
function(testCase) { attachFn: 'createShadowRoot', // Shadow DOM v0 API
},
{
attachFn: 'attachShadow', // Shadow DOM v1 API
},
].forEach(testCase => {
it(`creates the adder DOM in a shadow root (using ${testCase.attachFn})`, () => {
const adderEl = document.createElement('div'); const adderEl = document.createElement('div');
let shadowEl; let shadowEl;
...@@ -83,16 +88,8 @@ describe('annotator.adder', function() { ...@@ -83,16 +88,8 @@ describe('annotator.adder', function() {
); );
adderEl.remove(); adderEl.remove();
}, });
[ });
{
attachFn: 'createShadowRoot', // Shadow DOM v0 API
},
{
attachFn: 'attachShadow', // Shadow DOM v1 API
},
]
);
}); });
describe('button handling', function() { describe('button handling', function() {
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
'use strict'; 'use strict';
const unroll = require('../../../shared/test/util').unroll;
const Guest = require('../../guest'); const Guest = require('../../guest');
function quoteSelector(quote) { function quoteSelector(quote) {
...@@ -71,9 +70,25 @@ describe('anchoring', function() { ...@@ -71,9 +70,25 @@ describe('anchoring', function() {
console.warn.restore(); console.warn.restore();
}); });
unroll( [
'should highlight #tag when annotations are loaded', {
function(testCase) { tag: 'a simple quote',
quotes: ["This has not been a scientist's war"],
},
{
// Known failure with nested annotations that are anchored via quotes
// or positions. See https://github.com/hypothesis/h/pull/3313 and
// https://github.com/hypothesis/h/issues/3278
tag: 'nested quotes',
quotes: [
"This has not been a scientist's war;" +
' it has been a war in which all have had a part',
"scientist's war",
],
expectFail: true,
},
].forEach(testCase => {
it(`should highlight ${testCase.tag} when annotations are loaded`, () => {
const normalize = function(quotes) { const normalize = function(quotes) {
return quotes.map(function(q) { return quotes.map(function(q) {
return simplifyWhitespace(q); return simplifyWhitespace(q);
...@@ -97,24 +112,6 @@ describe('anchoring', function() { ...@@ -97,24 +112,6 @@ describe('anchoring', function() {
normalize(testCase.quotes) normalize(testCase.quotes)
); );
}); });
}, });
[ });
{
tag: 'a simple quote',
quotes: ["This has not been a scientist's war"],
},
{
// Known failure with nested annotations that are anchored via quotes
// or positions. See https://github.com/hypothesis/h/pull/3313 and
// https://github.com/hypothesis/h/issues/3278
tag: 'nested quotes',
quotes: [
"This has not been a scientist's war;" +
' it has been a war in which all have had a part',
"scientist's war",
],
expectFail: true,
},
]
);
}); });
'use strict'; 'use strict';
const unroll = require('../../shared/test/util').unroll;
const observable = require('../util/observable'); const observable = require('../util/observable');
const selections = require('../selections'); const selections = require('../selections');
...@@ -61,15 +59,11 @@ describe('selections', function() { ...@@ -61,15 +59,11 @@ describe('selections', function() {
clock.restore(); clock.restore();
}); });
unroll( it('emits the selected range when mouseup occurs', function() {
'emits the selected range when #event occurs', fakeDocument.dispatchEvent({ type: 'mouseup' });
function(testCase) { clock.tick(20);
fakeDocument.dispatchEvent({ type: testCase.event });
clock.tick(testCase.delay);
assert.calledWith(onSelectionChanged, range); assert.calledWith(onSelectionChanged, range);
}, });
[{ event: 'mouseup', delay: 20 }]
);
it('emits an event if there is a selection at the initial subscription', function() { it('emits an event if there is a selection at the initial subscription', function() {
const onInitialSelection = sinon.stub(); const onInitialSelection = sinon.stub();
......
'use strict';
/**
* Helper for writing parameterized tests.
*
* This is a wrapper around the `it()` function for creating a Mocha test case
* which takes an array of fixture objects and calls it() once for each fixture,
* passing in the fixture object as an argument to the test function.
*
* Usage:
* unroll('should return #output with #input', function (fixture) {
* assert.equal(functionUnderTest(fixture.input), fixture.output);
* },[
* {input: 'foo', output: 'bar'}
* ]);
*
* Based on https://github.com/lawrencec/Unroll with the following changes:
*
* 1. Support for test functions that return promises
* 2. Mocha's `it()` is the only supported test function
* 3. Fixtures are objects rather than arrays
*
* @param {string} description - Description with optional '#key' placeholders
* which are replaced by the values of the corresponding key from each
* fixture object.
* @param {Function} testFn - Test function which can accept either `fixture`
* or `done, fixture` as arguments, where `done` is the callback for
* reporting completion of an async test and `fixture` is an object
* from the `fixtures` array.
* @param {Array<T>} fixtures - Array of fixture objects.
*/
function unroll(description, testFn, fixtures) {
fixtures.forEach(function(fixture) {
const caseDescription = Object.keys(fixture).reduce(function(desc, key) {
return desc.replace('#' + key, String(fixture[key]));
}, description);
it(caseDescription, function(done) {
if (testFn.length === 1) {
// Test case does not accept a 'done' callback argument, so we either
// call done() immediately if it returns a non-Promiselike object
// or when the Promise resolves otherwise
const result = testFn(fixture);
if (typeof result === 'object' && result.then) {
result.then(function() {
done();
}, done);
} else {
done();
}
} else {
// Test case accepts a 'done' callback argument and takes responsibility
// for calling it when the test completes.
testFn(done, fixture);
}
});
});
}
module.exports = {
unroll: unroll,
};
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
const { createElement } = require('preact'); const { createElement } = require('preact');
const { shallow } = require('enzyme'); const { shallow } = require('enzyme');
const unroll = require('../../../shared/test/util').unroll;
const fixtures = require('../../test/annotation-fixtures'); const fixtures = require('../../test/annotation-fixtures');
const AnnotationHeader = require('../annotation-header'); const AnnotationHeader = require('../annotation-header');
...@@ -36,15 +35,6 @@ describe('AnnotationHeader', () => { ...@@ -36,15 +35,6 @@ describe('AnnotationHeader', () => {
assert.equal(replyCollapseLink.prop('onClick'), fakeCallback); assert.equal(replyCollapseLink.prop('onClick'), fakeCallback);
}); });
unroll(
'it should render the annotation reply count',
testCase => {
const wrapper = createAnnotationHeader({
replyCount: testCase.replyCount,
});
const replyCollapseLink = wrapper.find('.annotation-link');
assert.equal(replyCollapseLink.text(), testCase.expected);
},
[ [
{ {
replyCount: 0, replyCount: 0,
...@@ -58,8 +48,15 @@ describe('AnnotationHeader', () => { ...@@ -58,8 +48,15 @@ describe('AnnotationHeader', () => {
replyCount: 2, replyCount: 2,
expected: '2 replies', expected: '2 replies',
}, },
] ].forEach(testCase => {
); it(`it should render the annotation reply count (${testCase.replyCount})`, () => {
const wrapper = createAnnotationHeader({
replyCount: testCase.replyCount,
});
const replyCollapseLink = wrapper.find('.annotation-link');
assert.equal(replyCollapseLink.text(), testCase.expected);
});
});
}); });
describe('timestamps', () => { describe('timestamps', () => {
......
...@@ -4,13 +4,11 @@ const angular = require('angular'); ...@@ -4,13 +4,11 @@ const angular = require('angular');
const events = require('../../events'); const events = require('../../events');
const fixtures = require('../../test/annotation-fixtures'); const fixtures = require('../../test/annotation-fixtures');
const testUtil = require('../../../shared/test/util');
const util = require('../../directive/test/util'); const util = require('../../directive/test/util');
const annotationComponent = require('../annotation'); const annotationComponent = require('../annotation');
const inject = angular.mock.inject; const inject = angular.mock.inject;
const unroll = testUtil.unroll;
const draftFixtures = { const draftFixtures = {
shared: { text: 'draft', tags: [], isPrivate: false }, shared: { text: 'draft', tags: [], isPrivate: false },
...@@ -917,18 +915,6 @@ describe('annotation', function() { ...@@ -917,18 +915,6 @@ describe('annotation', function() {
}); });
describe('#shouldShowLicense', function() { describe('#shouldShowLicense', function() {
unroll(
'returns #expected if #case_',
function(testCase) {
const ann = fixtures.publicAnnotation();
ann.group = testCase.group.id;
fakeStore.getDraft.returns(testCase.draft);
fakeGroups.get.returns(testCase.group);
const controller = createDirective(ann).controller;
assert.equal(controller.shouldShowLicense(), testCase.expected);
},
[ [
{ {
case_: 'the annotation is not being edited', case_: 'the annotation is not being edited',
...@@ -960,8 +946,18 @@ describe('annotation', function() { ...@@ -960,8 +946,18 @@ describe('annotation', function() {
group: groupFixtures.restricted, group: groupFixtures.restricted,
expected: true, expected: true,
}, },
] ].forEach(testCase => {
); it(`returns ${testCase.expected} if ${testCase.case_}`, () => {
const ann = fixtures.publicAnnotation();
ann.group = testCase.group.id;
fakeStore.getDraft.returns(testCase.draft);
fakeGroups.get.returns(testCase.group);
const controller = createDirective(ann).controller;
assert.equal(controller.shouldShowLicense(), testCase.expected);
});
});
}); });
describe('#authorize', function() { describe('#authorize', function() {
...@@ -1272,17 +1268,6 @@ describe('annotation', function() { ...@@ -1272,17 +1268,6 @@ describe('annotation', function() {
assert.equal(el[0].querySelector('blockquote').textContent, '<<-&->>'); assert.equal(el[0].querySelector('blockquote').textContent, '<<-&->>');
}); });
unroll(
'renders hidden annotations with a custom text class (#context)',
function(testCase) {
const el = createDirective(testCase.ann).element;
assert.match(
el.find('markdown-view').controller('markdownView'),
sinon.match({
textClass: testCase.textClass,
})
);
},
[ [
{ {
context: 'for moderators', context: 'for moderators',
...@@ -1307,8 +1292,17 @@ describe('annotation', function() { ...@@ -1307,8 +1292,17 @@ describe('annotation', function() {
'has-content': false, 'has-content': false,
}, },
}, },
] ].forEach(testCase => {
it(`renders hidden annotations with a custom text class (${testCase.context})`, () => {
const el = createDirective(testCase.ann).element;
assert.match(
el.find('markdown-view').controller('markdownView'),
sinon.match({
textClass: testCase.textClass,
})
); );
});
});
it('flags the annotation when the user clicks the "Flag" button', function() { it('flags the annotation when the user clicks the "Flag" button', function() {
fakeAnnotationMapper.flagAnnotation.returns(Promise.resolve()); fakeAnnotationMapper.flagAnnotation.returns(Promise.resolve());
......
...@@ -5,7 +5,6 @@ const { createElement } = require('preact'); ...@@ -5,7 +5,6 @@ const { createElement } = require('preact');
const ModerationBanner = require('../moderation-banner'); const ModerationBanner = require('../moderation-banner');
const fixtures = require('../../test/annotation-fixtures'); const fixtures = require('../../test/annotation-fixtures');
const unroll = require('../../../shared/test/util').unroll;
const moderatedAnnotation = fixtures.moderatedAnnotation; const moderatedAnnotation = fixtures.moderatedAnnotation;
...@@ -44,26 +43,15 @@ describe('ModerationBanner', () => { ...@@ -44,26 +43,15 @@ describe('ModerationBanner', () => {
ModerationBanner.$imports.$restore(); ModerationBanner.$imports.$restore();
}); });
unroll(
'displays if user is a moderator and annotation is hidden or flagged',
function(testCase) {
const wrapper = createComponent({
annotation: testCase.ann,
});
if (testCase.expectVisible) {
assert.notEqual(wrapper.text().trim(), '');
} else {
assert.isFalse(wrapper.exists());
}
},
[ [
{ {
// Not hidden or flagged and user is not a moderator // Not hidden or flagged and user is not a moderator
test: 'not hidden or flagged and user is not a moderator',
ann: fixtures.defaultAnnotation(), ann: fixtures.defaultAnnotation(),
expectVisible: false, expectVisible: false,
}, },
{ {
// Hidden, but user is not a moderator test: 'hidden, but user is not a moderator',
ann: { ann: {
...fixtures.defaultAnnotation(), ...fixtures.defaultAnnotation(),
hidden: true, hidden: true,
...@@ -71,23 +59,34 @@ describe('ModerationBanner', () => { ...@@ -71,23 +59,34 @@ describe('ModerationBanner', () => {
expectVisible: false, expectVisible: false,
}, },
{ {
// Not hidden or flagged and user is a moderator test: 'not hidden or flagged and user is a moderator',
ann: fixtures.moderatedAnnotation({ flagCount: 0, hidden: false }), ann: fixtures.moderatedAnnotation({ flagCount: 0, hidden: false }),
expectVisible: false, expectVisible: false,
}, },
{ {
// Flagged but not hidden test: 'flagged but not hidden and the user is a moderator',
ann: fixtures.moderatedAnnotation({ flagCount: 1, hidden: false }), ann: fixtures.moderatedAnnotation({ flagCount: 1, hidden: false }),
expectVisible: true, expectVisible: true,
}, },
{ {
// Hidden but not flagged. The client only allows moderators to hide flagged // The client only allows moderators to hide flagged annotations but
// annotations but an unflagged annotation can still be hidden via the API. // an unflagged annotation can still be hidden via the API.
test: 'hidden but not flagged and the user is a moderator',
ann: fixtures.moderatedAnnotation({ flagCount: 0, hidden: true }), ann: fixtures.moderatedAnnotation({ flagCount: 0, hidden: true }),
expectVisible: true, expectVisible: true,
}, },
] ].forEach(testCase => {
); it(`displays if the annotation is ${testCase.test}`, () => {
const wrapper = createComponent({
annotation: testCase.ann,
});
if (testCase.expectVisible) {
assert.notEqual(wrapper.text().trim(), '');
} else {
assert.isFalse(wrapper.exists());
}
});
});
it('displays the number of flags the annotation has received', function() { it('displays the number of flags the annotation has received', function() {
const ann = fixtures.moderatedAnnotation({ flagCount: 10 }); const ann = fixtures.moderatedAnnotation({ flagCount: 10 });
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
const { createElement } = require('preact'); const { createElement } = require('preact');
const { shallow } = require('enzyme'); const { shallow } = require('enzyme');
const unroll = require('../../../shared/test/util').unroll;
const ShareAnnotationsPanel = require('../share-annotations-panel'); const ShareAnnotationsPanel = require('../share-annotations-panel');
const SidebarPanel = require('../sidebar-panel'); const SidebarPanel = require('../sidebar-panel');
...@@ -95,27 +94,6 @@ describe('ShareAnnotationsPanel', () => { ...@@ -95,27 +94,6 @@ describe('ShareAnnotationsPanel', () => {
}); });
}); });
unroll(
'it displays appropriate help text depending on group type',
testCase => {
fakeStore.focusedGroup.returns({
type: testCase.groupType,
name: 'Test Group',
id: 'testid,',
});
const wrapper = createShareAnnotationsPanel();
assert.match(
wrapper.find('.share-annotations-panel__intro').text(),
testCase.introPattern
);
assert.match(
wrapper.find('.share-annotations-panel').text(),
testCase.visibilityPattern
);
},
[ [
{ {
groupType: 'private', groupType: 'private',
...@@ -132,9 +110,28 @@ describe('ShareAnnotationsPanel', () => { ...@@ -132,9 +110,28 @@ describe('ShareAnnotationsPanel', () => {
introPattern: /Use this link to share these annotations with anyone/, introPattern: /Use this link to share these annotations with anyone/,
visibilityPattern: /Anyone using this link may view the annotations in the group/, visibilityPattern: /Anyone using this link may view the annotations in the group/,
}, },
] ].forEach(testCase => {
it('it displays appropriate help text depending on group type', () => {
fakeStore.focusedGroup.returns({
type: testCase.groupType,
name: 'Test Group',
id: 'testid,',
});
const wrapper = createShareAnnotationsPanel();
assert.match(
wrapper.find('.share-annotations-panel__intro').text(),
testCase.introPattern
); );
assert.match(
wrapper.find('.share-annotations-panel').text(),
testCase.visibilityPattern
);
});
});
describe('web share link', () => { describe('web share link', () => {
it('displays web share link in readonly form input', () => { it('displays web share link in readonly form input', () => {
const wrapper = createShareAnnotationsPanel(); const wrapper = createShareAnnotationsPanel();
......
'use strict'; 'use strict';
const angular = require('angular'); const angular = require('angular');
const unroll = require('../../../shared/test/util').unroll;
describe('BrandingDirective', function() { describe('BrandingDirective', function() {
let $compile; let $compile;
...@@ -62,9 +61,8 @@ describe('BrandingDirective', function() { ...@@ -62,9 +61,8 @@ describe('BrandingDirective', function() {
assert.equal(el[0].style.backgroundColor, ''); assert.equal(el[0].style.backgroundColor, '');
}); });
unroll( require('./h-branding-fixtures').forEach(testCase => {
'applies branding to elements', it('applies branding to elements', () => {
function(testCase) {
applyBrandingSettings(testCase.settings); applyBrandingSettings(testCase.settings);
const el = makeElementWithAttrs(testCase.attrs); const el = makeElementWithAttrs(testCase.attrs);
...@@ -84,7 +82,6 @@ describe('BrandingDirective', function() { ...@@ -84,7 +82,6 @@ describe('BrandingDirective', function() {
testCase.expectedPropValue testCase.expectedPropValue
); );
} }
}, });
require('./h-branding-fixtures') });
);
}); });
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
const angular = require('angular'); const angular = require('angular');
const unroll = require('../../../shared/test/util').unroll;
const util = require('./util'); const util = require('./util');
function testComponent() { function testComponent() {
...@@ -35,12 +34,6 @@ describe('hOnTouch', function() { ...@@ -35,12 +34,6 @@ describe('hOnTouch', function() {
testEl = util.createDirective(document, 'test', {}); testEl = util.createDirective(document, 'test', {});
}); });
unroll(
'calls the handler when activated with a "#event" event',
function(testCase) {
util.sendEvent(testEl[0].querySelector('div'), testCase.event);
assert.equal(testEl.ctrl.tapCount, 1);
},
[ [
{ {
event: 'touchstart', event: 'touchstart',
...@@ -51,6 +44,10 @@ describe('hOnTouch', function() { ...@@ -51,6 +44,10 @@ describe('hOnTouch', function() {
{ {
event: 'click', event: 'click',
}, },
] ].forEach(testCase => {
); it(`calls the handler when activated with a "${testCase.event}" event`, () => {
util.sendEvent(testEl[0].querySelector('div'), testCase.event);
assert.equal(testEl.ctrl.tapCount, 1);
});
});
}); });
...@@ -5,7 +5,6 @@ const immutable = require('seamless-immutable'); ...@@ -5,7 +5,6 @@ const immutable = require('seamless-immutable');
const storeFactory = require('../index'); const storeFactory = require('../index');
const annotationFixtures = require('../../test/annotation-fixtures'); const annotationFixtures = require('../../test/annotation-fixtures');
const metadata = require('../../util/annotation-metadata'); const metadata = require('../../util/annotation-metadata');
const unroll = require('../../../shared/test/util').unroll;
const uiConstants = require('../../ui-constants'); const uiConstants = require('../../ui-constants');
const defaultAnnotation = annotationFixtures.defaultAnnotation; const defaultAnnotation = annotationFixtures.defaultAnnotation;
...@@ -360,14 +359,12 @@ describe('store', function() { ...@@ -360,14 +359,12 @@ describe('store', function() {
}); });
describe('#setShowHighlights()', function() { describe('#setShowHighlights()', function() {
unroll( [{ state: true }, { state: false }].forEach(testCase => {
'sets the visibleHighlights state flag to #state', it(`sets the visibleHighlights state flag to ${testCase.state}`, () => {
function(testCase) {
store.setShowHighlights(testCase.state); store.setShowHighlights(testCase.state);
assert.equal(store.getState().viewer.visibleHighlights, testCase.state); assert.equal(store.getState().viewer.visibleHighlights, testCase.state);
}, });
[{ state: true }, { state: false }] });
);
}); });
describe('#updatingAnchorStatus', function() { describe('#updatingAnchorStatus', function() {
......
...@@ -3,8 +3,6 @@ ...@@ -3,8 +3,6 @@
const angular = require('angular'); const angular = require('angular');
const immutable = require('seamless-immutable'); const immutable = require('seamless-immutable');
const unroll = require('../../../shared/test/util').unroll;
const fixtures = immutable({ const fixtures = immutable({
annotations: [ annotations: [
{ {
...@@ -87,18 +85,6 @@ describe('annotation threading', function() { ...@@ -87,18 +85,6 @@ describe('annotation threading', function() {
assert.equal(rootThread.thread(store.getState()).children[0].id, '2'); assert.equal(rootThread.thread(store.getState()).children[0].id, '2');
}); });
unroll(
'should sort annotations by #mode',
function(testCase) {
store.addAnnotations(fixtures.annotations);
store.setSortKey(testCase.sortKey);
const actualOrder = rootThread
.thread(store.getState())
.children.map(function(thread) {
return thread.annotation.id;
});
assert.deepEqual(actualOrder, testCase.expectedOrder);
},
[ [
{ {
sortKey: 'Oldest', sortKey: 'Oldest',
...@@ -108,6 +94,16 @@ describe('annotation threading', function() { ...@@ -108,6 +94,16 @@ describe('annotation threading', function() {
sortKey: 'Newest', sortKey: 'Newest',
expectedOrder: ['2', '1'], expectedOrder: ['2', '1'],
}, },
] ].forEach(testCase => {
); it(`should sort annotations by ${testCase.mode}`, () => {
store.addAnnotations(fixtures.annotations);
store.setSortKey(testCase.sortKey);
const actualOrder = rootThread
.thread(store.getState())
.children.map(function(thread) {
return thread.annotation.id;
});
assert.deepEqual(actualOrder, testCase.expectedOrder);
});
});
}); });
'use strict'; 'use strict';
const commands = require('../markdown-commands'); const commands = require('../markdown-commands');
const unroll = require('../../shared/test/util').unroll;
/** /**
* Convert a string containing '<sel>' and '</sel>' markers * Convert a string containing '<sel>' and '</sel>' markers
...@@ -84,7 +83,7 @@ describe('markdown commands', function() { ...@@ -84,7 +83,7 @@ describe('markdown commands', function() {
}); });
describe('block formatting', function() { describe('block formatting', function() {
const FIXTURES = [ [
{ {
tag: 'adds formatting to blocks', tag: 'adds formatting to blocks',
input: 'one\n<sel>two\nthree</sel>\nfour', input: 'one\n<sel>two\nthree</sel>\nfour',
...@@ -105,19 +104,15 @@ describe('markdown commands', function() { ...@@ -105,19 +104,15 @@ describe('markdown commands', function() {
input: '<sel></sel>', input: '<sel></sel>',
output: '> <sel></sel>', output: '> <sel></sel>',
}, },
]; ].forEach(fixture => {
it(fixture.tag, () => {
unroll(
'#tag',
function(fixture) {
const output = commands.toggleBlockStyle( const output = commands.toggleBlockStyle(
parseState(fixture.input), parseState(fixture.input),
'> ' '> '
); );
assert.equal(formatState(output), fixture.output); assert.equal(formatState(output), fixture.output);
}, });
FIXTURES });
);
}); });
describe('link formatting', function() { describe('link formatting', function() {
...@@ -125,35 +120,31 @@ describe('markdown commands', function() { ...@@ -125,35 +120,31 @@ describe('markdown commands', function() {
return commands.convertSelectionToLink(parseState(text), linkType); return commands.convertSelectionToLink(parseState(text), linkType);
}; };
unroll( [{ selection: 'two' }, { selection: 'jim:smith' }].forEach(testCase => {
'converts text to links', it('converts text to links', () => {
function(testCase) {
const sel = testCase.selection; const sel = testCase.selection;
const output = linkify('one <sel>' + sel + '</sel> three'); const output = linkify('one <sel>' + sel + '</sel> three');
assert.equal( assert.equal(
formatState(output), formatState(output),
'one [' + sel + '](<sel>http://insert-your-link-here.com</sel>) three' 'one [' + sel + '](<sel>http://insert-your-link-here.com</sel>) three'
); );
}, });
[{ selection: 'two' }, { selection: 'jim:smith' }] });
);
unroll( [
'converts URLs to links', { selection: 'http://foobar.com' },
function(testCase) { { selection: 'https://twitter.com/username' },
{ selection: ' http://example.com/url-with-a-leading-space' },
].forEach(testCase => {
it(`converts URLs to links`, () => {
const sel = testCase.selection; const sel = testCase.selection;
const output = linkify('one <sel>' + sel + '</sel> three'); const output = linkify('one <sel>' + sel + '</sel> three');
assert.equal( assert.equal(
formatState(output), formatState(output),
'one [<sel>Description</sel>](' + sel + ') three' 'one [<sel>Description</sel>](' + sel + ') three'
); );
}, });
[ });
{ selection: 'http://foobar.com' },
{ selection: 'https://twitter.com/username' },
{ selection: ' http://example.com/url-with-a-leading-space' },
]
);
it('converts URLs to image links', function() { it('converts URLs to image links', function() {
const output = linkify( const output = linkify(
......
'use strict'; 'use strict';
const util = require('../../shared/test/util');
const VirtualThreadList = require('../virtual-thread-list'); const VirtualThreadList = require('../virtual-thread-list');
const unroll = util.unroll;
describe('VirtualThreadList', function() { describe('VirtualThreadList', function() {
let lastState; let lastState;
let threadList; let threadList;
...@@ -105,36 +102,6 @@ describe('VirtualThreadList', function() { ...@@ -105,36 +102,6 @@ describe('VirtualThreadList', function() {
}); });
}); });
unroll(
'generates expected state when #when',
function(testCase) {
const thread = generateRootThread(testCase.threads);
fakeScrollRoot.scrollTop = testCase.scrollOffset;
fakeWindow.innerHeight = testCase.windowHeight;
// make sure for everything that is not being presented in the
// visible viewport, we pass it to this function.
threadOptions.invisibleThreadFilter.returns(true);
threadList.setRootThread(thread);
const visibleIDs = threadIDs(lastState.visibleThreads);
const invisibleIDs = threadIDs(lastState.invisibleThreads);
assert.deepEqual(visibleIDs, testCase.expectedVisibleThreads);
assert.equal(
invisibleIDs.length,
testCase.threads - testCase.expectedVisibleThreads.length
);
assert.equal(
lastState.offscreenUpperHeight,
testCase.expectedHeightAbove
);
assert.equal(
lastState.offscreenLowerHeight,
testCase.expectedHeightBelow
);
},
[ [
{ {
when: 'scrollRoot is scrolled to top of list', when: 'scrollRoot is scrolled to top of list',
...@@ -163,8 +130,36 @@ describe('VirtualThreadList', function() { ...@@ -163,8 +130,36 @@ describe('VirtualThreadList', function() {
expectedHeightAbove: 17800, expectedHeightAbove: 17800,
expectedHeightBelow: 0, expectedHeightBelow: 0,
}, },
] ].forEach(testCase => {
it(`generates expected state when ${testCase.when}`, () => {
const thread = generateRootThread(testCase.threads);
fakeScrollRoot.scrollTop = testCase.scrollOffset;
fakeWindow.innerHeight = testCase.windowHeight;
// make sure for everything that is not being presented in the
// visible viewport, we pass it to this function.
threadOptions.invisibleThreadFilter.returns(true);
threadList.setRootThread(thread);
const visibleIDs = threadIDs(lastState.visibleThreads);
const invisibleIDs = threadIDs(lastState.invisibleThreads);
assert.deepEqual(visibleIDs, testCase.expectedVisibleThreads);
assert.equal(
invisibleIDs.length,
testCase.threads - testCase.expectedVisibleThreads.length
); );
assert.equal(
lastState.offscreenUpperHeight,
testCase.expectedHeightAbove
);
assert.equal(
lastState.offscreenLowerHeight,
testCase.expectedHeightBelow
);
});
});
it('recalculates when a window.resize occurs', function() { it('recalculates when a window.resize occurs', function() {
lastState = null; lastState = null;
...@@ -184,9 +179,17 @@ describe('VirtualThreadList', function() { ...@@ -184,9 +179,17 @@ describe('VirtualThreadList', function() {
}); });
describe('#setThreadHeight', function() { describe('#setThreadHeight', function() {
unroll( [
'affects visible threads', {
function(testCase) { threadHeight: 1000,
expectedVisibleThreads: idRange(0, 1),
},
{
threadHeight: 300,
expectedVisibleThreads: idRange(0, 4),
},
].forEach(testCase => {
it('affects visible threads', () => {
const thread = generateRootThread(10); const thread = generateRootThread(10);
fakeWindow.innerHeight = 500; fakeWindow.innerHeight = 500;
fakeScrollRoot.scrollTop = 0; fakeScrollRoot.scrollTop = 0;
...@@ -198,18 +201,8 @@ describe('VirtualThreadList', function() { ...@@ -198,18 +201,8 @@ describe('VirtualThreadList', function() {
threadIDs(lastState.visibleThreads), threadIDs(lastState.visibleThreads),
testCase.expectedVisibleThreads testCase.expectedVisibleThreads
); );
}, });
[ });
{
threadHeight: 1000,
expectedVisibleThreads: idRange(0, 1),
},
{
threadHeight: 300,
expectedVisibleThreads: idRange(0, 4),
},
]
);
}); });
describe('#detach', function() { describe('#detach', function() {
...@@ -228,17 +221,6 @@ describe('VirtualThreadList', function() { ...@@ -228,17 +221,6 @@ describe('VirtualThreadList', function() {
}); });
describe('#yOffsetOf', function() { describe('#yOffsetOf', function() {
unroll(
'returns #offset as the Y offset of the #nth thread',
function(testCase) {
const thread = generateRootThread(10);
threadList.setRootThread(thread);
idRange(0, 10).forEach(function(id) {
threadList.setThreadHeight(id, 100);
});
const id = idRange(testCase.index, testCase.index)[0];
assert.equal(threadList.yOffsetOf(id), testCase.offset);
},
[ [
{ {
nth: 'first', nth: 'first',
...@@ -255,7 +237,16 @@ describe('VirtualThreadList', function() { ...@@ -255,7 +237,16 @@ describe('VirtualThreadList', function() {
index: 9, index: 9,
offset: 900, offset: 900,
}, },
] ].forEach(testCase => {
); it(`returns ${testCase.offset} as the Y offset of the ${testCase.nth} thread`, () => {
const thread = generateRootThread(10);
threadList.setRootThread(thread);
idRange(0, 10).forEach(function(id) {
threadList.setThreadHeight(id, 100);
});
const id = idRange(testCase.index, testCase.index)[0];
assert.equal(threadList.yOffsetOf(id), testCase.offset);
});
});
}); });
}); });
...@@ -3,8 +3,6 @@ ...@@ -3,8 +3,6 @@
const annotationMetadata = require('../annotation-metadata'); const annotationMetadata = require('../annotation-metadata');
const fixtures = require('../../test/annotation-fixtures'); const fixtures = require('../../test/annotation-fixtures');
const unroll = require('../../../shared/test/util').unroll;
const documentMetadata = annotationMetadata.documentMetadata; const documentMetadata = annotationMetadata.documentMetadata;
const domainAndTitle = annotationMetadata.domainAndTitle; const domainAndTitle = annotationMetadata.domainAndTitle;
...@@ -288,14 +286,6 @@ describe('annotation-metadata', function() { ...@@ -288,14 +286,6 @@ describe('annotation-metadata', function() {
assert.isTrue(annotationMetadata.isPublic(fixtures.publicAnnotation())); assert.isTrue(annotationMetadata.isPublic(fixtures.publicAnnotation()));
}); });
unroll(
'returns false if an annotation is not publicly readable',
function(testCase) {
const annotation = Object.assign(fixtures.defaultAnnotation(), {
permissions: testCase,
});
assert.isFalse(annotationMetadata.isPublic(annotation));
},
[ [
{ {
read: ['acct:someemail@localhost'], read: ['acct:someemail@localhost'],
...@@ -303,8 +293,14 @@ describe('annotation-metadata', function() { ...@@ -303,8 +293,14 @@ describe('annotation-metadata', function() {
{ {
read: ['something invalid'], read: ['something invalid'],
}, },
] ].forEach(testCase => {
); it('returns false if an annotation is not publicly readable', () => {
const annotation = Object.assign(fixtures.defaultAnnotation(), {
permissions: testCase,
});
assert.isFalse(annotationMetadata.isPublic(annotation));
});
});
it('returns false if an annotation is missing permissions', function() { it('returns false if an annotation is missing permissions', function() {
assert.isFalse(annotationMetadata.isPublic(fixtures.defaultAnnotation())); assert.isFalse(annotationMetadata.isPublic(fixtures.defaultAnnotation()));
......
...@@ -3,17 +3,9 @@ ...@@ -3,17 +3,9 @@
const fixtures = require('../../test/annotation-fixtures'); const fixtures = require('../../test/annotation-fixtures');
const uiConstants = require('../../ui-constants'); const uiConstants = require('../../ui-constants');
const tabs = require('../tabs'); const tabs = require('../tabs');
const unroll = require('../../../shared/test/util').unroll;
describe('tabs', function() { describe('tabs', function() {
describe('tabForAnnotation', function() { describe('tabForAnnotation', function() {
unroll(
'shows annotation in correct tab',
function(testCase) {
const ann = testCase.ann;
const expectedTab = testCase.expectedTab;
assert.equal(tabs.tabForAnnotation(ann), expectedTab);
},
[ [
{ {
ann: fixtures.defaultAnnotation(), ann: fixtures.defaultAnnotation(),
...@@ -27,27 +19,16 @@ describe('tabs', function() { ...@@ -27,27 +19,16 @@ describe('tabs', function() {
ann: Object.assign(fixtures.defaultAnnotation(), { $orphan: true }), ann: Object.assign(fixtures.defaultAnnotation(), { $orphan: true }),
expectedTab: uiConstants.TAB_ORPHANS, expectedTab: uiConstants.TAB_ORPHANS,
}, },
] ].forEach(testCase => {
); it(`shows annotation in correct tab (${testCase.expectedTab})`, () => {
const ann = testCase.ann;
const expectedTab = testCase.expectedTab;
assert.equal(tabs.tabForAnnotation(ann), expectedTab);
});
});
}); });
describe('shouldShowInTab', function() { describe('shouldShowInTab', function() {
unroll(
'returns true if the annotation should be shown',
function(testCase) {
const ann = fixtures.defaultAnnotation();
ann.$anchorTimeout = testCase.anchorTimeout;
ann.$orphan = testCase.orphan;
assert.equal(
tabs.shouldShowInTab(ann, uiConstants.TAB_ANNOTATIONS),
testCase.expectedTab === uiConstants.TAB_ANNOTATIONS
);
assert.equal(
tabs.shouldShowInTab(ann, uiConstants.TAB_ORPHANS),
testCase.expectedTab === uiConstants.TAB_ORPHANS
);
},
[ [
{ {
// Anchoring in progress. // Anchoring in progress.
...@@ -80,7 +61,21 @@ describe('tabs', function() { ...@@ -80,7 +61,21 @@ describe('tabs', function() {
orphan: true, orphan: true,
expectedTab: uiConstants.TAB_ORPHANS, expectedTab: uiConstants.TAB_ORPHANS,
}, },
] ].forEach(testCase => {
it('returns true if the annotation should be shown', () => {
const ann = fixtures.defaultAnnotation();
ann.$anchorTimeout = testCase.anchorTimeout;
ann.$orphan = testCase.orphan;
assert.equal(
tabs.shouldShowInTab(ann, uiConstants.TAB_ANNOTATIONS),
testCase.expectedTab === uiConstants.TAB_ANNOTATIONS
); );
assert.equal(
tabs.shouldShowInTab(ann, uiConstants.TAB_ORPHANS),
testCase.expectedTab === uiConstants.TAB_ORPHANS
);
});
});
}); });
}); });
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