Skip to content

Commit 647f6d5

Browse files
committed
polish: add tests for more testUtils
adds tests for expectPromise and expectEqualPromisesOrValues
1 parent cfbc023 commit 647f6d5

File tree

5 files changed

+169
-45
lines changed

5 files changed

+169
-45
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { expect } from 'chai';
2+
import { describe, it } from 'mocha';
3+
4+
import { expectEqualPromisesOrValues } from '../expectEqualPromisesOrValues';
5+
import { expectPromise } from '../expectPromise';
6+
7+
describe('expectEqualPromisesOrValues', () => {
8+
it('throws when given unequal values', () => {
9+
expect(() => expectEqualPromisesOrValues([{}, {}, { test: 'test' }])).throw(
10+
"expected { test: 'test' } to deeply equal {}",
11+
);
12+
});
13+
14+
it('does not throw when given equal values', () => {
15+
const testValue = { test: 'test' };
16+
expect(() =>
17+
expectEqualPromisesOrValues([testValue, testValue, testValue]),
18+
).not.to.throw();
19+
});
20+
21+
it('does not throw when given equal promises', async () => {
22+
const testValue = Promise.resolve({ test: 'test' });
23+
24+
await expectPromise(
25+
expectEqualPromisesOrValues([testValue, testValue, testValue]),
26+
).toResolve();
27+
});
28+
29+
it('throws when given unequal promises', async () => {
30+
await expectPromise(
31+
expectEqualPromisesOrValues([
32+
Promise.resolve({}),
33+
Promise.resolve({}),
34+
Promise.resolve({ test: 'test' }),
35+
]),
36+
).toRejectWith("expected { test: 'test' } to deeply equal {}");
37+
});
38+
39+
it('throws when given equal values that are mixtures of values and promises', () => {
40+
const testValue = { test: 'test' };
41+
expect(() =>
42+
expectEqualPromisesOrValues([testValue, Promise.resolve(testValue)]),
43+
).to.throw('Received an invalid mixture of promises and values.');
44+
});
45+
});
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { expect } from 'chai';
2+
import { describe, it } from 'mocha';
3+
4+
import { expectPromise } from '../expectPromise';
5+
6+
describe('expectPromise', () => {
7+
it('throws if passed a value', () => {
8+
expect(() => expectPromise({})).to.throw(
9+
"Expected a promise, received '{}'",
10+
);
11+
});
12+
13+
it('toResolve returns the resolved value', async () => {
14+
const testValue = {};
15+
const promise = Promise.resolve(testValue);
16+
expect(await expectPromise(promise).toResolve()).to.equal(testValue);
17+
});
18+
19+
it('toRejectWith throws if the promise does not reject', async () => {
20+
try {
21+
await expectPromise(Promise.resolve({})).toRejectWith(
22+
'foo',
23+
); /* c8 ignore start */
24+
} /* c8 ignore stop */ catch (err) {
25+
expect(err.message).to.equal(
26+
"Promise should have rejected with message 'foo', but resolved as '{}'",
27+
);
28+
}
29+
});
30+
31+
it('toRejectWith throws if the promise rejects with the wrong reason', async () => {
32+
try {
33+
await expectPromise(Promise.reject(new Error('foo'))).toRejectWith('bar'); /* c8 ignore start */
34+
} /* c8 ignore stop */ catch (err) {
35+
expect(err.message).to.equal(
36+
"expected Error: foo to have property 'message' of 'bar', but got 'foo'",
37+
);
38+
}
39+
});
40+
41+
it('toRejectWith does not throw if the promise rejects with the right reason', async () => {
42+
try {
43+
await expectPromise(Promise.reject(new Error('foo'))).toRejectWith(
44+
'foo',
45+
); /* c8 ignore start */
46+
} catch (err) {
47+
// Not reached.
48+
expect.fail('promise threw unexpectedly');
49+
} /* c8 ignore stop */
50+
});
51+
});
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { assert } from 'chai';
2+
3+
import { isPromise } from '../jsutils/isPromise';
4+
import type { PromiseOrValue } from '../jsutils/PromiseOrValue';
5+
6+
import { expectJSON } from './expectJSON';
7+
8+
export function expectEqualPromisesOrValues<T>(
9+
items: ReadonlyArray<PromiseOrValue<T>>,
10+
): PromiseOrValue<T> {
11+
const remainingItems = items.slice();
12+
const firstItem = remainingItems.shift();
13+
14+
if (isPromise(firstItem)) {
15+
if (remainingItems.every(isPromise)) {
16+
return Promise.all(items).then(expectMatchingValues);
17+
}
18+
} else if (remainingItems.every((item) => !isPromise(item))) {
19+
return expectMatchingValues(items);
20+
}
21+
22+
assert(false, 'Received an invalid mixture of promises and values.');
23+
}
24+
25+
function expectMatchingValues<T>(values: ReadonlyArray<T>): T {
26+
const remainingValues = values.slice(1);
27+
for (const value of remainingValues) {
28+
expectJSON(value).toDeepEqual(values[0]);
29+
}
30+
return values[0];
31+
}

