You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by di...@apache.org on 2022/10/07 15:03:14 UTC
[superset] branch feat/d2d-charts-crud-filter-col updated: Add tests
This is an automated email from the ASF dual-hosted git repository.
diegopucci pushed a commit to branch feat/d2d-charts-crud-filter-col
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/feat/d2d-charts-crud-filter-col by this push:
new 723011d295 Add tests
723011d295 is described below
commit 723011d295af4c2b91bcd5f33af4d91659a90b96
Author: geido <di...@gmail.com>
AuthorDate: Fri Oct 7 18:02:52 2022 +0300
Add tests
---
.../src/components/ListView/CrossLinks.test.tsx | 97 +++++++++++++++++++++
.../src/components/ListView/CrossLinks.tsx | 98 ++++++++++------------
.../components/ListView/CrossLinksTooltip.test.tsx | 88 +++++++++++++++++++
.../src/components/ListView/CrossLinksTooltip.tsx | 69 +++++++++++++++
superset-frontend/src/hooks/useTruncation/index.ts | 1 -
.../src/views/CRUD/chart/ChartList.tsx | 11 ++-
6 files changed, 303 insertions(+), 61 deletions(-)
diff --git a/superset-frontend/src/components/ListView/CrossLinks.test.tsx b/superset-frontend/src/components/ListView/CrossLinks.test.tsx
new file mode 100644
index 0000000000..e50b32fe35
--- /dev/null
+++ b/superset-frontend/src/components/ListView/CrossLinks.test.tsx
@@ -0,0 +1,97 @@
+/**
+ * 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 } from 'spec/helpers/testing-library';
+import CrossLinks, { CrossLinksProps } from './CrossLinks';
+
+const mockedProps = {
+ crossLinks: [
+ {
+ id: 1,
+ title: 'Test dashboard',
+ },
+ {
+ id: 2,
+ title: 'Test dashboard 2',
+ },
+ {
+ id: 3,
+ title: 'Test dashboard 3',
+ },
+ {
+ id: 4,
+ title: 'Test dashboard 4',
+ },
+ ],
+};
+
+function setup(overrideProps: CrossLinksProps | {} = {}) {
+ return render(<CrossLinks {...{ ...mockedProps, ...overrideProps }} />, {
+ useRouter: true,
+ });
+}
+
+test('should render', () => {
+ const { container } = setup();
+ expect(container).toBeInTheDocument();
+});
+
+test('should not render links', () => {
+ setup({
+ crossLinks: [],
+ });
+ expect(screen.queryByRole('link')).not.toBeInTheDocument();
+});
+
+test('should render the link with just one item', () => {
+ setup({
+ crossLinks: [
+ {
+ id: 1,
+ title: 'Test dashboard',
+ },
+ ],
+ });
+ expect(screen.getByText('Test dashboard')).toBeInTheDocument();
+ expect(screen.getByRole('link')).toHaveAttribute(
+ 'href',
+ `/superset/dashboard/1`,
+ );
+});
+
+test('should render a custom prefix link', () => {
+ setup({
+ crossLinks: [
+ {
+ id: 1,
+ title: 'Test dashboard',
+ },
+ ],
+ linkPrefix: '/preset/dashboard/',
+ });
+ expect(screen.getByRole('link')).toHaveAttribute(
+ 'href',
+ `/preset/dashboard/1`,
+ );
+});
+
+test('should render multiple links', () => {
+ setup();
+ expect(screen.getAllByRole('link')).toHaveLength(4);
+});
diff --git a/superset-frontend/src/components/ListView/CrossLinks.tsx b/superset-frontend/src/components/ListView/CrossLinks.tsx
index 99bc83cb57..aa1796a6c7 100644
--- a/superset-frontend/src/components/ListView/CrossLinks.tsx
+++ b/superset-frontend/src/components/ListView/CrossLinks.tsx
@@ -16,31 +16,31 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React, { useRef } from 'react';
-import { styled, t } from '@superset-ui/core';
-import { Tooltip } from 'src/components/Tooltip';
+import React, { useMemo, useRef } from 'react';
+import { styled } from '@superset-ui/core';
import { Link } from 'react-router-dom';
import { useTruncation } from 'src/hooks/useTruncation';
+import CrossLinksTooltip from './CrossLinksTooltip';
export type CrossLinkProps = {
title: string;
id: number;
};
-interface CrossLinksProps {
+export type CrossLinksProps = {
crossLinks: Array<CrossLinkProps>;
maxLinks?: number;
linkPrefix?: string;
-}
+};
const StyledCrossLinks = styled.div`
${({ theme }) => `
- color: ${theme.colors.primary.dark1};
cursor: pointer;
- max-width: calc(100% - 20px);
+ position: relative;
+ display: flex;
.ant-tooltip-open {
- width: 100%;
+ display: inline;
}
.truncated {
@@ -59,14 +59,6 @@ const StyledCrossLinks = styled.div`
`}
`;
-const StyledLinkedTooltip = styled.div`
- .link {
- color: ${({ theme }) => theme.colors.grayscale.light5};
- display: block;
- text-decoration: underline;
- }
-`;
-
export default function CrossLinks({
crossLinks,
maxLinks = 50,
@@ -75,49 +67,43 @@ export default function CrossLinks({
const crossLinksRef = useRef<HTMLDivElement>(null);
const [elementsTruncated, hasHiddenElements] = useTruncation(crossLinksRef);
+ const links = useMemo(
+ () =>
+ crossLinks.map((link, index) => (
+ <Link
+ key={link.id}
+ to={linkPrefix + link.id}
+ target="_blank"
+ rel="noreferer noopener"
+ >
+ {index === 0 ? link.title : `, ${link.title}`}
+ </Link>
+ )),
+ [crossLinks],
+ );
+
return (
<StyledCrossLinks>
- {crossLinks.length > 1 ? (
- <Tooltip
- title={
- <StyledLinkedTooltip>
- {crossLinks.slice(0, maxLinks).map(link => (
- <Link
- className="link"
- key={link.id}
- to={linkPrefix + link.id}
- target="_blank"
- rel="noreferer noopener"
- >
- {link.title}
- </Link>
- ))}
- {crossLinks.length > maxLinks && (
- <span>{t('Plus %s more', crossLinks.length - maxLinks)}</span>
- )}
- </StyledLinkedTooltip>
- }
- >
- <span className="truncated" ref={crossLinksRef}>
- {crossLinks.map((element, index) => (
- <span>{index === 0 ? element.title : `, ${element.title}`}</span>
- ))}
- </span>
- {hasHiddenElements && (
- <span className="count">+{elementsTruncated}</span>
- )}
- </Tooltip>
- ) : (
- crossLinks[0] && (
- <Link
- to={linkPrefix + crossLinks[0].id}
- target="_blank"
- rel="noreferer noopener"
+ <span className="truncated" ref={crossLinksRef} data-test="crosslinks">
+ {elementsTruncated ? (
+ <CrossLinksTooltip
+ moreItems={
+ crossLinks.length > maxLinks
+ ? crossLinks.length - maxLinks
+ : undefined
+ }
+ crossLinks={crossLinks.slice(0, maxLinks).map(l => ({
+ title: l.title,
+ to: linkPrefix + l.id,
+ }))}
>
- {crossLinks[0].title}
- </Link>
- )
- )}
+ {links}
+ </CrossLinksTooltip>
+ ) : (
+ links
+ )}
+ </span>
+ {hasHiddenElements && <span className="count">+{elementsTruncated}</span>}
</StyledCrossLinks>
);
}
diff --git a/superset-frontend/src/components/ListView/CrossLinksTooltip.test.tsx b/superset-frontend/src/components/ListView/CrossLinksTooltip.test.tsx
new file mode 100644
index 0000000000..d0a21adf33
--- /dev/null
+++ b/superset-frontend/src/components/ListView/CrossLinksTooltip.test.tsx
@@ -0,0 +1,88 @@
+/**
+ * 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 userEvent from '@testing-library/user-event';
+import React from 'react';
+import { render, screen, waitFor } from 'spec/helpers/testing-library';
+import CrossLinksTooltip, { CrossLinksTooltipProps } from './CrossLinksTooltip';
+
+const mockedProps = {
+ crossLinks: [
+ {
+ to: 'somewhere/1',
+ title: 'Test dashboard',
+ },
+ {
+ to: 'somewhere/2',
+ title: 'Test dashboard 2',
+ },
+ {
+ to: 'somewhere/3',
+ title: 'Test dashboard 3',
+ },
+ {
+ to: 'somewhere/4',
+ title: 'Test dashboard 4',
+ },
+ ],
+ moreItems: 0,
+};
+
+function setup(overrideProps: CrossLinksTooltipProps | {} = {}) {
+ return render(
+ <CrossLinksTooltip {...{ ...mockedProps, ...overrideProps }}>
+ Hover me
+ </CrossLinksTooltip>,
+ {
+ useRouter: true,
+ },
+ );
+}
+
+test('should render', () => {
+ const { container } = setup();
+ expect(container).toBeInTheDocument();
+});
+
+test('should render multiple links', async () => {
+ setup();
+ userEvent.hover(screen.getByText('Hover me'));
+
+ await waitFor(() => {
+ expect(screen.getByText('Test dashboard')).toBeInTheDocument();
+ expect(screen.getByText('Test dashboard 2')).toBeInTheDocument();
+ expect(screen.getByText('Test dashboard 3')).toBeInTheDocument();
+ expect(screen.getByText('Test dashboard 4')).toBeInTheDocument();
+ expect(screen.getAllByRole('link')).toHaveLength(4);
+ });
+});
+
+test('should not render the "Plus {x} more"', () => {
+ setup();
+ userEvent.hover(screen.getByText('Hover me'));
+ expect(screen.queryByTestId('plus-more')).not.toBeInTheDocument();
+});
+
+test('should render the "Plus {x} more"', async () => {
+ setup({
+ moreItems: 3,
+ });
+ userEvent.hover(screen.getByText('Hover me'));
+ expect(await screen.findByTestId('plus-more')).toBeInTheDocument();
+ expect(await screen.findByText('Plus 3 more')).toBeInTheDocument();
+});
diff --git a/superset-frontend/src/components/ListView/CrossLinksTooltip.tsx b/superset-frontend/src/components/ListView/CrossLinksTooltip.tsx
new file mode 100644
index 0000000000..e6869c92e2
--- /dev/null
+++ b/superset-frontend/src/components/ListView/CrossLinksTooltip.tsx
@@ -0,0 +1,69 @@
+/**
+ * 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 { styled, t } from '@superset-ui/core';
+import { Tooltip } from 'src/components/Tooltip';
+import { Link } from 'react-router-dom';
+
+export type CrossLinksTooltipProps = {
+ children: React.ReactNode;
+ crossLinks: { to: string; title: string }[];
+ moreItems?: number;
+};
+
+const StyledLinkedTooltip = styled.div`
+ .link {
+ color: ${({ theme }) => theme.colors.grayscale.light5};
+ display: block;
+ text-decoration: underline;
+ }
+`;
+
+export default function CrossLinksTooltip({
+ children,
+ crossLinks = [],
+ moreItems = undefined,
+}: CrossLinksTooltipProps) {
+ return (
+ <Tooltip
+ placement="topLeft"
+ data-test="crosslinks-tooltip"
+ title={
+ <StyledLinkedTooltip>
+ {crossLinks.map(link => (
+ <Link
+ className="link"
+ key={link.to}
+ to={link.to}
+ target="_blank"
+ rel="noreferer noopener"
+ >
+ {link.title}
+ </Link>
+ ))}
+ {moreItems && (
+ <span data-test="plus-more">{t('Plus %s more', moreItems)}</span>
+ )}
+ </StyledLinkedTooltip>
+ }
+ >
+ {children}
+ </Tooltip>
+ );
+}
diff --git a/superset-frontend/src/hooks/useTruncation/index.ts b/superset-frontend/src/hooks/useTruncation/index.ts
index d000a6277a..311ad790fd 100644
--- a/superset-frontend/src/hooks/useTruncation/index.ts
+++ b/superset-frontend/src/hooks/useTruncation/index.ts
@@ -68,7 +68,6 @@ export const useTruncation = (elementRef: RefObject<HTMLElement>) => {
width += (childNodes[i] as HTMLElement).offsetWidth;
i += 1;
}
- console.log('i', i);
if (i === elementsCount) {
setElementsTruncated(1);
setHasHiddenElements(false);
diff --git a/superset-frontend/src/views/CRUD/chart/ChartList.tsx b/superset-frontend/src/views/CRUD/chart/ChartList.tsx
index 6376fa4bcb..621100f7fb 100644
--- a/superset-frontend/src/views/CRUD/chart/ChartList.tsx
+++ b/superset-frontend/src/views/CRUD/chart/ChartList.tsx
@@ -17,6 +17,7 @@
* under the License.
*/
import {
+ ensureIsArray,
getChartMetadataRegistry,
styled,
SupersetClient,
@@ -378,10 +379,12 @@ function ChartList(props: ChartListProps) {
},
}: any) => (
<CrossLinks
- crossLinks={dashboards.map((d: ChartLinkedDashboard) => ({
- title: d.dashboard_title,
- id: d.id,
- }))}
+ crossLinks={ensureIsArray(dashboards).map(
+ (d: ChartLinkedDashboard) => ({
+ title: d.dashboard_title,
+ id: d.id,
+ }),
+ )}
/>
),
Header: t('Dashboards added to'),