Skip to content

Commit 2624731

Browse files
authored
Merge branch 'develop' into fix/asset-size
2 parents 1601e0f + 1c05241 commit 2624731

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2304
-1016
lines changed

client/common/ButtonOrLink.jsx

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react';
2+
import { Link } from 'react-router';
3+
import PropTypes from 'prop-types';
4+
5+
/**
6+
* Helper for switching between <button>, <a>, and <Link>
7+
*/
8+
const ButtonOrLink = ({ href, children, ...props }) => {
9+
if (href) {
10+
if (href.startsWith('http')) {
11+
return (
12+
<a href={href} target="_blank" rel="noopener noreferrer" {...props}>
13+
{children}
14+
</a>
15+
);
16+
}
17+
return (
18+
<Link to={href} {...props}>
19+
{children}
20+
</Link>
21+
);
22+
}
23+
return <button {...props}>{children}</button>;
24+
};
25+
26+
/**
27+
* Accepts all the props of an HTML <a> or <button> tag.
28+
*/
29+
ButtonOrLink.propTypes = {
30+
/**
31+
* If providing an href, will render as a link instead of a button.
32+
* Can be internal or external.
33+
* Internal links will use react-router.
34+
* External links should start with 'http' or 'https' and will open in a new window.
35+
*/
36+
href: PropTypes.string,
37+
/**
38+
* Content of the button/link.
39+
* Can be either a string or a complex element.
40+
*/
41+
children: PropTypes.node.isRequired
42+
};
43+
44+
ButtonOrLink.defaultProps = {
45+
href: null
46+
};
47+
48+
export default ButtonOrLink;

client/common/ButtonOrLink.test.jsx

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import React from 'react';
2+
import { render, screen, fireEvent } from '../test-utils';
3+
import ButtonOrLink from './ButtonOrLink';
4+
5+
describe('ButtonOrLink', () => {
6+
const clickHandler = jest.fn();
7+
8+
afterEach(() => {
9+
clickHandler.mockClear();
10+
});
11+
12+
it('can render a clickable button', () => {
13+
render(<ButtonOrLink onClick={clickHandler}>Text</ButtonOrLink>);
14+
const button = screen.getByRole('button');
15+
expect(button).toBeInstanceOf(HTMLButtonElement);
16+
expect(button).toContainHTML('<button>Text</button>');
17+
fireEvent.click(button);
18+
expect(clickHandler).toHaveBeenCalled();
19+
});
20+
21+
it('can render an external link', () => {
22+
render(<ButtonOrLink href="https://p5js.org">p5</ButtonOrLink>);
23+
const link = screen.getByRole('link');
24+
expect(link).toBeInstanceOf(HTMLAnchorElement);
25+
expect(link).toHaveAttribute('href', 'https://p5js.org');
26+
});
27+
28+
it('can render an internal link with react-router', () => {
29+
render(<ButtonOrLink href="/about">About</ButtonOrLink>);
30+
// TODO: how can this be tested? Needs a router provider?
31+
});
32+
});

0 commit comments

Comments
 (0)