src/__testUtils__/expectPromise.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { assert, expect } from 'chai';
2+
3+
import { inspect } from '../jsutils/inspect';
4+
import { isPromise } from '../jsutils/isPromise';
5+
6+
export function expectPromise(maybePromise: unknown) {
7+
assert(
8+
isPromise(maybePromise),
9+
`Expected a promise, received '${inspect(maybePromise)}'`,
10+
);
11+
12+
return {
13+
toResolve() {
14+
return maybePromise;
15+
},
16+
async toRejectWith(message: string) {
17+
let caughtError: Error | undefined;
18+
let resolved;
19+
let rejected = false;
20+
try {
21+
resolved = await maybePromise;
22+
} catch (error) {
23+
rejected = true;
24+
caughtError = error;
25+
}
26+
27+
assert(
28+
rejected,
29+
`Promise should have rejected with message '${message}', but resolved as '${inspect(
30+
resolved,
31+
)}'`,
32+
);
33+
34+
expect(caughtError).to.be.an.instanceOf(Error);
35+
expect(caughtError).to.have.property('message', message);
36+
},
37+
};
38+
}

src/execution/__tests__/subscribe-test.ts

Lines changed: 4 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { assert, expect } from 'chai';
22
import { describe, it } from 'mocha';
33

4+
import { expectEqualPromisesOrValues } from '../../__testUtils__/expectEqualPromisesOrValues';
45
import { expectJSON } from '../../__testUtils__/expectJSON';
6+
import { expectPromise } from '../../__testUtils__/expectPromise';
57
import { resolveOnNextTick } from '../../__testUtils__/resolveOnNextTick';
68

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

128-
// TODO: consider adding this method to testUtils (with tests)
129-
function expectPromise(maybePromise: unknown) {
130-
assert(isPromise(maybePromise));
131-
132-
return {
133-
toResolve() {
134-
return maybePromise;
135-
},
136-
async toRejectWith(message: string) {
137-
let caughtError: Error;
138-
139-
try {
140-
/* c8 ignore next 2 */
141-
await maybePromise;
142-
expect.fail('promise should have thrown but did not');
143-
} catch (error) {
144-
caughtError = error;
145-
}
146-
147-
expect(caughtError).to.be.an.instanceOf(Error);
148-
expect(caughtError).to.have.property('message', message);
149-
},
150-
};
151-
}
152-
153-
// TODO: consider adding this method to testUtils (with tests)
154-
function expectEqualPromisesOrValues<T>(
155-
value1: PromiseOrValue<T>,
156-
value2: PromiseOrValue<T>,
157-
): PromiseOrValue<T> {
158-
if (isPromise(value1)) {
159-
assert(isPromise(value2));
160-
return Promise.all([value1, value2]).then((resolved) => {
161-
expectJSON(resolved[1]).toDeepEqual(resolved[0]);
162-
return resolved[0];
163-
});
164-
}
165-
166-
assert(!isPromise(value2));
167-
expectJSON(value2).toDeepEqual(value1);
168-
return value1;
169-
}
170-
171130
const DummyQueryType = new GraphQLObjectType({
172131
name: 'Query',
173132
fields: {
@@ -189,10 +148,10 @@ function subscribeWithBadFn(
189148
});
190149
const document = parse('subscription { foo }');
191150

192-
return expectEqualPromisesOrValues(
151+
return expectEqualPromisesOrValues([
193152
subscribe({ schema, document }),
194153
createSourceEventStream({ schema, document }),
195-
);
154+
]);
196155
}
197156

198157
/* eslint-disable @typescript-eslint/require-await */

0 commit comments

Comments
 (0)