diff --git a/superset-frontend/src/dashboard/components/CssEditor/CssEditor.test.tsx b/superset-frontend/src/dashboard/components/CssEditor/CssEditor.test.tsx index 16b2a1afbb7c7..28ac7672f691b 100644 --- a/superset-frontend/src/dashboard/components/CssEditor/CssEditor.test.tsx +++ b/superset-frontend/src/dashboard/components/CssEditor/CssEditor.test.tsx @@ -21,6 +21,7 @@ import { render, screen, waitFor } from 'spec/helpers/testing-library'; import { CssEditor as AceCssEditor } from 'src/components/AsyncAceEditor'; import { IAceEditorProps } from 'react-ace'; import userEvent from '@testing-library/user-event'; +import fetchMock from 'fetch-mock'; import CssEditor from '.'; jest.mock('src/components/AsyncAceEditor', () => ({ @@ -33,46 +34,59 @@ jest.mock('src/components/AsyncAceEditor', () => ({ })); const templates = [ - { label: 'Template A', css: 'background-color: red;' }, - { label: 'Template B', css: 'background-color: blue;' }, - { label: 'Template C', css: 'background-color: yellow;' }, + { template_name: 'Template A', css: 'background-color: red;' }, + { template_name: 'Template B', css: 'background-color: blue;' }, + { template_name: 'Template C', css: 'background-color: yellow;' }, ]; +fetchMock.get('glob:*/csstemplateasyncmodelview/api/read', { + result: templates, +}); + AceCssEditor.preload = () => new Promise(() => {}); -test('renders with default props', () => { - render(Click} />); +const defaultProps = { + triggerNode: <>Click, + addDangerToast: jest.fn(), +}; + +test('renders with default props', async () => { + await waitFor(() => render()); expect(screen.getByRole('button', { name: 'Click' })).toBeInTheDocument(); }); -test('renders with initial CSS', () => { +test('renders with initial CSS', async () => { const initialCss = 'margin: 10px;'; - render(Click} initialCss={initialCss} />); + await waitFor(() => + render(), + ); userEvent.click(screen.getByRole('button', { name: 'Click' })); expect(screen.getByText(initialCss)).toBeInTheDocument(); }); test('renders with templates', async () => { - render(Click} templates={templates} />); + await waitFor(() => render()); userEvent.click(screen.getByRole('button', { name: 'Click' })); userEvent.hover(screen.getByText('Load a CSS template')); await waitFor(() => { templates.forEach(template => - expect(screen.getByText(template.label)).toBeInTheDocument(), + expect(screen.getByText(template.template_name)).toBeInTheDocument(), ); }); }); -test('triggers onChange when using the editor', () => { +test('triggers onChange when using the editor', async () => { const onChange = jest.fn(); const initialCss = 'margin: 10px;'; const additionalCss = 'color: red;'; - render( - Click} - initialCss={initialCss} - onChange={onChange} - />, + await waitFor(() => + render( + , + ), ); userEvent.click(screen.getByRole('button', { name: 'Click' })); expect(onChange).not.toHaveBeenCalled(); @@ -82,12 +96,8 @@ test('triggers onChange when using the editor', () => { test('triggers onChange when selecting a template', async () => { const onChange = jest.fn(); - render( - Click} - templates={templates} - onChange={onChange} - />, + await waitFor(() => + render(), ); userEvent.click(screen.getByRole('button', { name: 'Click' })); userEvent.click(screen.getByText('Load a CSS template')); diff --git a/superset-frontend/src/dashboard/components/CssEditor/index.jsx b/superset-frontend/src/dashboard/components/CssEditor/index.jsx index ad12cb6c78a9e..9fcd1768a8985 100644 --- a/superset-frontend/src/dashboard/components/CssEditor/index.jsx +++ b/superset-frontend/src/dashboard/components/CssEditor/index.jsx @@ -21,7 +21,7 @@ import PropTypes from 'prop-types'; import { AntdDropdown } from 'src/components'; import { Menu } from 'src/components/Menu'; import Button from 'src/components/Button'; -import { t, styled } from '@superset-ui/core'; +import { t, styled, SupersetClient } from '@superset-ui/core'; import ModalTrigger from 'src/components/ModalTrigger'; import { CssEditor as AceCssEditor } from 'src/components/AsyncAceEditor'; @@ -47,7 +47,7 @@ const propTypes = { initialCss: PropTypes.string, triggerNode: PropTypes.node.isRequired, onChange: PropTypes.func, - templates: PropTypes.array, + addDangerToast: PropTypes.func.isRequired, }; const defaultProps = { @@ -60,6 +60,7 @@ class CssEditor extends React.PureComponent { super(props); this.state = { css: props.initialCss, + templates: [], }; this.changeCss = this.changeCss.bind(this); this.changeCssTemplate = this.changeCssTemplate.bind(this); @@ -67,6 +68,22 @@ class CssEditor extends React.PureComponent { componentDidMount() { AceCssEditor.preload(); + + SupersetClient.get({ endpoint: '/csstemplateasyncmodelview/api/read' }) + .then(({ json }) => { + const templates = json.result.map(row => ({ + value: row.template_name, + css: row.css, + label: row.template_name, + })); + + this.setState({ templates }); + }) + .catch(() => { + this.props.addDangerToast( + t('An error occurred while fetching available CSS templates'), + ); + }); } changeCss(css) { @@ -80,10 +97,10 @@ class CssEditor extends React.PureComponent { } renderTemplateSelector() { - if (this.props.templates) { + if (this.state.templates) { const menu = ( - {this.props.templates.map(template => ( + {this.state.templates.map(template => ( {template.label} ))} diff --git a/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx b/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx index f1a3f59039bd4..1926a975bb268 100644 --- a/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx +++ b/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx @@ -19,7 +19,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { isEmpty } from 'lodash'; -import { SupersetClient, t } from '@superset-ui/core'; +import { t } from '@superset-ui/core'; import { Menu } from 'src/components/Menu'; import { URL_PARAMS } from 'src/constants'; import ShareMenuItems from 'src/dashboard/components/menu/ShareMenuItems'; @@ -99,7 +99,6 @@ class HeaderActionsDropdown extends React.PureComponent { super(props); this.state = { css: props.customCss, - cssTemplates: [], showReportSubMenu: null, }; @@ -109,23 +108,6 @@ class HeaderActionsDropdown extends React.PureComponent { this.setShowReportSubMenu = this.setShowReportSubMenu.bind(this); } - UNSAFE_componentWillMount() { - SupersetClient.get({ endpoint: '/csstemplateasyncmodelview/api/read' }) - .then(({ json }) => { - const cssTemplates = json.result.map(row => ({ - value: row.template_name, - css: row.css, - label: row.template_name, - })); - this.setState({ cssTemplates }); - }) - .catch(() => { - this.props.addDangerToast( - t('An error occurred while fetching available CSS templates'), - ); - }); - } - UNSAFE_componentWillReceiveProps(nextProps) { if (this.props.customCss !== nextProps.customCss) { this.setState({ css: nextProps.customCss }, () => { @@ -257,8 +239,8 @@ class HeaderActionsDropdown extends React.PureComponent { {t('Edit CSS')}} initialCss={this.state.css} - templates={this.state.cssTemplates} onChange={this.changeCss} + addDangerToast={addDangerToast} /> )}