| import fetchMock from 'fetch-mock'; |
| import { |
| SupersetClientClass, |
| SupersetClient, |
| buildQueryContext, |
| QueryFormData, |
| configure as configureTranslation, |
| } from '@superset-ui/core/src'; |
| |
| import { |
| ChartClient, |
| getChartBuildQueryRegistry, |
| getChartMetadataRegistry, |
| ChartMetadata, |
| } from '@superset-ui/core/src/chart'; |
| import { SliceIdAndOrFormData } from '@superset-ui/core/src/chart/clients/ChartClient'; |
| import { LOGIN_GLOB } from '../fixtures/constants'; |
| import { sankeyFormData } from '../fixtures/formData'; |
| |
| configureTranslation(); |
| |
| describe('ChartClient', () => { |
| let chartClient: ChartClient; |
| |
| beforeAll(() => { |
| fetchMock.get(LOGIN_GLOB, { csrf_token: '1234' }); |
| SupersetClient.reset(); |
| SupersetClient.configure().init(); |
| }); |
| |
| beforeEach(() => { |
| chartClient = new ChartClient(); |
| }); |
| |
| afterEach(fetchMock.restore); |
| |
| describe('new ChartClient(config)', () => { |
| it('creates a client without argument', () => { |
| expect(chartClient).toBeInstanceOf(ChartClient); |
| }); |
| it('creates a client with specified config.client', () => { |
| const customClient = new SupersetClientClass(); |
| chartClient = new ChartClient({ client: customClient }); |
| expect(chartClient).toBeInstanceOf(ChartClient); |
| expect(chartClient.client).toBe(customClient); |
| }); |
| }); |
| |
| describe('.loadFormData({ sliceId, formData }, options)', () => { |
| const sliceId = 123; |
| it('fetches formData if given only sliceId', () => { |
| fetchMock.get(`glob:*/api/v1/form_data/?slice_id=${sliceId}`, sankeyFormData); |
| |
| return expect(chartClient.loadFormData({ sliceId })).resolves.toEqual(sankeyFormData); |
| }); |
| it('fetches formData from sliceId and merges with specify formData if both fields are specified', () => { |
| fetchMock.get(`glob:*/api/v1/form_data/?slice_id=${sliceId}`, sankeyFormData); |
| |
| return expect( |
| chartClient.loadFormData({ |
| sliceId, |
| formData: { |
| granularity: 'second', |
| viz_type: 'bar', |
| }, |
| }), |
| ).resolves.toEqual({ |
| ...sankeyFormData, |
| granularity: 'second', |
| viz_type: 'bar', |
| }); |
| }); |
| it('returns promise of formData if only formData was given', () => |
| expect( |
| chartClient.loadFormData({ |
| formData: { |
| datasource: '1__table', |
| granularity: 'minute', |
| viz_type: 'line', |
| }, |
| }), |
| ).resolves.toEqual({ |
| datasource: '1__table', |
| granularity: 'minute', |
| viz_type: 'line', |
| })); |
| it('rejects if none of sliceId or formData is specified', () => |
| expect(chartClient.loadFormData({} as SliceIdAndOrFormData)).rejects.toEqual( |
| new Error('At least one of sliceId or formData must be specified'), |
| )); |
| }); |
| |
| describe('.loadQueryData(formData, options)', () => { |
| it('returns a promise of query data for known chart type', () => { |
| getChartMetadataRegistry().registerValue( |
| 'word_cloud', |
| new ChartMetadata({ name: 'Word Cloud', thumbnail: '' }), |
| ); |
| |
| getChartBuildQueryRegistry().registerValue('word_cloud', (formData: QueryFormData) => |
| buildQueryContext(formData), |
| ); |
| fetchMock.post('glob:*/api/v1/chart/data', [ |
| { |
| field1: 'abc', |
| field2: 'def', |
| }, |
| ]); |
| |
| return expect( |
| chartClient.loadQueryData({ |
| granularity: 'minute', |
| viz_type: 'word_cloud', |
| datasource: '1__table', |
| }), |
| ).resolves.toEqual([ |
| { |
| field1: 'abc', |
| field2: 'def', |
| }, |
| ]); |
| }); |
| it('returns a promise that rejects for unknown chart type', () => |
| expect( |
| chartClient.loadQueryData({ |
| granularity: 'minute', |
| viz_type: 'rainbow_3d_pie', |
| datasource: '1__table', |
| }), |
| ).rejects.toEqual(new Error('Unknown chart type: rainbow_3d_pie'))); |
| |
| it('fetches data from the legacy API if ChartMetadata has useLegacyApi=true,', () => { |
| // note legacy charts do not register a buildQuery function in the registry |
| getChartMetadataRegistry().registerValue( |
| 'word_cloud_legacy', |
| new ChartMetadata({ |
| name: 'Legacy Word Cloud', |
| thumbnail: '.png', |
| useLegacyApi: true, |
| }), |
| ); |
| |
| fetchMock.post('glob:*/api/v1/chart/data', () => |
| Promise.reject(new Error('Unexpected all to v1 API')), |
| ); |
| |
| fetchMock.post('glob:*/superset/explore_json/', { |
| field1: 'abc', |
| field2: 'def', |
| }); |
| |
| return expect( |
| chartClient.loadQueryData({ |
| granularity: 'minute', |
| viz_type: 'word_cloud_legacy', |
| datasource: '1__table', |
| }), |
| ).resolves.toEqual([ |
| { |
| field1: 'abc', |
| field2: 'def', |
| }, |
| ]); |
| }); |
| }); |
| |
| describe('.loadDatasource(datasourceKey, options)', () => { |
| it('fetches datasource', () => { |
| fetchMock.get('glob:*/superset/fetch_datasource_metadata?datasourceKey=1__table', { |
| field1: 'abc', |
| field2: 'def', |
| }); |
| |
| return expect(chartClient.loadDatasource('1__table')).resolves.toEqual({ |
| field1: 'abc', |
| field2: 'def', |
| }); |
| }); |
| }); |
| |
| describe('.loadAnnotation(annotationLayer)', () => { |
| it('returns an empty object if the annotation layer does not require query', () => |
| expect( |
| chartClient.loadAnnotation({ |
| name: 'my-annotation', |
| }), |
| ).resolves.toEqual({})); |
| it('otherwise returns a rejected promise because it is not implemented yet', () => |
| expect( |
| chartClient.loadAnnotation({ |
| name: 'my-annotation', |
| sourceType: 'abc', |
| }), |
| ).rejects.toEqual(new Error('This feature is not implemented yet.'))); |
| }); |
| |
| describe('.loadAnnotations(annotationLayers)', () => { |
| it('loads multiple annotation layers and combine results', () => |
| expect( |
| chartClient.loadAnnotations([ |
| { |
| name: 'anno1', |
| }, |
| { |
| name: 'anno2', |
| }, |
| { |
| name: 'anno3', |
| }, |
| ]), |
| ).resolves.toEqual({ |
| anno1: {}, |
| anno2: {}, |
| anno3: {}, |
| })); |
| it('returns an empty object if input is not an array', () => |
| expect(chartClient.loadAnnotations()).resolves.toEqual({})); |
| it('returns an empty object if input is an empty array', () => |
| expect(chartClient.loadAnnotations()).resolves.toEqual({})); |
| }); |
| |
| describe('.loadChartData({ sliceId, formData })', () => { |
| const sliceId = 10120; |
| it('loadAllDataNecessaryForAChart', () => { |
| fetchMock.get(`glob:*/api/v1/form_data/?slice_id=${sliceId}`, { |
| granularity: 'minute', |
| viz_type: 'line', |
| datasource: '1__table', |
| color: 'living-coral', |
| }); |
| |
| fetchMock.get('glob:*/superset/fetch_datasource_metadata?datasourceKey=1__table', { |
| name: 'transactions', |
| schema: 'staging', |
| }); |
| |
| fetchMock.post('glob:*/api/v1/chart/data', { |
| lorem: 'ipsum', |
| dolor: 'sit', |
| amet: true, |
| }); |
| |
| getChartMetadataRegistry().registerValue( |
| 'line', |
| new ChartMetadata({ name: 'Line', thumbnail: '.gif' }), |
| ); |
| |
| getChartBuildQueryRegistry().registerValue('line', (formData: QueryFormData) => |
| buildQueryContext(formData), |
| ); |
| |
| return expect( |
| chartClient.loadChartData({ |
| sliceId, |
| }), |
| ).resolves.toEqual({ |
| annotationData: {}, |
| datasource: { |
| name: 'transactions', |
| schema: 'staging', |
| }, |
| formData: { |
| granularity: 'minute', |
| viz_type: 'line', |
| datasource: '1__table', |
| color: 'living-coral', |
| }, |
| queriesData: [ |
| { |
| lorem: 'ipsum', |
| dolor: 'sit', |
| amet: true, |
| }, |
| ], |
| }); |
| }); |
| }); |
| }); |