Skip to content

Commit

Permalink
update Subscription resolvers and tests ; add simple subscribe test u…
Browse files Browse the repository at this point in the history
…sing graphql.subscribe and pubsub
  • Loading branch information
getlarge committed May 12, 2020
1 parent 7c64a45 commit 27e59f5
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 93 deletions.
203 changes: 140 additions & 63 deletions src/engine/subscription/Subscription.spec.ts
Expand Up @@ -8,12 +8,16 @@ import {
SUBSCRIPTION_TYPE_UPDATE,
SUBSCRIPTION_TYPE_DELETE,
processEntitySubscriptions,
pubsub,
} from './Subscription';
import { Entity } from '../entity/Entity';
import { DataTypeString } from '../datatype/dataTypes';
import { passOrThrow } from '../util';
import { generateTestSchema } from '../../graphqlProtocol/test-helper';
import { generateGraphQLSchema } from '../../graphqlProtocol/generator';
import { subscribe, parse } from 'graphql';

describe('Mutation', () => {
describe('Subscription', () => {
const entity = new Entity({
name: 'SomeEntityName',
description: 'Just some description',
Expand Down Expand Up @@ -92,7 +96,7 @@ describe('Mutation', () => {
const subscription = new Subscription({
name: 'example',
type: SUBSCRIPTION_TYPE_CREATE,
description: 'mutate the world',
description: 'subscribe the world',
attributes: ['anything', { foo: 'bar' }],
});

Expand All @@ -107,7 +111,7 @@ describe('Mutation', () => {
const subscription = new Subscription({
name: 'example',
type: SUBSCRIPTION_TYPE_UPDATE,
description: 'mutate the world',
description: 'subscribe the world',
attributes: [],
});

Expand All @@ -119,7 +123,7 @@ describe('Mutation', () => {
const subscription = new Subscription({
name: 'example',
type: SUBSCRIPTION_TYPE_DELETE,
description: 'mutate the world',
description: 'subscribe the world',
attributes: [],
});

Expand Down Expand Up @@ -154,44 +158,48 @@ describe('Mutation', () => {
expect(String(subscription)).toBe('example');
});

// it('should have a valid preProcessor function', () => {
// function fn() {
// // eslint-disable-next-line no-new
// new Subscription({
// name: 'example',
// type: SUBSCRIPTION_TYPE_CREATE,
// description: 'mutate the world',
// attributes: ['anything'],
// preProcessor: 'not-a-function',
// });
// }

// expect(fn).toThrowErrorMatchingSnapshot();
// });

// it('should have a valid postProcessor function', () => {
// function fn() {
// // eslint-disable-next-line no-new
// new Subscription({
// name: 'example',
// type: SUBSCRIPTION_TYPE_CREATE,
// description: 'mutate the world',
// attributes: ['anything'],
// postProcessor: 'not-a-function',
// });
// }

// expect(fn).toThrowErrorMatchingSnapshot();
// });
it('should have a valid preProcessor function', () => {
function fn() {
// eslint-disable-next-line no-new
new Subscription({
name: 'example',
type: SUBSCRIPTION_TYPE_CREATE,
description: 'mutate the world',
attributes: ['anything'],
preProcessor: 'not-a-function',
});
}

expect(fn).toThrowErrorMatchingSnapshot();
});

it('should have a valid postProcessor function', () => {
function fn() {
// eslint-disable-next-line no-new
new Subscription({
name: 'example',
type: SUBSCRIPTION_TYPE_CREATE,
description: 'mutate the world',
attributes: ['anything'],
postProcessor: 'not-a-function',
});
}

expect(fn).toThrowErrorMatchingSnapshot();
});

describe('isSubscription', () => {
const subscription = new Subscription({
name: 'example',
type: SUBSCRIPTION_TYPE_UPDATE,
description: 'mutate the world',
attributes: ['anything'],
// preProcessor() {},
// postProcessor() {},
preProcessor() {
return {};
},
postProcessor() {
return {};
},
});

it('should recognize objects of type Subscription', () => {
Expand Down Expand Up @@ -220,27 +228,6 @@ describe('Mutation', () => {
});

describe('processEntitySubscriptions', () => {
// const subscriptionTypeCreateDefinition = {
// type: SUBSCRIPTION_TYPE_CREATE,
// name: 'build',
// description: 'on built item',
// attributes: ['someAttribute'],
// };

// const subscriptionTypeUpdateDefinition = {
// type: SUBSCRIPTION_TYPE_UPDATE,
// name: 'change',
// description: 'on changed item',
// attributes: ['id', 'someAttribute'],
// };

// const subscriptionTypeDeleteDefinition = {
// type: SUBSCRIPTION_TYPE_DELETE,
// name: 'drop',
// description: 'on dropped item',
// attributes: ['id'],
// };

it('should throw if provided with an invalid list of subscriptions', () => {
const subscriptions = {
foo: [{}],
Expand All @@ -263,7 +250,7 @@ describe('Mutation', () => {
expect(fn).toThrowErrorMatchingSnapshot();
});

it('should throw if required attribute (without defaultValue) is missing in CREATE type subscriptions', () => {
it('should throw if required attribute is missing in CREATE type subscriptions', () => {
function fn() {
const otherEntity = new Entity({
name: 'SomeEntityName',
Expand All @@ -282,14 +269,14 @@ describe('Mutation', () => {
subscriptions: [
new Subscription({
type: SUBSCRIPTION_TYPE_CREATE,
name: 'build',
name: 'onBuild',
description: 'build item',
attributes: ['someAttribute'],
}),
],
});

otherEntity.getMutationByName('build');
otherEntity.getSubscriptionByName('onBuild');
}

expect(fn).toThrowErrorMatchingSnapshot();
Expand All @@ -299,13 +286,13 @@ describe('Mutation', () => {
const subscriptions = [
new Subscription({
type: SUBSCRIPTION_TYPE_CREATE,
name: 'build',
name: 'onBuild',
description: 'build item',
attributes: ['someAttribute'],
}),
new Subscription({
type: SUBSCRIPTION_TYPE_DELETE,
name: 'build',
name: 'onBuild',
description: 'build item',
attributes: ['someAttribute'],
}),
Expand All @@ -322,7 +309,7 @@ describe('Mutation', () => {
const subscriptions = [
new Subscription({
type: SUBSCRIPTION_TYPE_CREATE,
name: 'build',
name: 'onBuild',
description: 'build item',
attributes: ['doesNotExist'],
}),
Expand All @@ -339,7 +326,7 @@ describe('Mutation', () => {
const subscriptions = [
new Subscription({
type: SUBSCRIPTION_TYPE_DELETE,
name: 'drop',
name: 'onDrop',
description: 'drop item',
attributes: [],
}),
Expand All @@ -348,4 +335,94 @@ describe('Mutation', () => {
processEntitySubscriptions(entity, subscriptions);
});
});

describe('preProcessor', () => {
it('should pass through preProcessor if it is declared', async () => {
const testEntity = new Entity({
name: 'SomeTestsEntityName',
description: 'Just some description',
attributes: {
someAttribute: {
type: DataTypeString,
description: 'Just some description',
required: true,
},
anotherAttribute: {
type: DataTypeString,
description: 'Just some description',
},
},
subscriptions: [
new Subscription({
name: 'SomeSubWithPreProcessor',
type: SUBSCRIPTION_TYPE_CREATE,
description: 'build item',
attributes: ['someAttribute'],
delimiter: '/',
wildCard: '',
pattern: '',
// pattern: 'someAttribute/anotherAttribute',
preProcessor: (_entity, _source, payload) => {
if (payload === 13) {
throw new Error('13 brings bad luck');
}
return payload;
},
}),
],
});

const subscriptionByName = testEntity.getSubscriptionByName(
'SomeSubWithPreProcessor',
);

expect(subscriptionByName).toMatchSnapshot();

const setup = await generateTestSchema({ entities: [testEntity] });

const graphqlSchema = generateGraphQLSchema(setup.configuration);

const subscriptionDoc = parse(`
subscription someSubWithPreProcessorSomeTestsEntityName($input: SomeSubWithPreProcessorSomeTestsEntityNameInput!) {
someSubWithPreProcessorSomeTestsEntityName(input: $input) {
someTestsEntityName {
someAttribute
}
}
}`);

const subscription = (await subscribe({
schema: graphqlSchema,
document: subscriptionDoc,
variableValues: {
input: {
someTestsEntityName: {
someAttribute: 'test',
},
},
},
contextValue: { pubsub },
})) as AsyncIterableIterator<any>;

// if (subscription.errors) {
// console.log({ errors: subscription.errors });
// }

const pending = subscription.next();

await pubsub.publish('SomeSubWithPreProcessorSomeTestsEntityName', {
// someTestsEntityName: {
someAttribute: 'hello',
anotherAttribute: 'world',
// },
});

const result = await pending;
// console.log('should pass through preProcessor if it is declared', result);

expect(result).toMatchSnapshot();

expect(await subscription.return()).toMatchSnapshot();
});
});
});
64 changes: 52 additions & 12 deletions src/engine/subscription/__snapshots__/Subscription.spec.ts.snap
@@ -1,25 +1,65 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Mutation isSubscription should recognize non-Subscription objects 1`] = `"Not a Subscription object"`;
exports[`Subscription isSubscription should recognize non-Subscription objects 1`] = `"Not a Subscription object"`;

exports[`Mutation processEntitySubscriptions should throw if provided with an invalid list of subscriptions 1`] = `"Entity 'SomeEntityName' subscriptions definition needs to be an array of subscriptions"`;
exports[`Subscription preProcessor should pass through preProcessor if it is declared 1`] = `
Subscription {
"attributes": Array [
"someAttribute",
],
"delimiter": "/",
"description": "build item",
"isTypeCreate": true,
"name": "SomeSubWithPreProcessor",
"preProcessor": [Function],
"type": "onCreate",
}
`;

exports[`Mutation processEntitySubscriptions should throw if provided with an invalid subscription 1`] = `"Invalid subscription definition for entity 'SomeEntityName' at position '0'"`;
exports[`Subscription preProcessor should pass through preProcessor if it is declared 2`] = `
Object {
"done": false,
"value": Object {
"data": Object {
"someSubWithPreProcessorSomeTestsEntityName": Object {
"someTestsEntityName": Object {
"someAttribute": "hello",
},
},
},
},
}
`;

exports[`Mutation processEntitySubscriptions should throw if required attribute (without defaultValue) is missing in CREATE type subscriptions 1`] = `"Invalid setup property 'subscriptions' in entity 'SomeEntityName'"`;
exports[`Subscription preProcessor should pass through preProcessor if it is declared 3`] = `
Object {
"done": true,
"value": undefined,
}
`;

exports[`Mutation processEntitySubscriptions should throw if unknown attributes are used 1`] = `"Cannot use attribute 'SomeEntityName.doesNotExist' in subscription 'SomeEntityName.build' as it does not exist"`;
exports[`Subscription processEntitySubscriptions should throw if provided with an invalid list of subscriptions 1`] = `"Entity 'SomeEntityName' subscriptions definition needs to be an array of subscriptions"`;

exports[`Mutation processEntitySubscriptions should throw on duplicate subscription names 1`] = `"Duplicate subscription name 'build' found in 'SomeEntityName'"`;
exports[`Subscription processEntitySubscriptions should throw if provided with an invalid subscription 1`] = `"Invalid subscription definition for entity 'SomeEntityName' at position '0'"`;

exports[`Mutation should have a description 1`] = `"Missing description for subscription 'example'"`;
exports[`Subscription processEntitySubscriptions should throw if required attribute is missing in CREATE type subscriptions 1`] = `"Missing required attributes in subscription 'SomeEntityName.onBuild' need to have a defaultValue() function: [ neededAttribute ]"`;

exports[`Mutation should have a list of unique attribute names 1`] = `"Subscription 'SomeEntityName.example' needs to have a list of unique attribute names"`;
exports[`Subscription processEntitySubscriptions should throw if unknown attributes are used 1`] = `"Cannot use attribute 'SomeEntityName.doesNotExist' in subscription 'SomeEntityName.onBuild' as it does not exist"`;

exports[`Mutation should have a list of valid attribute names 1`] = `"Subscription 'SomeEntityName.example' needs to have a list of attribute names"`;
exports[`Subscription processEntitySubscriptions should throw on duplicate subscription names 1`] = `"Duplicate subscription name 'onBuild' found in 'SomeEntityName'"`;

exports[`Mutation should have a name 1`] = `"Missing subscription name"`;
exports[`Subscription should have a description 1`] = `"Missing description for subscription 'example'"`;

exports[`Mutation should have a type 1`] = `"Missing type for subscription 'example'"`;
exports[`Subscription should have a list of unique attribute names 1`] = `"Subscription 'SomeEntityName.example' needs to have a list of unique attribute names"`;

exports[`Mutation should have a valid type 1`] = `"Unknown subscription type '12346' used, try one of these: 'onCreate, onUpdate, onDelete'"`;
exports[`Subscription should have a list of valid attribute names 1`] = `"Subscription 'SomeEntityName.example' needs to have a list of attribute names"`;

exports[`Subscription should have a name 1`] = `"Missing subscription name"`;

exports[`Subscription should have a type 1`] = `"Missing type for subscription 'example'"`;

exports[`Subscription should have a valid postProcessor function 1`] = `"postProcessor of subscription 'example' needs to be a valid function"`;

exports[`Subscription should have a valid preProcessor function 1`] = `"preProcessor of subscription 'example' needs to be a valid function"`;

exports[`Subscription should have a valid type 1`] = `"Unknown subscription type '12346' used, try one of these: 'onCreate, onUpdate, onDelete'"`;

0 comments on commit 27e59f5

Please sign in to comment.