diff --git a/superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.test.jsx b/superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.test.jsx index bfc7349107a2c..dd2c3e9e10436 100644 --- a/superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.test.jsx +++ b/superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.test.jsx @@ -16,16 +16,14 @@ * specific language governing permissions and limitations * under the License. */ -import sinon from 'sinon'; -import { shallow } from 'enzyme'; -import { AGGREGATES } from 'src/explore/constants'; -import { LabelsContainer } from 'src/explore/components/controls/OptionControls'; -import { supersetTheme } from '@superset-ui/core'; +import { screen, render, selectOption } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; import MetricsControl from 'src/explore/components/controls/MetricControl/MetricsControl'; import AdhocMetric, { EXPRESSION_TYPES, } from 'src/explore/components/controls/MetricControl/AdhocMetric'; +import { AGGREGATES } from 'src/explore/constants'; const defaultProps = { name: 'metrics', @@ -45,131 +43,140 @@ const defaultProps = { }; function setup(overrides) { - const onChange = sinon.spy(); + const onChange = jest.fn(); const props = { onChange, - theme: supersetTheme, ...defaultProps, ...overrides, }; - const wrapper = shallow(); - const component = wrapper.shallow(); - return { wrapper, component, onChange }; + render(, { useDnd: true }); + return { onChange }; } -const valueColumn = { type: 'DOUBLE', column_name: 'value' }; +const valueColumn = { type: 'double', column_name: 'value' }; const sumValueAdhocMetric = new AdhocMetric({ + expressionType: EXPRESSION_TYPES.SIMPLE, column: valueColumn, aggregate: AGGREGATES.SUM, label: 'SUM(value)', }); -// TODO: rewrite the tests to RTL -describe.skip('MetricsControl', () => { - it('renders Select', () => { - const { component } = setup(); - expect(component.find(LabelsContainer)).toExist(); - }); +test('renders the LabelsContainer', () => { + setup(); + expect(screen.getByText('Metrics')).toBeInTheDocument(); +}); - describe('constructor', () => { - it('coerces Adhoc Metrics from form data into instances of the AdhocMetric class and leaves saved metrics', () => { - const { component } = setup({ - value: [ - { - expressionType: EXPRESSION_TYPES.SIMPLE, - column: { type: 'double', column_name: 'value' }, - aggregate: AGGREGATES.SUM, - label: 'SUM(value)', - optionName: 'blahblahblah', - }, - ], - }); - - const adhocMetric = component.state('value')[0]; - expect(adhocMetric instanceof AdhocMetric).toBe(true); - expect(adhocMetric.optionName.length).toBeGreaterThan(10); - expect(component.state('value')).toEqual([ - { - expressionType: EXPRESSION_TYPES.SIMPLE, - column: { type: 'double', column_name: 'value' }, - aggregate: AGGREGATES.SUM, - label: 'SUM(value)', - hasCustomLabel: false, - optionName: 'blahblahblah', - sqlExpression: null, - }, - ]); - }); +test('coerces Adhoc Metrics from form data into instances of the AdhocMetric class and leaves saved metrics', () => { + setup({ + value: [sumValueAdhocMetric], }); - describe('onChange', () => { - it('handles creating a new metric', () => { - const { component, onChange } = setup(); - component.instance().onNewMetric({ - metric_name: 'sum__value', - expression: 'SUM(energy_usage.value)', - }); - expect(onChange.lastCall.args).toEqual([['sum__value']]); - }); + const adhocMetric = screen.getByText('SUM(value)'); + expect(adhocMetric).toBeInTheDocument(); +}); + +test('handles creating a new metric', async () => { + const { onChange } = setup(); + + userEvent.click(screen.getByText(/add metric/i)); + await selectOption('sum__value', /select saved metrics/i); + userEvent.click(screen.getByRole('button', { name: /save/i })); + expect(onChange).toHaveBeenCalledWith(['sum__value']); +}); + +test('accepts an edited metric from an AdhocMetricEditPopover', async () => { + const { onChange } = setup({ + value: [sumValueAdhocMetric], }); - describe('onMetricEdit', () => { - it('accepts an edited metric from an AdhocMetricEditPopover', () => { - const { component, onChange } = setup({ - value: [sumValueAdhocMetric], - }); + const metricLabel = screen.getByText('SUM(value)'); + userEvent.click(metricLabel); - const editedMetric = sumValueAdhocMetric.duplicateWith({ - aggregate: AGGREGATES.AVG, - }); - component.instance().onMetricEdit(editedMetric, sumValueAdhocMetric); + await screen.findByText('aggregate'); + selectOption('AVG', /select aggregate options/i); - expect(onChange.lastCall.args).toEqual([[editedMetric]]); - }); + await screen.findByText('AVG(value)'); + + userEvent.click(screen.getByRole('button', { name: /save/i })); + + expect(onChange).toHaveBeenCalledWith([ + expect.objectContaining({ + aggregate: AGGREGATES.AVG, + label: 'AVG(value)', + }), + ]); +}); + +test('removes metrics if savedMetrics changes', async () => { + setup({ + value: [sumValueAdhocMetric], }); - describe('option filter', () => { - it('Removes metrics if savedMetrics changes', () => { - const { props, component, onChange } = setup({ - value: [ - { - expressionType: EXPRESSION_TYPES.SIMPLE, - column: { type: 'double', column_name: 'value' }, - aggregate: AGGREGATES.SUM, - label: 'SUM(value)', - optionName: 'blahblahblah', - }, - ], - }); - expect(component.state('value')).toHaveLength(1); - - component.setProps({ ...props, columns: [] }); - expect(onChange.lastCall.args).toEqual([[]]); - }); - - it('Does not remove custom sql metric if savedMetrics changes', () => { - const { props, component, onChange } = setup({ - value: [ - { - expressionType: EXPRESSION_TYPES.SQL, - sqlExpression: 'COUNT(*)', - label: 'old label', - hasCustomLabel: true, - }, - ], - }); - expect(component.state('value')).toHaveLength(1); - - component.setProps({ ...props, columns: [] }); - expect(onChange.calledOnce).toEqual(false); - }); - it('Does not fail if no columns or savedMetrics are passed', () => { - const { component } = setup({ - savedMetrics: null, - columns: null, - }); - expect(component.exists('.metrics-select')).toEqual(true); - }); + expect(screen.getByText('SUM(value)')).toBeInTheDocument(); + userEvent.click(screen.getByText('SUM(value)')); + + const savedTab = screen.getByRole('tab', { name: /saved/i }); + userEvent.click(savedTab); + await selectOption('avg__value', /select saved metrics/i); + + const simpleTab = screen.getByRole('tab', { name: /simple/i }); + userEvent.click(simpleTab); + await screen.findByText('aggregate'); + + expect(screen.queryByText('SUM')).not.toBeInTheDocument(); + expect(screen.queryByText('value')).not.toBeInTheDocument(); +}); + +test('does not remove custom SQL metric if savedMetrics changes', async () => { + const { rerender } = render( + , + { useDnd: true }, + ); + + expect(screen.getByText('old label')).toBeInTheDocument(); + + // Simulate removing columns + rerender( + , + ); + + expect(screen.getByText('old label')).toBeInTheDocument(); +}); + +test('does not fail if no columns or savedMetrics are passed', () => { + setup({ + savedMetrics: null, + columns: null, }); + expect(screen.getByText(/add metric/i)).toBeInTheDocument(); });