Skip to content

Commit

Permalink
polish: add tests for more testUtils
Browse files Browse the repository at this point in the history
adds tests for expectPromise and expectEqualPromisesOrValues
  • Loading branch information
yaacovCR committed Jun 21, 2022
1 parent cfbc023 commit 647f6d5
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 45 deletions.
45 changes: 45 additions & 0 deletions src/__testUtils__/__tests__/expectEqualPromisesOrValues-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { expect } from 'chai';
import { describe, it } from 'mocha';

import { expectEqualPromisesOrValues } from '../expectEqualPromisesOrValues';
import { expectPromise } from '../expectPromise';

describe('expectEqualPromisesOrValues', () => {
it('throws when given unequal values', () => {
expect(() => expectEqualPromisesOrValues([{}, {}, { test: 'test' }])).throw(
"expected { test: 'test' } to deeply equal {}",
);
});

it('does not throw when given equal values', () => {
const testValue = { test: 'test' };
expect(() =>
expectEqualPromisesOrValues([testValue, testValue, testValue]),
).not.to.throw();
});

it('does not throw when given equal promises', async () => {
const testValue = Promise.resolve({ test: 'test' });

await expectPromise(
expectEqualPromisesOrValues([testValue, testValue, testValue]),
).toResolve();
});

it('throws when given unequal promises', async () => {
await expectPromise(
expectEqualPromisesOrValues([
Promise.resolve({}),
Promise.resolve({}),
Promise.resolve({ test: 'test' }),
]),
).toRejectWith("expected { test: 'test' } to deeply equal {}");
});

it('throws when given equal values that are mixtures of values and promises', () => {
const testValue = { test: 'test' };
expect(() =>
expectEqualPromisesOrValues([testValue, Promise.resolve(testValue)]),
).to.throw('Received an invalid mixture of promises and values.');
});
});
51 changes: 51 additions & 0 deletions src/__testUtils__/__tests__/expectPromise-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { expect } from 'chai';
import { describe, it } from 'mocha';

import { expectPromise } from '../expectPromise';

describe('expectPromise', () => {
it('throws if passed a value', () => {
expect(() => expectPromise({})).to.throw(
"Expected a promise, received '{}'",
);
});

it('toResolve returns the resolved value', async () => {
const testValue = {};
const promise = Promise.resolve(testValue);
expect(await expectPromise(promise).toResolve()).to.equal(testValue);
});

it('toRejectWith throws if the promise does not reject', async () => {
try {
await expectPromise(Promise.resolve({})).toRejectWith(
'foo',
); /* c8 ignore start */
} /* c8 ignore stop */ catch (err) {
expect(err.message).to.equal(
"Promise should have rejected with message 'foo', but resolved as '{}'",
);
}
});

it('toRejectWith throws if the promise rejects with the wrong reason', async () => {
try {
await expectPromise(Promise.reject(new Error('foo'))).toRejectWith('bar'); /* c8 ignore start */
} /* c8 ignore stop */ catch (err) {
expect(err.message).to.equal(
"expected Error: foo to have property 'message' of 'bar', but got 'foo'",
);
}
});

it('toRejectWith does not throw if the promise rejects with the right reason', async () => {
try {
await expectPromise(Promise.reject(new Error('foo'))).toRejectWith(
'foo',
); /* c8 ignore start */
} catch (err) {
// Not reached.
expect.fail('promise threw unexpectedly');
} /* c8 ignore stop */
});
});
31 changes: 31 additions & 0 deletions src/__testUtils__/expectEqualPromisesOrValues.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { assert } from 'chai';

import { isPromise } from '../jsutils/isPromise';
import type { PromiseOrValue } from '../jsutils/PromiseOrValue';

import { expectJSON } from './expectJSON';

export function expectEqualPromisesOrValues<T>(
items: ReadonlyArray<PromiseOrValue<T>>,
): PromiseOrValue<T> {
const remainingItems = items.slice();
const firstItem = remainingItems.shift();

if (isPromise(firstItem)) {
if (remainingItems.every(isPromise)) {
return Promise.all(items).then(expectMatchingValues);
}
} else if (remainingItems.every((item) => !isPromise(item))) {
return expectMatchingValues(items);
}

assert(false, 'Received an invalid mixture of promises and values.');
}

function expectMatchingValues<T>(values: ReadonlyArray<T>): T {
const remainingValues = values.slice(1);
for (const value of remainingValues) {
expectJSON(value).toDeepEqual(values[0]);
}
return values[0];
}
38 changes: 38 additions & 0 deletions src/__testUtils__/expectPromise.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { assert, expect } from 'chai';

import { inspect } from '../jsutils/inspect';
import { isPromise } from '../jsutils/isPromise';

export function expectPromise(maybePromise: unknown) {
assert(
isPromise(maybePromise),
`Expected a promise, received '${inspect(maybePromise)}'`,
);

return {
toResolve() {
return maybePromise;
},
async toRejectWith(message: string) {
let caughtError: Error | undefined;
let resolved;
let rejected = false;
try {
resolved = await maybePromise;
} catch (error) {
rejected = true;
caughtError = error;
}

assert(
rejected,
`Promise should have rejected with message '${message}', but resolved as '${inspect(
resolved,
)}'`,
);

expect(caughtError).to.be.an.instanceOf(Error);
expect(caughtError).to.have.property('message', message);
},
};
}
49 changes: 4 additions & 45 deletions src/execution/__tests__/subscribe-test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { assert, expect } from 'chai';
import { describe, it } from 'mocha';

import { expectEqualPromisesOrValues } from '../../__testUtils__/expectEqualPromisesOrValues';
import { expectJSON } from '../../__testUtils__/expectJSON';
import { expectPromise } from '../../__testUtils__/expectPromise';
import { resolveOnNextTick } from '../../__testUtils__/resolveOnNextTick';

import { isAsyncIterable } from '../../jsutils/isAsyncIterable';
Expand Down Expand Up @@ -125,49 +127,6 @@ function createSubscription(pubsub: SimplePubSub<Email>) {
return subscribe({ schema: emailSchema, document, rootValue: data });
}

// TODO: consider adding this method to testUtils (with tests)
function expectPromise(maybePromise: unknown) {
assert(isPromise(maybePromise));

return {
toResolve() {
return maybePromise;
},
async toRejectWith(message: string) {
let caughtError: Error;

try {
/* c8 ignore next 2 */
await maybePromise;
expect.fail('promise should have thrown but did not');
} catch (error) {
caughtError = error;
}

expect(caughtError).to.be.an.instanceOf(Error);
expect(caughtError).to.have.property('message', message);
},
};
}

// TODO: consider adding this method to testUtils (with tests)
function expectEqualPromisesOrValues<T>(
value1: PromiseOrValue<T>,
value2: PromiseOrValue<T>,
): PromiseOrValue<T> {
if (isPromise(value1)) {
assert(isPromise(value2));
return Promise.all([value1, value2]).then((resolved) => {
expectJSON(resolved[1]).toDeepEqual(resolved[0]);
return resolved[0];
});
}

assert(!isPromise(value2));
expectJSON(value2).toDeepEqual(value1);
return value1;
}

const DummyQueryType = new GraphQLObjectType({
name: 'Query',
fields: {
Expand All @@ -189,10 +148,10 @@ function subscribeWithBadFn(
});
const document = parse('subscription { foo }');

return expectEqualPromisesOrValues(
return expectEqualPromisesOrValues([
subscribe({ schema, document }),
createSourceEventStream({ schema, document }),
);
]);
}

/* eslint-disable @typescript-eslint/require-await */
Expand Down

0 comments on commit 647f6d5

Please sign in to comment.