Skip to content

Commit 505034c

Browse files
authored
[Footer] Propagate attributes (#129)
* feat: [Footer] Propagate attributes * test: FooterLinks * test: Footer
1 parent e9b3c32 commit 505034c

File tree

3 files changed

+238
-15
lines changed

3 files changed

+238
-15
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { render, screen } from '@testing-library/react';
2+
import Footer from './Footer';
3+
4+
describe('Footer', () => {
5+
it('Skips empty lists', () => {
6+
render(<Footer />);
7+
8+
// List not rendered
9+
const list = screen.queryAllByRole('list');
10+
expect(list.length).toEqual(0);
11+
12+
// Items not rendered
13+
const items = screen.queryAllByRole('listitem');
14+
expect(items.length).toEqual(0);
15+
16+
// Banner displayed (text is broken up, hence the multiple queries)
17+
expect(screen.getByText('An official website of the'));
18+
expect(screen.getByText('United States government'));
19+
});
20+
21+
it('Renders NavLinks', () => {
22+
const expectedClassName = /o-footer_nav-list/g;
23+
const expectedItemCount = 3;
24+
25+
const navLink = [
26+
<a href='/' className='link1' key='link1'>
27+
Link 1
28+
</a>,
29+
<a href='/' className='link2' key='link2'>
30+
Link 2
31+
</a>,
32+
<a href='/' className='link3' key='link3'>
33+
Link 3
34+
</a>
35+
];
36+
render(<Footer navLinks={navLink} />);
37+
38+
// // List rendered
39+
const list = screen.getAllByRole('list');
40+
expect(list.length).toEqual(1);
41+
expect(list[0].className).toMatch(expectedClassName);
42+
43+
// Items rendered
44+
const items = screen.getAllByRole('listitem');
45+
expect(items.length).toEqual(expectedItemCount);
46+
});
47+
48+
it('Renders SocialLinks', () => {
49+
const expectedClassName = /m-social-media_icons/g;
50+
const expectedItemCount = 1;
51+
52+
const socialLink = [
53+
<a href='/' className='link1' key='link1'>
54+
Link 1
55+
</a>
56+
];
57+
render(<Footer socialLinks={socialLink} />);
58+
59+
// // List rendered
60+
const list = screen.getAllByRole('list');
61+
expect(list.length).toEqual(1);
62+
expect(list[0].className).toMatch(expectedClassName);
63+
64+
// Items rendered
65+
const items = screen.getAllByRole('listitem');
66+
expect(items.length).toEqual(expectedItemCount);
67+
});
68+
69+
it('Renders all 3 link columns', () => {
70+
const expectedClassName = /o-footer_list/g;
71+
const expectedItemCount = 3;
72+
73+
const socialLink = [
74+
<a href='/' className='link1' key='link1'>
75+
Link 1
76+
</a>
77+
];
78+
render(
79+
<Footer
80+
linksCol1={socialLink}
81+
linksCol2={socialLink}
82+
linksCol3={socialLink}
83+
/>
84+
);
85+
86+
// Lists rendered
87+
const list = screen.getAllByRole('list');
88+
expect(list.length).toEqual(3);
89+
expect(list[0].className).toMatch(expectedClassName);
90+
91+
// All items rendered
92+
const items = screen.getAllByRole('listitem');
93+
expect(items.length).toEqual(expectedItemCount);
94+
});
95+
});

src/components/Footer/Footer.tsx

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
import List from '../List/List';
2-
import { ListItemBuilder } from '../List/ListItem';
1+
import classnames from 'classnames';
32
import { BackToTop } from './BackToTop';
43
import './Footer.less';
54
import { FooterBanner } from './FooterBanner';
65
import { FooterLinksColumn, NavLinks, SocialLinks } from './FooterLinks';
76
import './SocialMedia.less';
87

9-
interface FooterProperties {
10-
navLinks: JSX.Element[];
11-
socialLinks: JSX.Element[];
12-
linksCol1: JSX.Element[];
13-
linksCol2: JSX.Element[];
14-
linksCol3: JSX.Element[];
8+
interface FooterProperties extends React.HTMLProps<HTMLElement> {
9+
navLinks?: JSX.Element[];
10+
socialLinks?: JSX.Element[];
11+
linksCol1?: JSX.Element[];
12+
linksCol2?: JSX.Element[];
13+
linksCol3?: JSX.Element[];
1514
}
1615

1716
/**
@@ -22,10 +21,18 @@ export default function Footer({
2221
socialLinks = [],
2322
linksCol1 = [],
2423
linksCol2 = [],
25-
linksCol3 = []
24+
linksCol3 = [],
25+
className,
26+
...properties
2627
}: FooterProperties): JSX.Element {
28+
const classes = ['o-footer', className];
29+
2730
return (
28-
<footer className='o-footer' data-js-hook='state_atomic_init'>
31+
<footer
32+
className={classnames(classes)}
33+
data-js-hook='state_atomic_init'
34+
{...properties}
35+
>
2936
<div className='wrapper wrapper__match-content'>
3037
<div className='o-footer_pre'>
3138
<BackToTop />
@@ -39,11 +46,7 @@ export default function Footer({
3946
</div>
4047

4148
<div className='o-footer-middle-right'>
42-
<List className='o-footer_list'>
43-
<ListItemBuilder className='m-list_link'>
44-
{linksCol3}
45-
</ListItemBuilder>
46-
</List>
49+
<FooterLinksColumn>{linksCol3}</FooterLinksColumn>
4750
</div>
4851

4952
<FooterBanner />
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { render, screen } from '@testing-library/react';
2+
import { Icon } from '../Icon/Icon';
3+
import { FooterLinksColumn, NavLinks, SocialLinks } from './FooterLinks';
4+
5+
describe('NavLinks', () => {
6+
it('Skips empty children', () => {
7+
render(<NavLinks>{[]}</NavLinks>);
8+
9+
// List not rendered
10+
const list = screen.queryAllByRole('list');
11+
expect(list.length).toEqual(0);
12+
13+
// Items not rendered
14+
const items = screen.queryAllByRole('listitem');
15+
expect(items.length).toEqual(0);
16+
});
17+
18+
it('Renders children as nav-list', () => {
19+
render(
20+
<NavLinks>
21+
<a href='/' key='first' className='f1'>
22+
First
23+
</a>
24+
<a href='/' key='second' className='f2'>
25+
Second
26+
</a>
27+
</NavLinks>
28+
);
29+
30+
// List rendered
31+
const list = screen.getAllByRole('list');
32+
expect(list.length).toEqual(1);
33+
expect(list[0].className).toMatch(/o-footer_nav-list/g);
34+
35+
// Items rendered
36+
const items = screen.getAllByRole('listitem');
37+
expect(items.length).toEqual(2);
38+
39+
// Classnames propagated
40+
const links = screen.getAllByRole('link');
41+
expect(links[0].className).toMatch(/f1/g);
42+
expect(links[1].className).toMatch(/f2/g);
43+
});
44+
});
45+
46+
describe('SocialLinks', () => {
47+
it('Skips empty children', () => {
48+
render(<SocialLinks>{[]}</SocialLinks>);
49+
50+
// List not rendered
51+
const list = screen.queryAllByRole('list');
52+
expect(list.length).toEqual(0);
53+
54+
// Items not rendered
55+
const items = screen.queryAllByRole('listitem');
56+
expect(items.length).toEqual(0);
57+
});
58+
59+
it('Renders items', () => {
60+
render(
61+
<SocialLinks>
62+
{[
63+
<a href='/' key='first' className='facebook'>
64+
<Icon name='facebook' withBg />
65+
</a>
66+
]}
67+
</SocialLinks>
68+
);
69+
70+
// List rendered
71+
const list = screen.getAllByRole('list');
72+
expect(list.length).toEqual(1);
73+
expect(list[0].className).toMatch(/m-social-media_icons/g);
74+
75+
// Items rendered
76+
const items = screen.getAllByRole('listitem');
77+
expect(items.length).toEqual(1);
78+
79+
// Classnames propagated
80+
const links = screen.getAllByRole('link');
81+
expect(links[0].className).toMatch(/facebook/g);
82+
83+
// TODO: How to test that the Icon is rendered?
84+
// It does not show up in the screen.debug() output
85+
});
86+
});
87+
88+
describe('FooterLinksColumn', () => {
89+
it('Skips empty children', () => {
90+
render(<FooterLinksColumn>{[]}</FooterLinksColumn>);
91+
92+
// List not rendered
93+
const list = screen.queryAllByRole('list');
94+
expect(list.length).toEqual(0);
95+
96+
// Items not rendered
97+
const items = screen.queryAllByRole('listitem');
98+
expect(items.length).toEqual(0);
99+
});
100+
101+
it('Renders items', () => {
102+
render(
103+
<FooterLinksColumn>
104+
{[
105+
<a href='/' key='first' className='facebook'>
106+
Link 1
107+
</a>
108+
]}
109+
</FooterLinksColumn>
110+
);
111+
112+
// List rendered
113+
const list = screen.getAllByRole('list');
114+
expect(list.length).toEqual(1);
115+
expect(list[0].className).toMatch(/o-footer_list/g);
116+
117+
// Items rendered
118+
const items = screen.getAllByRole('listitem');
119+
expect(items.length).toEqual(1);
120+
121+
// Classnames propagated
122+
const links = screen.getAllByRole('link');
123+
expect(links[0].className).toMatch(/facebook/g);
124+
});
125+
});

0 commit comments

Comments
 (0)