diff --git a/superset-frontend/.storybook/preview.jsx b/superset-frontend/.storybook/preview.jsx index e20ff6c5e237..94fcfd71858a 100644 --- a/superset-frontend/.storybook/preview.jsx +++ b/superset-frontend/.storybook/preview.jsx @@ -21,18 +21,34 @@ import { addDecorator } from '@storybook/react'; import { jsxDecorator } from 'storybook-addon-jsx'; import { addParameters } from '@storybook/react'; import { withPaddings } from 'storybook-addon-paddings'; - import { supersetTheme, ThemeProvider } from '@superset-ui/core'; +import { combineReducers, createStore, applyMiddleware, compose } from 'redux'; +import thunk from 'redux-thunk'; +import { Provider } from 'react-redux'; +import reducerIndex from 'spec/helpers/reducerIndex'; -import '../src/theme.ts'; +import 'src/theme.ts'; import './storybook.css'; +const store = createStore( + combineReducers(reducerIndex), + {}, + compose(applyMiddleware(thunk)), +); + const themeDecorator = Story => ( {} ); +const providerDecorator = Story => ( + + + +); + addDecorator(jsxDecorator); addDecorator(themeDecorator); +addDecorator(providerDecorator); addDecorator(withPaddings); addParameters({ diff --git a/superset-frontend/spec/javascripts/components/CopyToClipboard_spec.jsx b/superset-frontend/spec/javascripts/components/CopyToClipboard_spec.jsx deleted file mode 100644 index 9f27ac6c7635..000000000000 --- a/superset-frontend/spec/javascripts/components/CopyToClipboard_spec.jsx +++ /dev/null @@ -1,33 +0,0 @@ -/** - * 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 React from 'react'; - -import CopyToClipboard from 'src/components/CopyToClipboard'; - -describe('CopyToClipboard', () => { - const defaultProps = { - text: 'some text to copy', - }; - - it('renders', () => { - expect(React.isValidElement()).toBe( - true, - ); - }); -}); diff --git a/superset-frontend/src/common/components/Collapse/Collapse.stories.tsx b/superset-frontend/src/common/components/Collapse/Collapse.stories.tsx index f6636a81ccf0..169d3bc45ae4 100644 --- a/superset-frontend/src/common/components/Collapse/Collapse.stories.tsx +++ b/superset-frontend/src/common/components/Collapse/Collapse.stories.tsx @@ -62,10 +62,10 @@ InteractiveCollapse.argTypes = { InteractiveCollapse.story = { parameters: { actions: { - disabled: true, + disable: true, }, knobs: { - disabled: true, + disable: true, }, }, }; diff --git a/superset-frontend/src/common/components/Tooltip/Tooltip.stories.tsx b/superset-frontend/src/common/components/Tooltip/Tooltip.stories.tsx index f1040d71d2bb..f4c1302da494 100644 --- a/superset-frontend/src/common/components/Tooltip/Tooltip.stories.tsx +++ b/superset-frontend/src/common/components/Tooltip/Tooltip.stories.tsx @@ -52,7 +52,7 @@ export const InteractiveTooltip = (args: TooltipProps) => ( InteractiveTooltip.story = { parameters: { knobs: { - disabled: true, + disable: true, }, }, }; diff --git a/superset-frontend/src/components/Alert/Alert.stories.tsx b/superset-frontend/src/components/Alert/Alert.stories.tsx index 4b4f86ea3db5..da02aae7ccbb 100644 --- a/superset-frontend/src/components/Alert/Alert.stories.tsx +++ b/superset-frontend/src/components/Alert/Alert.stories.tsx @@ -63,13 +63,13 @@ export const AlertGallery = () => ( AlertGallery.story = { parameters: { actions: { - disabled: true, + disable: true, }, controls: { - disabled: true, + disable: true, }, knobs: { - disabled: true, + disable: true, }, }, }; @@ -94,7 +94,7 @@ InteractiveAlert.argTypes = { InteractiveAlert.story = { parameters: { knobs: { - disabled: true, + disable: true, }, }, }; diff --git a/superset-frontend/src/components/AsyncAceEditor/AsyncAceEditor.stories.tsx b/superset-frontend/src/components/AsyncAceEditor/AsyncAceEditor.stories.tsx index 6587121fa947..6269ba9224f5 100644 --- a/superset-frontend/src/components/AsyncAceEditor/AsyncAceEditor.stories.tsx +++ b/superset-frontend/src/components/AsyncAceEditor/AsyncAceEditor.stories.tsx @@ -81,7 +81,7 @@ export const AsyncAceEditor = ( AsyncAceEditor.args = { defaultTabSize: 2, width: '100%', - height: 500, + height: '500px', value: `{"text": "Simple text"}`, }; @@ -99,10 +99,10 @@ AsyncAceEditor.argTypes = { AsyncAceEditor.story = { parameters: { actions: { - disabled: true, + disable: true, }, knobs: { - disabled: true, + disable: true, }, }, }; diff --git a/superset-frontend/src/components/Button/Button.stories.tsx b/superset-frontend/src/components/Button/Button.stories.tsx index b5a683b36fa2..9a1853ce0fce 100644 --- a/superset-frontend/src/components/Button/Button.stories.tsx +++ b/superset-frontend/src/components/Button/Button.stories.tsx @@ -98,13 +98,13 @@ export const ButtonGallery = () => ( ButtonGallery.story = { parameters: { actions: { - disabled: true, + disable: true, }, controls: { - disabled: true, + disable: true, }, knobs: { - disabled: true, + disable: true, }, }, }; @@ -117,7 +117,7 @@ export const InteractiveButton = (args: ButtonProps & { label: string }) => { InteractiveButton.story = { parameters: { knobs: { - disabled: true, + disable: true, }, }, }; diff --git a/superset-frontend/src/components/ButtonGroup/ButtonGroup.stories.tsx b/superset-frontend/src/components/ButtonGroup/ButtonGroup.stories.tsx index 8c878644a769..e5b0b94cbcfc 100644 --- a/superset-frontend/src/components/ButtonGroup/ButtonGroup.stories.tsx +++ b/superset-frontend/src/components/ButtonGroup/ButtonGroup.stories.tsx @@ -61,10 +61,10 @@ InteractiveButtonGroup.argTypes = { InteractiveButtonGroup.story = { parameters: { actions: { - disabled: true, + disable: true, }, knobs: { - disabled: true, + disable: true, }, }, }; diff --git a/superset-frontend/src/components/CopyToClipboard/CopyToClipboard.stories.tsx b/superset-frontend/src/components/CopyToClipboard/CopyToClipboard.stories.tsx new file mode 100644 index 000000000000..e932b4593859 --- /dev/null +++ b/superset-frontend/src/components/CopyToClipboard/CopyToClipboard.stories.tsx @@ -0,0 +1,66 @@ +/** + * 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 React from 'react'; +import Button from 'src/components/Button'; +import Icon from 'src/components/Icon'; +import ToastPresenter from 'src/messageToasts/containers/ToastPresenter'; +import CopyToClipboard from '.'; + +export default { + title: 'CopyToClipboard', + component: CopyToClipboard, +}; + +export const InteractiveCopyToClipboard = ({ copyNode, ...rest }: any) => { + let node = ; + if (copyNode === 'Icon') { + node = ; + } else if (copyNode === 'Text') { + node = Copy; + } + return ( + <> + + + + ); +}; + +InteractiveCopyToClipboard.args = { + shouldShowText: true, + text: 'http://superset.apache.org/', + wrapped: true, + tooltipText: 'Copy to clipboard', +}; + +InteractiveCopyToClipboard.argTypes = { + onCopyEnd: { action: 'onCopyEnd' }, + copyNode: { + defaultValue: 'Button', + control: { type: 'radio', options: ['Button', 'Icon', 'Text'] }, + }, +}; + +InteractiveCopyToClipboard.story = { + parameters: { + knobs: { + disable: true, + }, + }, +}; diff --git a/superset-frontend/src/components/CopyToClipboard/CopyToClipboard.test.tsx b/superset-frontend/src/components/CopyToClipboard/CopyToClipboard.test.tsx new file mode 100644 index 000000000000..81103a8a080e --- /dev/null +++ b/superset-frontend/src/components/CopyToClipboard/CopyToClipboard.test.tsx @@ -0,0 +1,76 @@ +/** + * 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 React from 'react'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import CopyToClipboard from '.'; + +test('renders with default props', () => { + const text = 'Text'; + render(, { useRedux: true }); + expect(screen.getByText(text)).toBeInTheDocument(); + expect(screen.getByText('Copy')).toBeInTheDocument(); +}); + +test('renders with custom copy node', () => { + const copyNode = Custom node; + render(, { useRedux: true }); + expect(screen.getByRole('link')).toBeInTheDocument(); +}); + +test('renders without text showing', () => { + const text = 'Text'; + render(, { + useRedux: true, + }); + expect(screen.queryByText(text)).not.toBeInTheDocument(); +}); + +test('getText on copy', async () => { + const getText = jest.fn(() => 'Text'); + render(, { useRedux: true }); + userEvent.click(screen.getByText('Copy')); + await waitFor(() => expect(getText).toHaveBeenCalled()); +}); + +test('renders tooltip on hover', async () => { + const tooltipText = 'Tooltip'; + render(, { useRedux: true }); + userEvent.hover(screen.getByText('Copy')); + const tooltip = await screen.findByRole('tooltip'); + expect(tooltip).toBeInTheDocument(); + expect(tooltip).toHaveTextContent(tooltipText); +}); + +test('triggers onCopyEnd', async () => { + const onCopyEnd = jest.fn(); + render(, { + useRedux: true, + }); + userEvent.click(screen.getByText('Copy')); + await waitFor(() => expect(onCopyEnd).toHaveBeenCalled()); +}); + +test('renders unwrapped', () => { + const text = 'Text'; + render(, { + useRedux: true, + }); + expect(screen.queryByText(text)).not.toBeInTheDocument(); +}); diff --git a/superset-frontend/src/components/CopyToClipboard.jsx b/superset-frontend/src/components/CopyToClipboard/index.jsx similarity index 98% rename from superset-frontend/src/components/CopyToClipboard.jsx rename to superset-frontend/src/components/CopyToClipboard/index.jsx index bded61fd69f5..bff6116857a3 100644 --- a/superset-frontend/src/components/CopyToClipboard.jsx +++ b/superset-frontend/src/components/CopyToClipboard/index.jsx @@ -102,7 +102,7 @@ class CopyToClipboard extends React.Component { renderLink() { return ( - + {this.props.shouldShowText && this.props.text && ( {this.props.text} diff --git a/superset-frontend/src/components/Loading/Loading.stories.tsx b/superset-frontend/src/components/Loading/Loading.stories.tsx index b0d8bf11f0ec..60ef378fc1e4 100644 --- a/superset-frontend/src/components/Loading/Loading.stories.tsx +++ b/superset-frontend/src/components/Loading/Loading.stories.tsx @@ -49,13 +49,13 @@ export const LoadingGallery = () => ( LoadingGallery.story = { parameters: { actions: { - disabled: true, + disable: true, }, controls: { - disabled: true, + disable: true, }, knobs: { - disabled: true, + disable: true, }, }, }; @@ -65,7 +65,7 @@ export const InteractiveLoading = (args: Props) => ; InteractiveLoading.story = { parameters: { knobs: { - disabled: true, + disable: true, }, }, };