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'),