Commit ec3d81f3 authored by Kyle Keating's avatar Kyle Keating

Add assert-methods.js module

- This is used to patch in helper methods into the global assert object such as `rejects()` for testing.
- The new rejects method gives tests the ability to easily test error results in async methods that return a promise.
- Replace all async try/catch tests with assert.rejects
Signed-off-by: 's avatarKyle Keating <kkeating@hypothes.is>
parent b802467d
......@@ -244,12 +244,7 @@ describe('annotationsService', () => {
fakeApi.annotation.delete.rejects(new Error('Annotation does not exist'));
const annot = fixtures.defaultAnnotation();
try {
await svc.delete(annot);
} catch (e) {
/* Ignored */
}
await assert.rejects(svc.delete(annot), 'Annotation does not exist');
assert.notCalled(fakeStore.removeAnnotations);
});
});
......@@ -271,12 +266,7 @@ describe('annotationsService', () => {
fakeApi.annotation.flag.rejects(new Error('Annotation does not exist'));
const annot = fixtures.defaultAnnotation();
try {
await svc.flag(annot);
} catch (e) {
/* Ignored */
}
await assert.rejects(svc.flag(annot), 'Annotation does not exist');
assert.notCalled(fakeStore.updateFlagStatus);
});
});
......
// Expose the sinon assertions.
sinon.assert.expose(assert, { prefix: null });
// Patch extra assert helper methods
import patch from '../../test-util/assert-methods';
patch(assert);
import 'angular';
import 'angular-mocks';
......
import { assertPromiseIsRejected } from '../../../shared/test/promise-util';
import { fetchConfig, $imports } from '../fetch-config';
describe('sidebar.util.fetch-config', () => {
......@@ -108,18 +107,18 @@ describe('sidebar.util.fetch-config', () => {
});
});
it('rejects if sidebar is top frame', () => {
it('rejects if sidebar is top frame', async () => {
fakeWindow.parent = fakeWindow;
fakeWindow.top = fakeWindow;
const config = fetchConfig({}, fakeWindow);
return assertPromiseIsRejected(config, 'Client is top frame');
await assert.rejects(
fetchConfig({}, fakeWindow),
'Client is top frame'
);
});
it('rejects if fetching config fails', () => {
it('rejects if fetching config fails', async () => {
fakeJsonRpc.call.returns(Promise.reject(new Error('Nope')));
const config = fetchConfig({}, fakeWindow);
return assertPromiseIsRejected(config, 'Nope');
await assert.rejects(fetchConfig({}, fakeWindow), 'Nope');
});
it('returns config from ancestor frame', async () => {
......@@ -210,15 +209,10 @@ describe('sidebar.util.fetch-config', () => {
ancestorLevel: 10, // The top window is only 2 levels high
},
});
try {
await fetchConfig({}, fakeWindow);
throw new Error('Failed to catch error');
} catch (e) {
assert.equal(
e.message,
'The target parent frame has exceeded the ancestor tree. Try reducing the `requestConfigFromFrame.ancestorLevel` value in the `hypothesisConfig`'
);
}
await assert.rejects(
fetchConfig({}, fakeWindow),
/The target parent frame has exceeded the ancestor tree|Try reducing the/g
);
});
it('creates a merged config when the RPC requests returns the host config', async () => {
......@@ -235,9 +229,7 @@ describe('sidebar.util.fetch-config', () => {
it('rejects if fetching config fails` ', async () => {
fakeJsonRpc.call.rejects(new Error('Nope'));
const appConfig = { foo: 'bar', appType: 'via' };
const result = fetchConfig(appConfig, fakeWindow);
return assertPromiseIsRejected(result, 'Nope');
await assert.rejects(fetchConfig(appConfig, fakeWindow), 'Nope');
});
it('returns the `groups` array with the initial host config request', async () => {
......@@ -278,12 +270,10 @@ describe('sidebar.util.fetch-config', () => {
fakeJsonRpc.call.onFirstCall().resolves({ foo: 'baz' }); // host config
fakeJsonRpc.call.onSecondCall().rejects(); // requestGroups
const result = await fetchConfig(appConfig, fakeWindow);
try {
await result.services[0].groups;
throw new Error('Failed to catch error');
} catch (e) {
assert.equal(e.message, 'Unable to fetch groups');
}
await assert.rejects(
result.services[0].groups,
'Unable to fetch groups'
);
});
});
......@@ -299,15 +289,10 @@ describe('sidebar.util.fetch-config', () => {
// missing ancestorLevel
},
});
try {
await fetchConfig({}, fakeWindow);
throw new Error('Failed to catch error');
} catch (e) {
assert.equal(
e.message,
'Improper `requestConfigFromFrame` object. Both `ancestorLevel` and `origin` need to be specified'
);
}
await assert.rejects(
fetchConfig({}, fakeWindow),
'Improper `requestConfigFromFrame` object. Both `ancestorLevel` and `origin` need to be specified'
);
});
it('missing origin', async () => {
......@@ -317,15 +302,10 @@ describe('sidebar.util.fetch-config', () => {
ancestorLevel: 2,
},
});
try {
await fetchConfig({}, fakeWindow);
throw new Error('Failed to catch error');
} catch (e) {
assert.equal(
e.message,
'Improper `requestConfigFromFrame` object. Both `ancestorLevel` and `origin` need to be specified'
);
}
await assert.rejects(
fetchConfig({}, fakeWindow),
'Improper `requestConfigFromFrame` object. Both `ancestorLevel` and `origin` need to be specified'
);
});
});
});
......
/**
* Add-on for async exception testing.
*
* The `promiseResult` is awaited, and then upon any exception, the resulting
* error message is matched against the `errorMessage` string or regex. This
* method throws an error if `promiseResult` does not throw an error or will
* throw an assertion error if the caught error message differs from the
* `errorMessage` parameter.
*
* e.g. await rejects(someAsyncFunction(), /expected error/g);
*
* @param {Promise} promiseResult - The returned promise a function to test
* @param errorMessage {RegEx|String} - A string or regex that matches the error
* which is expected to be thrown.
*/
const rejects = async (promiseResult, errorMessage) => {
try {
await promiseResult;
const error = new Error();
error.name = 'ErrorNotCaught';
throw error;
} catch (e) {
if (e.name === 'ErrorNotCaught') {
throw new Error(
'Expected to catch the rejected promise but it was not thrown'
);
}
if (errorMessage instanceof RegExp) {
assert.isTrue(errorMessage.test(e.message));
} else {
assert.equal(errorMessage, e.message);
}
}
};
/**
* Patches the assert object with additional custom helper methods
* defined in this module.
*
* @param {Object} assert - global assertion object.
*/
export default function patch(assert) {
assert.rejects = rejects;
}
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