UNPKG

@silexlabs/grapesjs-data-source

Version:
656 lines (619 loc) 18.5 kB
import GraphQL, { GQLField, GQLType, GQLKind, GraphQLOptions, GQLOfType } from './GraphQL' import { directusTestSchema, simpleSchema, strapiSchema} from '../../__mocks__/graphql-mocks' import { Field, Tree, Type } from '../types' import dedent from 'dedent-js' import { importDataSource } from '../test-data' // FIXME: Workaround to avoid import of lit-html which breakes unit tests jest.mock('lit', () => ({ html: jest.fn(), render: jest.fn(), })) const bearerToken = process.env.BEARER ?? '' const options: GraphQLOptions = { id: 'testDataSourceId', type: 'graphql', label: 'GraphQL', url: `https://sandbox.internet2000.net/cms/graphql?access_token=${bearerToken}`, method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + bearerToken, }, //queryable: ['posts', 'Contact', 'test'], } class GQLTest extends GraphQL { protected queryType = 'query' constructor(options: GraphQLOptions, private overrideTypes: Type[] = [], private overrideFields: Field[] = []) { super(options) } getTypes(): Type[] { return this.overrideTypes } getQueryables(): Field[] { return this.overrideFields } graphQLToField(field: GQLField): Field { return super.graphQLToField(field) } graphQLToType(allTypes: string[], type: GQLType, kind: GQLKind, queryable: boolean): Type { return super.graphQLToType(allTypes, type, kind, queryable) } getOfTypeProp<T>(prop: string, type: GQLOfType, defaultValue?: T): T { return super.getOfTypeProp(prop, type, defaultValue) } getQuery(...args: unknown[]): string { /* @ts-expect-error just a mock */ return super.getQuery(...args) } } beforeEach(async () => { jest.resetAllMocks() }) test('getTypeProp', async () => { const gql = new GQLTest({ url: 'http://localhost', method: 'POST', headers: {}, id: 'testDataSourceId', label: 'test', type: 'graphql', }) expect(gql.getOfTypeProp('kind', {kind: 'SCALAR'})).toBe('SCALAR') expect(gql.getOfTypeProp('kind', {kind: 'NON_NULL', ofType: {kind: 'SCALAR'}})).toBe('SCALAR') expect(gql.getOfTypeProp('kind', {kind: 'NON_NULL', ofType: {kind: 'LIST', ofType: {kind: 'SCALAR'}}})).toBe('SCALAR') expect(gql.getOfTypeProp('kind', {kind: 'NON_NULL', ofType: {kind: 'LIST', ofType: {kind: 'NON_NULL', ofType: {kind: 'SCALAR'}}}})).toBe('SCALAR') expect(gql.getOfTypeProp('kind', {kind: 'NON_NULL', ofType: {kind: 'LIST', ofType: {kind: 'NON_NULL', ofType: {kind: 'LIST', ofType: {kind: 'SCALAR'}}}}})).toBe('SCALAR') const testType: GQLType = { 'name': 'PostEntityResponseCollection', 'fields': [ { 'name': 'data', 'type': { 'kind': 'NON_NULL', 'ofType': { 'kind': 'LIST', 'ofType': { 'kind': 'NON_NULL', 'ofType': { 'name': 'PostEntity', 'kind': 'OBJECT' } } } } } ] } expect(testType.fields[0].type).not.toBeUndefined() expect(gql.getOfTypeProp('name', testType.fields[0].type)).toBe('PostEntity') }) test('graphQLToType', async () => { const testType: GQLType = { 'name': 'PostEntityResponseCollection', 'fields': [ { 'name': 'data', 'type': { 'kind': 'NON_NULL', 'ofType': { 'kind': 'LIST', 'ofType': { 'kind': 'NON_NULL', 'ofType': { 'name': 'PostEntity', 'kind': 'OBJECT' } } } } } ] } const allTypes = ['PostEntityResponseCollection', 'PostEntity'] const gql = new GQLTest({ url: 'http://localhost', method: 'POST', headers: {}, id: 'testDataSourceId', label: 'test', type: 'graphql', }) const result = gql.graphQLToType(allTypes, testType, 'SCALAR', false) expect(result).not.toBeUndefined() expect(result.label).toBe('PostEntityResponseCollection') expect(result.id).toBe('PostEntityResponseCollection') expect(result.fields).not.toBeUndefined() expect(result.fields).toHaveLength(1) expect(result.fields).toContainEqual({ id: 'data', label: 'data', typeIds: ['PostEntity'], kind: 'list', dataSourceId: 'testDataSourceId', }) }) test('graphQLToField', async () => { const gql = new GQLTest({ url: 'http://localhost', method: 'POST', headers: {}, id: 'testDataSourceId', label: 'test', type: 'graphql', }) const result = gql.graphQLToField({ 'name': 'posts', 'type': { 'name': 'PostEntityResponseCollection', 'kind': 'OBJECT' as GQLKind, }, }) expect(result).not.toBeUndefined() expect(result.id).toBe('posts') expect(result.label).toBe('posts') expect(result.typeIds).toEqual(['PostEntityResponseCollection']) // With possible types expect(gql.graphQLToField({ 'name': 'posts', 'type': { 'name': undefined, 'kind': 'LIST', 'possibleTypes': [ { 'name': 'PostEntityResponseCollection', 'kind': 'OBJECT' as GQLKind, }, ], }, })).toEqual({ id: 'posts', label: 'posts', typeIds: ['PostEntityResponseCollection'], kind: 'object', dataSourceId: 'testDataSourceId', }) expect(gql.graphQLToField({ 'name': 'posts', 'type': { 'name': undefined, 'kind': 'LIST', 'possibleTypes': undefined, 'ofType': { 'kind': 'NON_NULL', 'name': undefined, 'possibleTypes': undefined, 'ofType': { 'kind': 'UNION', 'name': 'PageDataModulesComponentUnionDto', 'possibleTypes': [ { 'kind': 'OBJECT', 'name': 'HeroWordSliderComponent' }, { 'kind': 'OBJECT', 'name': 'SectionSlideshowUpComponent' } ], 'ofType': undefined, } } }, })).toEqual({ id: 'posts', label: 'posts', typeIds: ['HeroWordSliderComponent', 'SectionSlideshowUpComponent'], kind: 'list', dataSourceId: 'testDataSourceId', arguments: undefined, }) }) test('connect', async () => { const DataSource = (await importDataSource([simpleSchema])) const dataSource = new DataSource(options) await dataSource.connect() await new Promise(resolve => setTimeout(resolve, 100)) }) test('getTypes simple mocks', async () => { const GraphQLDataSource = (await importDataSource([simpleSchema])) const dataSource = new GraphQLDataSource(options) await dataSource.connect() const types = await dataSource.getTypes() expect(types).not.toBeUndefined() expect(types!.length).toBeGreaterThan(5) const postsType: Type = types!.find((type: Type) => type.id === 'posts')! expect(postsType).not.toBeUndefined() expect(postsType.id).toBe('posts') expect(postsType.label).toBe('posts') expect(postsType.fields).not.toBeUndefined() expect(postsType.fields).toContainEqual({ id: 'data', label: 'data', typeIds: ['PostEntity'], kind: 'list', dataSourceId: 'testDataSourceId' }) }) test('getTypes directus', async () => { const GraphQLDataSource = (await importDataSource([directusTestSchema])) const dataSource = new GraphQLDataSource(options) await dataSource.connect() const types = await dataSource.getTypes() expect(types).not.toBeUndefined() expect(types!.length).toBeGreaterThan(10) const contactType: Type = types!.find((prop: Type) => prop.id === 'Contact')! expect(contactType).not.toBeUndefined() expect(contactType.id).toBe('Contact') expect(contactType.label).toBe('Contact') expect(contactType.fields).not.toBeUndefined() expect(contactType.fields).toContainEqual({id: 'id', label: 'id', typeIds: ['ID'], kind: 'scalar', dataSourceId: 'testDataSourceId'}) const testType: Type | undefined = types!.find((prop: Type) => prop.id === 'test') expect(testType).not.toBeUndefined() expect(testType!.fields).not.toBeUndefined() const testO2MField: Field | undefined = testType!.fields!.find(field => field.id === 'test_o2m') expect(testO2MField).not.toBeUndefined() expect((testO2MField as unknown as GQLType).fields).toBeUndefined() const testO2MType: Type | undefined = types!.find((t: Type) => testO2MField!.typeIds.includes(t.id)) expect(testO2MType).not.toBeUndefined() expect(testO2MType!.id).toBe('test_o2m') expect(testO2MType!.fields).not.toBeUndefined() expect(testO2MType!.fields).toContainEqual({id: 'id', label: 'id', typeIds: ['ID'], kind: 'scalar', dataSourceId: 'testDataSourceId'}) expect(testO2MType!.fields).toContainEqual({id: 'label', label: 'label', typeIds: ['String'], kind: 'scalar', dataSourceId: 'testDataSourceId'}) }) test('getTypes strapi', async () => { const GraphQLDataSource = (await importDataSource([strapiSchema])) const dataSource = new GraphQLDataSource(options) await dataSource.connect() const types = await dataSource.getTypes() expect(types).not.toBeUndefined() expect(types!.length).toBeGreaterThan(10) const postsType: Type = types!.find((type: Type) => type.id === 'posts')! expect(postsType).not.toBeUndefined() expect(postsType.id).toBe('posts') expect(postsType.label).toBe('posts') expect(postsType.fields).not.toBeUndefined() const dataField = postsType.fields!.find(field => field.id === 'data') expect(dataField).not.toBeUndefined() expect(dataField!.label).toBe('data') expect(dataField!.kind).toBe('list') }) test('getQueryables strapi', async () => { const GraphQLDataSource = (await importDataSource([strapiSchema])) const dataSource = new GraphQLDataSource(options) await dataSource.connect() const queryables = await dataSource.getQueryables() const post: Field = queryables!.find((field: Field) => field.id === 'post')! expect(post).not.toBeUndefined() expect(post.id).toBe('post') expect(post.label).toBe('post') expect(post.arguments).not.toBeUndefined() expect(post.arguments).toHaveLength(1) expect(post.arguments![0].name).toBe('id') }) test('build query from tree', () => { const gql = new GQLTest({ url: 'http://localhost', method: 'POST', headers: {}, id: 'testDataSourceId', label: 'test', type: 'graphql', }, [{ id: 'query', label: 'test type name', dataSourceId: 'testDataSourceId', fields: [{ id: 'posts', label: 'test field name', typeIds: ['PostEntity'], kind: 'object', }], }, { id: 'PostEntity', label: 'test type name', dataSourceId: 'testDataSourceId', fields: [{ id: 'testFieldPropertyId', label: 'test field name', typeIds: ['testTypeId'], kind: 'object', dataSourceId: 'testDataSourceId', }], }]) const tree: Tree = { token: { type: 'property', propType: 'field', fieldId: 'posts', label: 'test field name', typeIds: ['PostEntity'], kind: 'object', dataSourceId: 'testDataSourceId', }, children: [{ token: { type: 'property', propType: 'field', fieldId: 'testFieldPropertyId', label: 'test field property name', typeIds: ['testFieldPropertyTypeId'], kind: 'scalar', dataSourceId: 'testDataSourceId', }, children: [], }], } const query = gql.getQuery([tree]) expect(query) .toEqual(`query { __typename posts { __typename testFieldPropertyId } }`) }) test('build query with fragments', () => { const gql = new GQLTest({ url: 'http://localhost', method: 'POST', headers: {}, id: 'testDataSourceId', label: 'test', type: 'graphql', }, [{ id: 'query', label: 'test type name', dataSourceId: 'testDataSourceId', fields: [{ id: 'parentFieldId', label: 'test field name', typeIds: ['testParentId'], kind: 'object', dataSourceId: 'testDataSourceId', }], }, { id: 'testParentId', label: 'test type name', dataSourceId: 'testDataSourceId', fields: [{ id: 'testFieldId', label: 'test field name', typeIds: ['testTypeId1', 'testTypeId2'], kind: 'object', dataSourceId: 'testDataSourceId', }], }, { id: 'testTypeId1', label: 'test type name', dataSourceId: 'testDataSourceId', fields: [{ id: 'ONLY_TEST_TYPE_ID1', label: 'test field property name', typeIds: ['testFieldPropertyTypeId1'], kind: 'scalar', dataSourceId: 'testDataSourceId', }], }, { id: 'testTypeId2', label: 'test type name', dataSourceId: 'testDataSourceId', fields: [{ id: 'ONLY_TEST_TYPE_ID2', label: 'test field property name', typeIds: ['testFieldPropertyTypeId2'], kind: 'scalar', dataSourceId: 'testDataSourceId', }], }], [{ id: 'testFieldId', label: 'test field name', typeIds: ['testTypeId1', 'testTypeId2'], kind: 'object', dataSourceId: 'testDataSourceId', arguments: [{ name: 'id', typeId: 'ID', }], }, { id: 'parentFieldId', label: 'test field name', typeIds: ['testParentId'], kind: 'object', dataSourceId: 'testDataSourceId', }]) // Simple case expect(gql.getQuery([{ token: { type: 'property', propType: 'field', fieldId: 'parentFieldId', label: 'test parent name', typeIds: ['testParentId'], kind: 'object', dataSourceId: 'testDataSourceId', }, children: [{ token: { type: 'property', propType: 'field', fieldId: 'testFieldId', label: 'test field name', typeIds: ['testTypeId1'], kind: 'object', dataSourceId: 'testDataSourceId', }, children: [], }], }])) .toEqual(dedent` query { __typename parentFieldId { __typename testFieldId { ...on testTypeId1 { __typename } } } }`) // More complex const tree: Tree = { token: { type: 'property', propType: 'field', fieldId: 'parentFieldId', label: 'test parent name', typeIds: ['testParentId'], kind: 'object', dataSourceId: 'testDataSourceId', }, children: [{ token: { type: 'property', propType: 'field', fieldId: 'testFieldId', label: 'test field name', typeIds: ['testTypeId1'], kind: 'object', dataSourceId: 'testDataSourceId', }, children: [{ token: { type: 'property', propType: 'field', fieldId: 'ONLY_TEST_TYPE_ID1', label: 'test field property name', typeIds: ['testFieldPropertyTypeId1'], kind: 'scalar', dataSourceId: 'testDataSourceId', }, children: [], }], }, { token: { type: 'property', propType: 'field', fieldId: 'testFieldId', label: 'test field name', typeIds: ['testTypeId2'], kind: 'object', dataSourceId: 'testDataSourceId', }, children: [{ token: { type: 'property', propType: 'field', fieldId: 'ONLY_TEST_TYPE_ID2', label: 'test field property name', typeIds: ['testFieldPropertyTypeId2'], kind: 'scalar', dataSourceId: 'testDataSourceId', }, children: [], }], }], } const query = gql.getQuery([tree]) expect(query) .toEqual(dedent` query { __typename parentFieldId { __typename testFieldId { ...on testTypeId1 { __typename ONLY_TEST_TYPE_ID1 } } testFieldId { ...on testTypeId2 { __typename ONLY_TEST_TYPE_ID2 } } } }`) }) // test('get query with options', () => { // const fn = jest.fn(expression => ([{ // token: testTokens.rootField1, // children: [], // }] as Tree[])) // class GQLTestQuery extends GraphQL { // getTrees(expression: Expression): Tree[] { // return fn(expression) // } // } // const gql = new GQLTestQuery({ // url: 'http://localhost', // method: 'POST', // headers: {}, // id: 'testDataSourceId', // label: 'test', // type: 'graphql', // }) // const expression: Expression = [{ // ...testTokens.rootField1, // }, { // ...testTokens.filter, // options: { // id: 1, // childExpressionAbsolute: JSON.stringify([testTokens.rootField2, testTokens.childField2]), // childExpressionRelative: JSON.stringify([testTokens.childField1]), // }, // } as Filter, // testTokens.childField3 // ] // expect(() => gql.getQuery([expression])).not.toThrow() // fn.mockClear() // gql.getQuery([expression]) // expect(fn).toHaveBeenCalledTimes(1) // expect(fn).toHaveBeenCalledWith( // [{ // token: testTokens.rootField1, // children: [{ // token: testTokens.childField3, // children: [], // }], // }, { // token: testTokens.rootField1, // children: [{ // token: testTokens.childField1, // children: [], // }], // }, { // token: testTokens.rootField2, // children: [{ // token: testTokens.childField2, // children: [], // }], // }] // ) // }) //// test('Get data', async () => { //// const DataSource = (await importDataSource([connect, postsId, postsDetails])) //// const dataSource = new DataSource(options) //// await dataSource.connect() //// const dataPostsId = await dataSource.getData({ //// name: 'posts', //// attributes: [['limit', '1']], //// }) //// expect(dataPostsId).not.toBeUndefined() //// expect(dataPostsId).toHaveLength(1) //// expect(dataPostsId[0].author).toBeUndefined() //// //// const dataPostsDetails = await dataSource.getData({ //// name: 'posts', //// attributes: [['limit', '1']], //// children: [{ //// name: 'author', //// children: ['email', 'first_name', { //// name: 'avatar', //// children: ['id', 'filename_disk'], //// }], //// }, 'title', 'content'], //// }) //// expect(dataPostsDetails).not.toBeUndefined() //// expect(dataPostsDetails).toHaveLength(1) //// expect(dataPostsDetails[0].author).not.toBeUndefined() //// expect(dataPostsDetails[0].author.avatar).not.toBeUndefined() //// })