chore: Upgrade Webpack to v5 (#16701)

* Upgrade Webpack to v5

* Remove mapbox hack

* Replace url-loaders and file-loaders with asset modules

* Remove 1 rule

* Change --colors to --color

* Remove invalid option (--no-progress)

* Remove url-loader, bump plugin

* Fix AnnotationLayer formula check

* Remove redundant tests

* Bump cypress packages

* Remove old comment

* Fix tests

* Remove checks for number of scripts in markdown test

* Cosmetic changes

* Add tests

* Fix test

* Fix test

* Fixes test warnings

* disable flaky test

Co-authored-by: Ville Brofeldt <ville.v.brofeldt@gmail.com>
Co-authored-by: Michael S. Molina <michael.s.molina@gmail.com>
This commit is contained in:
Kamil Gabryjelski
2021-09-22 13:24:54 +02:00
committed by GitHub
parent 9b17e86b44
commit 486e0d412c
16 changed files with 9046 additions and 29792 deletions

View File

@@ -20,7 +20,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { CompactPicker } from 'react-color';
import Button from 'src/components/Button';
import { parse as mathjsParse } from 'mathjs';
import mexp from 'math-expression-evaluator';
import {
t,
SupersetClient,
@@ -204,15 +204,30 @@ export default class AnnotationLayer extends React.PureComponent {
return sources;
}
isValidFormula(value, annotationType) {
isValidFormula(expression, annotationType) {
if (annotationType === ANNOTATION_TYPES.FORMULA) {
try {
mathjsParse(value).compile().evaluate({ x: 0 });
const token = {
type: 3,
token: 'x',
show: 'x',
value: 'x',
};
// handle input like "y = x+1" instead of just "x+1"
const subexpressions = expression.split('=');
if (
subexpressions.length > 2 ||
(subexpressions[1] && !subexpressions[0].match(/^\s*[a-zA-Z]\w*\s*$/))
) {
return false;
}
mexp.eval(subexpressions[1] ?? subexpressions[0], [token], { x: 0 });
} catch (err) {
return true;
return false;
}
}
return false;
return true;
}
isValidForm() {
@@ -238,7 +253,7 @@ export default class AnnotationLayer extends React.PureComponent {
errors.push(validateNonEmpty(intervalEndColumn));
}
}
errors.push(this.isValidFormula(value, annotationType));
errors.push(!this.isValidFormula(value, annotationType));
return !errors.filter(x => x).length;
}
@@ -442,7 +457,7 @@ export default class AnnotationLayer extends React.PureComponent {
value={value}
onChange={this.handleValue}
validationErrors={
this.isValidFormula(value, annotationType) ? ['Bad formula.'] : []
!this.isValidFormula(value, annotationType) ? ['Bad formula.'] : []
}
/>
);

View File

@@ -57,16 +57,18 @@ beforeAll(() => {
);
});
test('renders with default props', () => {
const { container } = render(<AnnotationLayer {...defaultProps} />);
expect(container).toBeInTheDocument();
const waitForRender = (props?: any) =>
waitFor(() => render(<AnnotationLayer {...defaultProps} {...props} />));
test('renders with default props', async () => {
await waitForRender();
expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled();
expect(screen.getByRole('button', { name: 'OK' })).toBeDisabled();
expect(screen.getByRole('button', { name: 'Cancel' })).toBeEnabled();
});
test('renders extra checkboxes when type is time series', () => {
render(<AnnotationLayer {...defaultProps} />);
test('renders extra checkboxes when type is time series', async () => {
await waitForRender();
expect(
screen.queryByRole('button', { name: 'Show Markers' }),
).not.toBeInTheDocument();
@@ -82,7 +84,7 @@ test('renders extra checkboxes when type is time series', () => {
});
test('enables apply and ok buttons', async () => {
render(<AnnotationLayer {...defaultProps} />);
await waitForRender();
userEvent.type(screen.getByLabelText('Name'), 'Test');
userEvent.type(screen.getByLabelText('Formula'), '2x');
await waitFor(() => {
@@ -91,68 +93,47 @@ test('enables apply and ok buttons', async () => {
});
});
test('triggers addAnnotationLayer when apply button is clicked', () => {
test('triggers addAnnotationLayer when apply button is clicked', async () => {
const addAnnotationLayer = jest.fn();
render(
<AnnotationLayer
{...defaultProps}
name="Test"
value="2x"
addAnnotationLayer={addAnnotationLayer}
/>,
);
await waitForRender({ name: 'Test', value: '2x', addAnnotationLayer });
userEvent.click(screen.getByRole('button', { name: 'Apply' }));
expect(addAnnotationLayer).toHaveBeenCalled();
});
test('triggers addAnnotationLayer and close when ok button is clicked', () => {
test('triggers addAnnotationLayer and close when ok button is clicked', async () => {
const addAnnotationLayer = jest.fn();
const close = jest.fn();
render(
<AnnotationLayer
{...defaultProps}
name="Test"
value="2x"
addAnnotationLayer={addAnnotationLayer}
close={close}
/>,
);
await waitForRender({ name: 'Test', value: '2x', addAnnotationLayer, close });
userEvent.click(screen.getByRole('button', { name: 'OK' }));
expect(addAnnotationLayer).toHaveBeenCalled();
expect(close).toHaveBeenCalled();
});
test('triggers close when cancel button is clicked', () => {
test('triggers close when cancel button is clicked', async () => {
const close = jest.fn();
render(<AnnotationLayer {...defaultProps} close={close} />);
await waitForRender({ close });
userEvent.click(screen.getByRole('button', { name: 'Cancel' }));
expect(close).toHaveBeenCalled();
});
test('triggers removeAnnotationLayer and close when remove button is clicked', () => {
test('triggers removeAnnotationLayer and close when remove button is clicked', async () => {
const removeAnnotationLayer = jest.fn();
const close = jest.fn();
render(
<AnnotationLayer
{...defaultProps}
name="Test"
value="2x"
removeAnnotationLayer={removeAnnotationLayer}
close={close}
/>,
);
await waitForRender({
name: 'Test',
value: '2x',
removeAnnotationLayer,
close,
});
userEvent.click(screen.getByRole('button', { name: 'Remove' }));
expect(removeAnnotationLayer).toHaveBeenCalled();
expect(close).toHaveBeenCalled();
});
test('renders chart options', async () => {
render(
<AnnotationLayer
{...defaultProps}
annotationType={ANNOTATION_TYPES_METADATA.EVENT.value}
/>,
);
await waitForRender({
annotationType: ANNOTATION_TYPES_METADATA.EVENT.value,
});
userEvent.click(screen.getByText('2 option(s)'));
userEvent.click(screen.getByText('Superset annotation'));
expect(await screen.findByLabelText('Annotation layer')).toBeInTheDocument();
@@ -162,15 +143,12 @@ test('renders chart options', async () => {
});
test('keeps apply disabled when missing required fields', async () => {
render(
<AnnotationLayer
{...defaultProps}
annotationType={ANNOTATION_TYPES_METADATA.EVENT.value}
sourceType="Table"
/>,
);
userEvent.click(await screen.findByText('1 option(s)'));
userEvent.click(screen.getByText('Chart A'));
await waitForRender({
annotationType: ANNOTATION_TYPES_METADATA.EVENT.value,
sourceType: 'Table',
});
userEvent.click(screen.getByText('1 option(s)'));
await waitFor(() => userEvent.click(screen.getByText('Chart A')));
expect(
screen.getByText('Annotation Slice Configuration'),
).toBeInTheDocument();
@@ -188,3 +166,48 @@ test('keeps apply disabled when missing required fields', async () => {
expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled();
});
test.skip('Disable apply button if formula is incorrect', async () => {
// TODO: fix flaky test that passes locally but fails on CI
await waitForRender({ name: 'test' });
userEvent.clear(screen.getByLabelText('Formula'));
userEvent.type(screen.getByLabelText('Formula'), 'x+1');
await waitFor(() => {
expect(screen.getByLabelText('Formula')).toHaveValue('x+1');
expect(screen.getByRole('button', { name: 'OK' })).toBeEnabled();
expect(screen.getByRole('button', { name: 'Apply' })).toBeEnabled();
});
userEvent.clear(screen.getByLabelText('Formula'));
userEvent.type(screen.getByLabelText('Formula'), 'y = x*2+1');
await waitFor(() => {
expect(screen.getByLabelText('Formula')).toHaveValue('y = x*2+1');
expect(screen.getByRole('button', { name: 'OK' })).toBeEnabled();
expect(screen.getByRole('button', { name: 'Apply' })).toBeEnabled();
});
userEvent.clear(screen.getByLabelText('Formula'));
userEvent.type(screen.getByLabelText('Formula'), 'y+1');
await waitFor(() => {
expect(screen.getByLabelText('Formula')).toHaveValue('y+1');
expect(screen.getByRole('button', { name: 'OK' })).toBeDisabled();
expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled();
});
userEvent.clear(screen.getByLabelText('Formula'));
userEvent.type(screen.getByLabelText('Formula'), 'x+');
await waitFor(() => {
expect(screen.getByLabelText('Formula')).toHaveValue('x+');
expect(screen.getByRole('button', { name: 'OK' })).toBeDisabled();
expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled();
});
userEvent.clear(screen.getByLabelText('Formula'));
userEvent.type(screen.getByLabelText('Formula'), 'y = z+1');
await waitFor(() => {
expect(screen.getByLabelText('Formula')).toHaveValue('y = z+1');
expect(screen.getByRole('button', { name: 'OK' })).toBeDisabled();
expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled();
});
});