diff --git a/superset-frontend/src/components/Pagination/Ellipsis.test.tsx b/superset-frontend/src/components/Pagination/Ellipsis.test.tsx
new file mode 100644
index 000000000..430924e1b
--- /dev/null
+++ b/superset-frontend/src/components/Pagination/Ellipsis.test.tsx
@@ -0,0 +1,39 @@
+/**
+ * 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 userEvent from '@testing-library/user-event';
+import { Ellipsis } from './Ellipsis';
+
+test('Ellipsis - click when the button is enabled', () => {
+ const click = jest.fn();
+ render();
+ expect(click).toBeCalledTimes(0);
+ userEvent.click(screen.getByRole('button'));
+ expect(click).toBeCalledTimes(1);
+});
+
+test('Ellipsis - click when the button is disabled', () => {
+ const click = jest.fn();
+ render();
+ expect(click).toBeCalledTimes(0);
+ userEvent.click(screen.getByRole('button'));
+ expect(click).toBeCalledTimes(0);
+});
diff --git a/superset-frontend/src/components/Pagination/Ellipsis.tsx b/superset-frontend/src/components/Pagination/Ellipsis.tsx
new file mode 100644
index 000000000..59267025f
--- /dev/null
+++ b/superset-frontend/src/components/Pagination/Ellipsis.tsx
@@ -0,0 +1,39 @@
+/**
+ * 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 classNames from 'classnames';
+import { PaginationButtonProps } from './types';
+
+export function Ellipsis({ disabled, onClick }: PaginationButtonProps) {
+ return (
+
+ {
+ e.preventDefault();
+ if (!disabled) onClick(e);
+ }}
+ >
+ …
+
+
+ );
+}
diff --git a/superset-frontend/src/components/Pagination/Item.test.tsx b/superset-frontend/src/components/Pagination/Item.test.tsx
new file mode 100644
index 000000000..a94227671
--- /dev/null
+++ b/superset-frontend/src/components/Pagination/Item.test.tsx
@@ -0,0 +1,49 @@
+/**
+ * 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 userEvent from '@testing-library/user-event';
+import { Item } from './Item';
+
+test('Item - click when the item is not active', () => {
+ const click = jest.fn();
+ render(
+ -
+
+
,
+ );
+ expect(click).toBeCalledTimes(0);
+ userEvent.click(screen.getByRole('button'));
+ expect(click).toBeCalledTimes(1);
+ expect(screen.getByTestId('test')).toBeInTheDocument();
+});
+
+test('Item - click when the item is active', () => {
+ const click = jest.fn();
+ render(
+ -
+
+
,
+ );
+ expect(click).toBeCalledTimes(0);
+ userEvent.click(screen.getByRole('button'));
+ expect(click).toBeCalledTimes(0);
+ expect(screen.getByTestId('test')).toBeInTheDocument();
+});
diff --git a/superset-frontend/src/components/Pagination/Item.tsx b/superset-frontend/src/components/Pagination/Item.tsx
new file mode 100644
index 000000000..78c5abcd2
--- /dev/null
+++ b/superset-frontend/src/components/Pagination/Item.tsx
@@ -0,0 +1,44 @@
+/**
+ * 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 classNames from 'classnames';
+import { PaginationButtonProps } from './types';
+
+interface PaginationItemButton extends PaginationButtonProps {
+ active?: boolean;
+ children: React.ReactNode;
+}
+
+export function Item({ active, children, onClick }: PaginationItemButton) {
+ return (
+
+ {
+ e.preventDefault();
+ if (!active) onClick(e);
+ }}
+ >
+ {children}
+
+
+ );
+}
diff --git a/superset-frontend/src/components/Pagination/Next.test.tsx b/superset-frontend/src/components/Pagination/Next.test.tsx
new file mode 100644
index 000000000..9daddec0d
--- /dev/null
+++ b/superset-frontend/src/components/Pagination/Next.test.tsx
@@ -0,0 +1,39 @@
+/**
+ * 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 userEvent from '@testing-library/user-event';
+import { Next } from './Next';
+
+test('Next - click when the button is enabled', () => {
+ const click = jest.fn();
+ render();
+ expect(click).toBeCalledTimes(0);
+ userEvent.click(screen.getByRole('button'));
+ expect(click).toBeCalledTimes(1);
+});
+
+test('Next - click when the button is disabled', () => {
+ const click = jest.fn();
+ render();
+ expect(click).toBeCalledTimes(0);
+ userEvent.click(screen.getByRole('button'));
+ expect(click).toBeCalledTimes(0);
+});
diff --git a/superset-frontend/src/components/Pagination/Next.tsx b/superset-frontend/src/components/Pagination/Next.tsx
new file mode 100644
index 000000000..838f38aa3
--- /dev/null
+++ b/superset-frontend/src/components/Pagination/Next.tsx
@@ -0,0 +1,39 @@
+/**
+ * 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 classNames from 'classnames';
+import { PaginationButtonProps } from './types';
+
+export function Next({ disabled, onClick }: PaginationButtonProps) {
+ return (
+
+ {
+ e.preventDefault();
+ if (!disabled) onClick(e);
+ }}
+ >
+ »
+
+
+ );
+}
diff --git a/superset-frontend/src/components/Pagination/Pagination.test.tsx b/superset-frontend/src/components/Pagination/Pagination.test.tsx
new file mode 100644
index 000000000..192d4de3f
--- /dev/null
+++ b/superset-frontend/src/components/Pagination/Pagination.test.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 { render, screen } from 'spec/helpers/testing-library';
+import Pagination from '.';
+
+jest.mock('./Next', () => ({
+ Next: () => ,
+}));
+jest.mock('./Prev', () => ({
+ Prev: () => ,
+}));
+jest.mock('./Item', () => ({
+ Item: () => ,
+}));
+jest.mock('./Ellipsis', () => ({
+ Ellipsis: () => ,
+}));
+
+test('Pagination rendering correctly', () => {
+ render(
+
+
+ ,
+ );
+ expect(screen.getByRole('navigation')).toBeInTheDocument();
+ expect(screen.getByTestId('test')).toBeInTheDocument();
+});
+
+test('Next attribute', () => {
+ render();
+ expect(screen.getByTestId('next')).toBeInTheDocument();
+});
+
+test('Prev attribute', () => {
+ render();
+ expect(screen.getByTestId('next')).toBeInTheDocument();
+});
+
+test('Item attribute', () => {
+ render(
+
+ <>>
+ ,
+ );
+ expect(screen.getByTestId('item')).toBeInTheDocument();
+});
+
+test('Ellipsis attribute', () => {
+ render();
+ expect(screen.getByTestId('ellipsis')).toBeInTheDocument();
+});
diff --git a/superset-frontend/src/components/Pagination/Prev.test.tsx b/superset-frontend/src/components/Pagination/Prev.test.tsx
new file mode 100644
index 000000000..924a9e997
--- /dev/null
+++ b/superset-frontend/src/components/Pagination/Prev.test.tsx
@@ -0,0 +1,39 @@
+/**
+ * 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 userEvent from '@testing-library/user-event';
+import { Prev } from './Prev';
+
+test('Prev - click when the button is enabled', () => {
+ const click = jest.fn();
+ render();
+ expect(click).toBeCalledTimes(0);
+ userEvent.click(screen.getByRole('button'));
+ expect(click).toBeCalledTimes(1);
+});
+
+test('Prev - click when the button is disabled', () => {
+ const click = jest.fn();
+ render();
+ expect(click).toBeCalledTimes(0);
+ userEvent.click(screen.getByRole('button'));
+ expect(click).toBeCalledTimes(0);
+});
diff --git a/superset-frontend/src/components/Pagination/Prev.tsx b/superset-frontend/src/components/Pagination/Prev.tsx
new file mode 100644
index 000000000..678b49323
--- /dev/null
+++ b/superset-frontend/src/components/Pagination/Prev.tsx
@@ -0,0 +1,39 @@
+/**
+ * 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 classNames from 'classnames';
+import { PaginationButtonProps } from './types';
+
+export function Prev({ disabled, onClick }: PaginationButtonProps) {
+ return (
+
+ {
+ e.preventDefault();
+ if (!disabled) onClick(e);
+ }}
+ >
+ «
+
+
+ );
+}
diff --git a/superset-frontend/src/components/Pagination.tsx b/superset-frontend/src/components/Pagination/index.tsx
similarity index 55%
rename from superset-frontend/src/components/Pagination.tsx
rename to superset-frontend/src/components/Pagination/index.tsx
index 6a9a7466c..cff503da0 100644
--- a/superset-frontend/src/components/Pagination.tsx
+++ b/superset-frontend/src/components/Pagination/index.tsx
@@ -16,62 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React, { PureComponent } from 'react';
-import cx from 'classnames';
+
+import React from 'react';
import { styled } from '@superset-ui/core';
-
-interface PaginationButton {
- disabled?: boolean;
- onClick: React.EventHandler>;
-}
-
-interface PaginationItemButton extends PaginationButton {
- active: boolean;
- children: React.ReactNode;
-}
-
-function Prev({ disabled, onClick }: PaginationButton) {
- return (
-
-
- «
-
-
- );
-}
-
-function Next({ disabled, onClick }: PaginationButton) {
- return (
-
-
- »
-
-
- );
-}
-
-function Item({ active, children, onClick }: PaginationItemButton) {
- return (
-
-
- {children}
-
-
- );
-}
-
-function Ellipsis({ disabled, onClick }: PaginationButton) {
- return (
-
-
- …
-
-
- );
-}
+import { Next } from './Next';
+import { Prev } from './Prev';
+import { Item } from './Item';
+import { Ellipsis } from './Ellipsis';
interface PaginationProps {
- children: React.ReactNode;
+ children: JSX.Element | JSX.Element[];
}
const PaginationList = styled.ul`
@@ -122,16 +76,13 @@ const PaginationList = styled.ul`
}
`;
-export default class Pagination extends PureComponent {
- static Next = Next;
-
- static Prev = Prev;
-
- static Item = Item;
-
- static Ellipsis = Ellipsis;
-
- render() {
- return {this.props.children};
- }
+function Pagination({ children }: PaginationProps) {
+ return {children};
}
+
+Pagination.Next = Next;
+Pagination.Prev = Prev;
+Pagination.Item = Item;
+Pagination.Ellipsis = Ellipsis;
+
+export default Pagination;
diff --git a/superset-frontend/src/components/Pagination/types.ts b/superset-frontend/src/components/Pagination/types.ts
new file mode 100644
index 000000000..fb9c97ba0
--- /dev/null
+++ b/superset-frontend/src/components/Pagination/types.ts
@@ -0,0 +1,23 @@
+/**
+ * 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.
+ */
+
+export interface PaginationButtonProps {
+ disabled?: boolean;
+ onClick: React.EventHandler>;
+}