blob: 8fe42b5e7e8f1b35cfa58c71f5f59b83d800467f [file]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import {
render,
screen,
waitFor,
userEvent,
} from 'spec/helpers/testing-library';
import { SupersetClient } from '@superset-ui/core';
import AddSemanticViewModal from './AddSemanticViewModal';
jest.mock('@superset-ui/core', () => ({
...jest.requireActual('@superset-ui/core'),
SupersetClient: {
...jest.requireActual('@superset-ui/core').SupersetClient,
get: jest.fn(),
post: jest.fn(),
},
}));
const mockedGet = SupersetClient.get as jest.Mock;
const mockedPost = SupersetClient.post as jest.Mock;
const createProps = () => ({
show: true,
onHide: jest.fn(),
onSuccess: jest.fn(),
addDangerToast: jest.fn(),
addSuccessToast: jest.fn(),
});
const selectOption = async (name: string, optionLabel: string) => {
const select = await screen.findByRole('combobox', { name });
await userEvent.click(select);
await userEvent.click(await screen.findByText(optionLabel));
};
beforeEach(() => {
mockedGet.mockReset();
mockedPost.mockReset();
});
test('loads layers on open and adds selected semantic views', async () => {
mockedGet.mockResolvedValue({
json: {
result: [{ uuid: 'layer-1', name: 'Snowflake SL' }],
},
});
mockedPost.mockImplementation(({ endpoint }: { endpoint: string }) => {
if (endpoint === '/api/v1/semantic_layer/layer-1/schema/runtime') {
return Promise.resolve({ json: { result: { properties: {} } } });
}
if (endpoint === '/api/v1/semantic_layer/layer-1/views') {
return Promise.resolve({
json: {
result: [
{ name: 'orders', already_added: false },
{ name: 'customers', already_added: true },
],
},
});
}
if (endpoint === '/api/v1/semantic_view/') {
return Promise.resolve({
json: {
result: {
created: [{ uuid: 'view-1', name: 'orders' }],
},
},
});
}
return Promise.reject(new Error(`Unexpected endpoint: ${endpoint}`));
});
const props = createProps();
render(<AddSemanticViewModal {...props} />);
await waitFor(() => {
expect(mockedGet).toHaveBeenCalledWith({
endpoint: '/api/v1/semantic_layer/',
});
});
await selectOption('Semantic layer', 'Snowflake SL');
await waitFor(() => {
expect(mockedPost).toHaveBeenCalledWith({
endpoint: '/api/v1/semantic_layer/layer-1/schema/runtime',
jsonPayload: {},
});
});
await waitFor(() => {
expect(mockedPost).toHaveBeenCalledWith({
endpoint: '/api/v1/semantic_layer/layer-1/views',
jsonPayload: { runtime_data: {} },
});
});
await selectOption('Semantic views', 'orders');
await userEvent.click(
screen.getByRole('button', { name: /add 1 view\(s\)/i }),
);
await waitFor(() => {
expect(mockedPost).toHaveBeenCalledWith({
endpoint: '/api/v1/semantic_view/',
jsonPayload: {
views: [
{
name: 'orders',
semantic_layer_uuid: 'layer-1',
configuration: {},
},
],
},
});
});
expect(props.addSuccessToast).toHaveBeenCalledWith(
'1 semantic view(s) added',
);
expect(props.onSuccess).toHaveBeenCalled();
expect(props.onHide).toHaveBeenCalled();
});
test('shows partial success feedback when only some semantic views are created', async () => {
mockedGet.mockResolvedValue({
json: {
result: [{ uuid: 'layer-1', name: 'Snowflake SL' }],
},
});
mockedPost.mockImplementation(({ endpoint }: { endpoint: string }) => {
if (endpoint === '/api/v1/semantic_layer/layer-1/schema/runtime') {
return Promise.resolve({ json: { result: { properties: {} } } });
}
if (endpoint === '/api/v1/semantic_layer/layer-1/views') {
return Promise.resolve({
json: {
result: [
{ name: 'orders', already_added: false },
{ name: 'customers', already_added: false },
],
},
});
}
if (endpoint === '/api/v1/semantic_view/') {
return Promise.resolve({
json: {
result: {
created: [{ uuid: 'view-1', name: 'orders' }],
errors: [{ name: 'customers', error: 'create failed' }],
},
},
});
}
return Promise.reject(new Error(`Unexpected endpoint: ${endpoint}`));
});
const props = createProps();
render(<AddSemanticViewModal {...props} />);
await selectOption('Semantic layer', 'Snowflake SL');
await waitFor(() => {
expect(
screen.getByRole('combobox', { name: 'Semantic views' }),
).toBeInTheDocument();
});
await selectOption('Semantic views', 'orders');
await selectOption('Semantic views', 'customers');
await userEvent.click(
screen.getByRole('button', { name: /add 2 view\(s\)/i }),
);
await waitFor(() => {
expect(props.addSuccessToast).toHaveBeenCalledWith(
'1 semantic view(s) added',
);
expect(props.addDangerToast).toHaveBeenCalledWith(
'1 semantic view(s) failed to add: customers',
);
});
expect(props.onSuccess).not.toHaveBeenCalled();
expect(props.onHide).not.toHaveBeenCalled();
});
test('shows toast when loading semantic layers fails', async () => {
mockedGet.mockRejectedValue(new Error('boom'));
const props = createProps();
render(<AddSemanticViewModal {...props} />);
await waitFor(() => {
expect(props.addDangerToast).toHaveBeenCalledWith(
'An error occurred while fetching semantic layers',
);
});
});
test('shows toast when add semantic views fails', async () => {
mockedGet.mockResolvedValue({
json: {
result: [{ uuid: 'layer-1', name: 'Snowflake SL' }],
},
});
mockedPost.mockImplementation(({ endpoint }: { endpoint: string }) => {
if (endpoint === '/api/v1/semantic_layer/layer-1/schema/runtime') {
return Promise.resolve({ json: { result: { properties: {} } } });
}
if (endpoint === '/api/v1/semantic_layer/layer-1/views') {
return Promise.resolve({
json: {
result: [{ name: 'orders', already_added: false }],
},
});
}
if (endpoint === '/api/v1/semantic_view/') {
return Promise.reject(new Error('save failed'));
}
return Promise.reject(new Error(`Unexpected endpoint: ${endpoint}`));
});
const props = createProps();
render(<AddSemanticViewModal {...props} />);
await selectOption('Semantic layer', 'Snowflake SL');
await waitFor(() => {
expect(
screen.getByRole('combobox', { name: 'Semantic views' }),
).toBeInTheDocument();
});
await selectOption('Semantic views', 'orders');
await userEvent.click(
screen.getByRole('button', { name: /add 1 view\(s\)/i }),
);
await waitFor(() => {
expect(props.addDangerToast).toHaveBeenCalledWith(
'An error occurred while adding semantic views',
);
});
});