Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,22 +1,160 @@
import React from 'react';
import { render } from '@testing-library/react';
import React, { RefObject } from 'react';
import { fireEvent, render, screen } from '@testing-library/react';
import { BackToTop } from '../BackToTop';
import userEvent from '@testing-library/user-event';

describe('BackToTop', () => {
test('verify basic', () => {
const { asFragment } = render(<BackToTop />);
expect(asFragment()).toMatchSnapshot();
});
jest.mock('../../Button', () => ({
Button: ({ variant, iconPosition, children, icon }) => (
<>
<button>{children}</button>
<p>{variant}</p>
<p>{iconPosition}</p>
Comment on lines +10 to +11
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: can you update these to have some additional text which you include in your getByText query to ensure that we don't get false positive because of text elsewhere in the component?

Suggested change
<p>{variant}</p>
<p>{iconPosition}</p>
<p>Variant: {variant}</p>
<p>Icon position: {iconPosition}</p>

<div data-testid="icon">{icon}</div>
</>
)
}));

test('verify custom class', () => {
const { asFragment } = render(<BackToTop className="custom-css">test</BackToTop>);
test('Renders BackToTop', () => {
render(
<div data-testid="backtotop">
<BackToTop />
</div>
);

expect(asFragment()).toMatchSnapshot();
});
expect(screen.getByTestId('backtotop').firstChild).toBeTruthy();
});

test('Renders with the default class', () => {
render(<BackToTop />);

expect(screen.getByRole(`button`).parentElement).toHaveClass('pf-c-back-to-top');
});

test('BackToTop is not yet visible', () => {
render(<BackToTop />);

expect(screen.getByRole(`button`).parentElement).toHaveClass('pf-m-hidden');
});

test('BackToTop is visible after scrolling', () => {
render(<BackToTop />);

fireEvent.scroll(window, { target: { scrollY: 401 } });
expect(screen.getByRole(`button`).parentElement).not.toHaveClass('pf-m-hidden');
});

test('ScrollTo event is fired after clicking BackToTop', async () => {
render(<BackToTop />);
const user = userEvent.setup();
fireEvent.scroll(window, { target: { scrollY: 401 } });
global.scrollTo = jest.fn();

await user.click(screen.getByRole(`button`).parentElement as Element);
expect(global.scrollTo).toHaveBeenCalledWith({ top: 0, behavior: 'smooth' });
});

test('BackToTop gets hidden again after user scrolls back up', () => {
render(<BackToTop />);

fireEvent.scroll(window, { target: { scrollY: 401 } });

fireEvent.scroll(window, { target: { scrollY: 0 } });
expect(screen.getByRole(`button`).parentElement).toHaveClass('pf-m-hidden');
});

test('Renders BackToTop when isAlwaysVisible prop is set', () => {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: can you adjust this test name since it isn't really testing that BackToTop renders, but rather that it renders without the hidden class?

render(<BackToTop isAlwaysVisible />);

expect(screen.getByRole(`button`).parentElement).not.toHaveClass('pf-m-hidden');
});

test('Renders with custom className prop passed', () => {
render(<BackToTop className="test-class" />);
expect(screen.getByRole(`button`).parentElement).toHaveClass('test-class');
});

test('Renders with custom title prop passed', () => {
render(<BackToTop title="Back to the Future" />);
expect(screen.getByRole(`button`).parentElement).toHaveTextContent('Back to the Future');
});

test('Renders with passed aria-label', () => {
render(<BackToTop aria-label="Back to top test" />);
expect(screen.getByRole(`button`).parentElement).toHaveAccessibleName('Back to top test');
});

test('BackToTop can be accessed via passed innerRef', () => {
const testRef: RefObject<HTMLElement> = React.createRef();
render(<BackToTop innerRef={testRef} isAlwaysVisible />);
global.scrollTo = jest.fn();
testRef.current?.click();
expect(global.scrollTo).toBeCalledTimes(1);
});

test('BackToTop reacts to scrolling inside element passed via scrollableSelector', () => {
render(
<div id="backToTopWrapper">
<BackToTop scrollableSelector="#backToTopWrapper" />
</div>
);
const wrapper = document.getElementById('backToTopWrapper');
fireEvent.scroll(wrapper as HTMLElement, { target: { scrollY: 401 } });

expect(screen.getByRole(`button`).parentElement).not.toHaveClass('pf-m-hidden');
});

test('BackToTop does not react to scrolling inside window when scrollableSelector passed', () => {
render(
<div id="backToTopWrapper">
<BackToTop scrollableSelector="#backToTopWrapper" />
</div>
);
fireEvent.scroll(window, { target: { scrollY: 401 } });

expect(screen.getByRole(`button`).parentElement).toHaveClass('pf-m-hidden');
});

test('Clicking backToTop scrolls back to top of the element passed via scrollableSelector', async () => {
render(
<div id="backToTopWrapper">
<BackToTop scrollableSelector="#backToTopWrapper" />
</div>
);
const user = userEvent.setup();
const wrapper = document.getElementById('backToTopWrapper');
fireEvent.scroll(wrapper as HTMLElement, { target: { scrollY: 401 } });
wrapper!.scrollTo = jest.fn();
await user.click(screen.getByRole(`button`).parentElement as Element);

expect(wrapper?.scrollTo).toBeCalledTimes(1);
});

test('Passes correct text content to button child component', () => {
render(<BackToTop title="Back to the future" />);

expect(screen.getByText('Back to the future')).toBeVisible();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: here I would rather see us use the getByRole query to select the button and assert that it's text is what we expect using the toHaveTextContent matcher.

});

test('Passes correct variant to button child component', () => {
render(<BackToTop title="Back to the future" />);

expect(screen.getByText('primary')).toBeVisible();
});

test('Passes correct iconPosition to button child component', () => {
render(<BackToTop />);

expect(screen.getByText('right')).toBeVisible();
});

test('Passes correct icon to button child component', () => {
render(<BackToTop />);

expect(screen.getByTestId('icon').firstChild).toBeTruthy();
});
Comment on lines +150 to +154
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: for the icon I would rather see us do something like what I did for the angle right icon in the accordion toggle where we mock it out (since the SVG isn't actually a responsibility of BackToTop), and then I would just assert that the icon div contains the text you pass in for the mock so that we know it's being sent to Button properly.


test('verify always show', () => {
const { asFragment } = render(<BackToTop isAlwaysVisible>test</BackToTop>);
test('Matches the snapshot', () => {
const { asFragment } = render(<BackToTop />);

expect(asFragment()).toMatchSnapshot();
});
expect(asFragment()).toMatchSnapshot();
});
Original file line number Diff line number Diff line change
@@ -1,109 +1,36 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`BackToTop verify always show 1`] = `
<DocumentFragment>
<div
class="pf-c-back-to-top"
>
<button
aria-disabled="false"
class="pf-c-button pf-m-primary"
data-ouia-component-id="OUIA-Generated-Button-primary-3"
data-ouia-component-type="PF4/Button"
data-ouia-safe="true"
type="button"
>
Back to top
<span
class="pf-c-button__icon pf-m-end"
>
<svg
aria-hidden="true"
fill="currentColor"
height="1em"
role="img"
style="vertical-align: -0.125em;"
viewBox="0 0 320 512"
width="1em"
>
<path
d="M177 159.7l136 136c9.4 9.4 9.4 24.6 0 33.9l-22.6 22.6c-9.4 9.4-24.6 9.4-33.9 0L160 255.9l-96.4 96.4c-9.4 9.4-24.6 9.4-33.9 0L7 329.7c-9.4-9.4-9.4-24.6 0-33.9l136-136c9.4-9.5 24.6-9.5 34-.1z"
/>
</svg>
</span>
</button>
</div>
</DocumentFragment>
`;

exports[`BackToTop verify basic 1`] = `
exports[`Matches the snapshot 1`] = `
<DocumentFragment>
<div
class="pf-c-back-to-top pf-m-hidden"
>
<button
aria-disabled="false"
class="pf-c-button pf-m-primary"
data-ouia-component-id="OUIA-Generated-Button-primary-1"
data-ouia-component-type="PF4/Button"
data-ouia-safe="true"
type="button"
>
<button>
Back to top
<span
class="pf-c-button__icon pf-m-end"
>
<svg
aria-hidden="true"
fill="currentColor"
height="1em"
role="img"
style="vertical-align: -0.125em;"
viewBox="0 0 320 512"
width="1em"
>
<path
d="M177 159.7l136 136c9.4 9.4 9.4 24.6 0 33.9l-22.6 22.6c-9.4 9.4-24.6 9.4-33.9 0L160 255.9l-96.4 96.4c-9.4 9.4-24.6 9.4-33.9 0L7 329.7c-9.4-9.4-9.4-24.6 0-33.9l136-136c9.4-9.5 24.6-9.5 34-.1z"
/>
</svg>
</span>
</button>
</div>
</DocumentFragment>
`;

exports[`BackToTop verify custom class 1`] = `
<DocumentFragment>
<div
class="pf-c-back-to-top pf-m-hidden custom-css"
>
<button
aria-disabled="false"
class="pf-c-button pf-m-primary"
data-ouia-component-id="OUIA-Generated-Button-primary-2"
data-ouia-component-type="PF4/Button"
data-ouia-safe="true"
type="button"
<p>
primary
</p>
<p>
right
</p>
<div
data-testid="icon"
>
Back to top
<span
class="pf-c-button__icon pf-m-end"
<svg
aria-hidden="true"
fill="currentColor"
height="1em"
role="img"
style="vertical-align: -0.125em;"
viewBox="0 0 320 512"
width="1em"
>
<svg
aria-hidden="true"
fill="currentColor"
height="1em"
role="img"
style="vertical-align: -0.125em;"
viewBox="0 0 320 512"
width="1em"
>
<path
d="M177 159.7l136 136c9.4 9.4 9.4 24.6 0 33.9l-22.6 22.6c-9.4 9.4-24.6 9.4-33.9 0L160 255.9l-96.4 96.4c-9.4 9.4-24.6 9.4-33.9 0L7 329.7c-9.4-9.4-9.4-24.6 0-33.9l136-136c9.4-9.5 24.6-9.5 34-.1z"
/>
</svg>
</span>
</button>
<path
d="M177 159.7l136 136c9.4 9.4 9.4 24.6 0 33.9l-22.6 22.6c-9.4 9.4-24.6 9.4-33.9 0L160 255.9l-96.4 96.4c-9.4 9.4-24.6 9.4-33.9 0L7 329.7c-9.4-9.4-9.4-24.6 0-33.9l136-136c9.4-9.5 24.6-9.5 34-.1z"
/>
</svg>
</div>
</div>
</DocumentFragment>
`;