UNPKG

@silexlabs/grapesjs-data-source

Version:
313 lines (290 loc) 9.27 kB
/** * @jest-environment jsdom */ import grapesjs, { Component, Editor } from 'grapesjs' import { DataTree } from './DataTree' import { getCompletion, getContext } from './completion' import { simpleFilters, simpleQueryables, simpleTypes, testDataSourceId } from '../test-data' import { DataSourceEditor, Filter, Property, State, Token } from '../types' import { getOrCreatePersistantId, getStateIds } from './state' // FIXME: Workaround to avoid import of lit-html which breakes unit tests jest.mock('lit', () => ({ html: jest.fn(), render: jest.fn(), })) // Mock only getState jest.mock('./state', () => ({ ...jest.requireActual('./state'), getState: jest.fn(), getStateIds: jest.fn(), getOrCreatePersistantId: jest.fn(), getParentByPersistentId: jest.fn(), })) /** * Remove the optionsForm from the token * This is how tokens are stored */ function asStored(val: Token) { delete (val as Property | Filter).optionsForm return val } const simpleQueryableTokens: Property[] = [{ fieldId: 'testSimpleQueryableId', label: 'test queryable', type: 'property', propType: 'field', typeIds: ['testTypeId'], kind: 'scalar', dataSourceId: testDataSourceId, }] const fixedToken = { fieldId: 'fixed', label: 'Fixed value', type: 'property', propType: 'field', kind: 'scalar', typeIds: ['String'], options: { value: '' }, } let editor: Editor beforeEach(async () => { jest.resetAllMocks() ;(getStateIds as jest.Mock).mockReturnValue([]) // Default for getStateIds editor = grapesjs.init({ container: document.createElement('div'), components: '<div></div>', }) }) test('get empty context', () => { const editor = grapesjs.init({ container: document.createElement('div'), components: '<div></div>', }) const component = editor.getComponents().first() const dataTree = new DataTree(editor as DataSourceEditor, {filters: [], dataSources: []}) const context = getContext(component, dataTree) expect(context).toBeDefined() expect(context).toHaveLength(1) // 1 Fixed value }) test('get context with filters', () => { const component = editor.getComponents().first() const dataTree = new DataTree(editor as DataSourceEditor, { dataSources: [], filters: simpleFilters, }) const context = getContext(component, dataTree) expect(context).toBeDefined() expect(context).toHaveLength(2) // 1 Filter only for no input + 1 Fixed value const filter = context[0] as Filter expect(filter.id).toBe('testFilterAnyInput') }) test('get context with parent compontent states', () => { const component = editor.getComponents().first() const child: Component = component.append('<div></div>')[0] expect(component.get('components')).toHaveLength(1) expect(child).toBeDefined() // Define mock values ;(getStateIds as jest.Mock).mockImplementation((c: unknown) => { if(c === component) return ['testStateId'] else return [] }) ;(getOrCreatePersistantId as jest.Mock).mockReturnValue('testPersistentId') const dataTree = new DataTree(editor as DataSourceEditor, { filters: [], dataSources: [] }) const context = getContext(child, dataTree) expect(context).toBeDefined() expect(context).toHaveLength(2) // 1 State + 1 Fixed value const typeProp = context[0] as State expect(typeProp.type).toBe('state') expect(typeProp.componentId).toBe('testPersistentId') expect(typeProp.storedStateId).toBe('testStateId') }) // Don't get the states which are not yet defined test('get context with available states only', () => { const component = editor.getComponents().first() const child: Component = component.append('<div></div>')[0] // Define mock values ;(getStateIds as jest.Mock).mockImplementation((c: unknown) => { if(c === component) return ['testStateId0', 'testStateId1', 'testStateId2'] else if(c === child) return ['childStateId0', 'childStateId1', 'childStateId2'] else return [] }) const dataTree = new DataTree(editor as DataSourceEditor, { filters: [], dataSources: [] }) // Case of an attribute, all states are available const context = getContext(component, dataTree) expect(context).toBeDefined() expect(getStateIds).toHaveBeenCalledTimes(2) // The component and the body, not the child expect(getStateIds).toHaveBeenNthCalledWith(1, component, true, undefined) expect(getStateIds).toHaveBeenNthCalledWith(2, component.parent(), true, undefined) // Case of the first state, no states are available ;(getStateIds as jest.Mock).mockClear() const context2 = getContext(child, dataTree, 'childStateId0') expect(context2).toBeDefined() expect(getStateIds).toHaveBeenCalledTimes(3) expect(getStateIds).toHaveBeenNthCalledWith(1, child, true, 'childStateId0') expect(getStateIds).toHaveBeenNthCalledWith(2, child.parent(), true, undefined) }) test('get context with data source queryable values', () => { const component = editor.getComponents().first() const dataTree = new DataTree(editor as DataSourceEditor, { filters: [], dataSources: [{ id: testDataSourceId, connect: async () => {}, isConnected: () => true, getTypes: () => [{ id: 'testTypeId1', label: 'test type name 1', kind: 'scalar', fields: [], dataSourceId: testDataSourceId, }, { id: 'testTypeId2', label: 'test type name 2', kind: 'scalar', fields: [], dataSourceId: testDataSourceId, }], getQueryables: () => [{ id: 'testFieldId2', label: 'test field name 2', typeIds: ['testTypeId2'], kind: 'scalar', dataSourceId: testDataSourceId, }], getQuery: () => '', }], }) const context = getContext(component, dataTree) expect(context).toBeDefined() expect(context).toHaveLength(2) // 1 Queryable + 1 Fixed value const typeProp = context[0] as Property expect(typeProp.fieldId).toContain('testFieldId2') }) test('get completion with simple context', () => { const dataTree = new DataTree(editor as DataSourceEditor, { filters: [], dataSources: [{ id: testDataSourceId, connect: async () => { }, isConnected: () => true, getTypes: () => simpleTypes, getQueryables: () => simpleQueryables, getQuery: () => '', }], }) const component = editor.getComponents().first() // Empty value // The context is the queryables here const completion1 = getCompletion({ component, expression: [], dataTree, }) expect(completion1).toHaveLength(2) expect(completion1.map(asStored)).toEqual([ ...simpleQueryableTokens, fixedToken, ]) // 1 level value const completion2 = getCompletion({ component, expression: [{ type: 'property', propType: 'field', fieldId: 'testFieldId', label: 'test field name', typeIds: ['testTypeId'], kind: 'object', dataSourceId: testDataSourceId, }], dataTree, }) expect(completion2).toHaveLength(1) const typeProp = completion2[0] as Property expect(typeProp.typeIds).toContain('testFieldTypeId') // 2 levels value const completion3 = getCompletion({ component, expression: [{ type: 'property', propType: 'field', fieldId: 'testFieldId', label: 'test field name', typeIds: ['testTypeId'], kind: 'object', dataSourceId: testDataSourceId, }, { type: 'property', propType: 'field', fieldId: 'testFieldId', label: 'test field name', typeIds: ['testFieldTypeId'], kind: 'object', dataSourceId: testDataSourceId, }], dataTree, }) expect(completion3).toHaveLength(0) }) test('get completion with filters', () => { const dataTree = new DataTree(editor as DataSourceEditor, { filters: simpleFilters, dataSources: [{ id: testDataSourceId, connect: async () => { }, isConnected: () => true, getTypes: () => simpleTypes, getQueryables: () => simpleQueryables, getQuery: () => '', }], }) const component = editor.getComponents().first() // Empty value expect(getCompletion({ component, expression: [], dataTree, }).map(asStored)).toEqual([ simpleQueryableTokens[0], simpleFilters[0], fixedToken, ]) // 1 level value const completion = getCompletion({ component, expression: [{ type: 'property', propType: 'field', fieldId: 'testFieldId', label: 'test field name', typeIds: ['testTypeId'], kind: 'object', dataSourceId: testDataSourceId, }], dataTree, }) expect(completion).toHaveLength(2) // 1 field and 1 filters // 2 levels value const completion2 = getCompletion({ component, expression: [{ type: 'property', propType: 'field', fieldId: 'testFieldId', label: 'test field name', typeIds: ['testTypeId'], kind: 'object', dataSourceId: testDataSourceId, }, { type: 'property', propType: 'field', fieldId: 'testFieldId', label: 'test field name', typeIds: ['testFieldTypeId'], kind: 'object', dataSourceId: testDataSourceId, }], dataTree, }) expect(completion2).toHaveLength(1) // 1 filter })