Skip to content

Commit fedf008

Browse files
authored
Configure Jest with Typescript and convert Button to Typescript. (#1797)
1 parent 0ea54e4 commit fedf008

File tree

10 files changed

+246
-111
lines changed

10 files changed

+246
-111
lines changed

.babelrc.js

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ module.exports = {
2020
},
2121
},
2222
],
23+
'@babel/preset-typescript',
2324
],
2425
},
2526
},

components/Buttons/Button/Button.js

-82
This file was deleted.

components/Buttons/Button/Button.tsx

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import React from 'react';
2+
import noop from 'lodash/noop';
3+
import classNames from 'classnames';
4+
import { BUTTON } from 'common/constants/testIDs';
5+
import { gtag } from 'common/utils/thirdParty/gtag';
6+
import { getDataAttributes, getAriaAttributes } from 'common/utils/prop-utils';
7+
import styles from './Button.module.css';
8+
9+
type GoogleAnalyticsEventPropType = {
10+
/**
11+
* A description of the behaviour. E.g. 'Clicked Delete', 'Added a component', 'Deleted account'
12+
*/
13+
action: string;
14+
/**
15+
* A top level category for these events. E.g. 'User', 'Navigation', 'App Editing', etc.
16+
*/
17+
category: string;
18+
/**
19+
* More precise labeling of the related action. E.g. alongside the 'Added a component' action,
20+
* we could add the name of a component as the label. E.g. 'Survey', 'Heading', 'Button', etc.
21+
*/
22+
label?: string;
23+
/**
24+
* A means of recording a numerical value against an event. E.g. a rating, a score, etc.
25+
*/
26+
value?: number;
27+
/**
28+
* If an event is not triggered by a user interaction, but instead by our code (e.g. on page
29+
* load), it should be flagged as a nonInteraction event to avoid skewing bounce rate data.
30+
*/
31+
nonInteraction?: boolean;
32+
/**
33+
* This specifies the transport mechanism with which hits will be sent. Valid values include
34+
* 'beacon', 'xhr', or 'image'.
35+
*/
36+
transport?: 'beacon' | 'xhr' | 'image';
37+
};
38+
39+
type ButtonProps = {
40+
/**
41+
* Helps track in-page `event` interactions.
42+
*/
43+
analyticsObject?: GoogleAnalyticsEventPropType;
44+
/**
45+
* Forces the component's width as wide as its parent container's width.
46+
*/
47+
fullWidth?: boolean;
48+
/**
49+
* Sets the button color theme.
50+
*/
51+
theme?: 'primary' | 'secondary';
52+
} & React.ButtonHTMLAttributes<HTMLButtonElement>;
53+
54+
export default function Button({
55+
analyticsObject = {
56+
action: 'Button Selected',
57+
category: 'Interactions',
58+
},
59+
children,
60+
className = undefined,
61+
disabled = false,
62+
fullWidth = false,
63+
onClick = noop,
64+
tabIndex = 0,
65+
theme = 'primary',
66+
type = 'button',
67+
...rest
68+
}: ButtonProps) {
69+
const customDataAttributes = getDataAttributes(rest);
70+
const ariaAttributes = getAriaAttributes(rest);
71+
72+
const eventConfig = {
73+
...analyticsObject,
74+
label: typeof children === 'string' ? children : undefined,
75+
};
76+
77+
return (
78+
<button
79+
className={classNames(styles.Button, className, styles[theme], {
80+
[styles.disabled]: disabled,
81+
[styles.fullWidth]: fullWidth,
82+
})}
83+
data-testid={BUTTON}
84+
disabled={disabled}
85+
onClick={e => {
86+
gtag.event(eventConfig);
87+
onClick(e);
88+
}}
89+
tabIndex={tabIndex}
90+
type={type}
91+
{...customDataAttributes}
92+
{...ariaAttributes}
93+
>
94+
{children}
95+
</button>
96+
);
97+
}

components/Buttons/Button/__stories__/Button.stories.js

-18
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Meta, StoryObj } from '@storybook/react';
2+
import Button from '../Button';
3+
4+
type ButtonStoryType = StoryObj<typeof Button>;
5+
6+
export const Default: ButtonStoryType = {
7+
render: args => <Button {...args} />,
8+
args: {
9+
children: 'Button',
10+
},
11+
};
12+
13+
const meta: Meta<typeof Button> = {
14+
title: 'Buttons/Button',
15+
component: Button,
16+
parameters: {
17+
actions: {
18+
handles: ['click'],
19+
},
20+
},
21+
};
22+
23+
export default meta;

components/Buttons/Button/__tests__/Button.test.js renamed to components/Buttons/Button/__tests__/Button.test.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ describe('Button', () => {
3636
const { queryByTestId } = render(<Button onClick={onClickMock}>Testing</Button>);
3737

3838
expect(onClickMock).toHaveBeenCalledTimes(0);
39-
39+
// @ts-expect-error Argument of type 'HTMLElement | null' is not assignable (delete comment to view full error)
4040
fireEvent.click(queryByTestId(BUTTON));
4141

4242
expect(onClickMock).toHaveBeenCalledTimes(1);
@@ -46,7 +46,7 @@ describe('Button', () => {
4646
const { queryByTestId } = render(<Button {...requiredProps} />);
4747

4848
expect(gtag.event).toHaveBeenCalledTimes(0);
49-
49+
// @ts-expect-error Argument of type 'HTMLElement | null' is not assignable (delete comment to view full error)
5050
fireEvent.click(queryByTestId(BUTTON));
5151

5252
expect(gtag.event).toHaveBeenCalledTimes(1);

jest.config.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,7 @@ module.exports = {
8484
// ],
8585

8686
// An array of file extensions your modules use
87-
// moduleFileExtensions: [
88-
// "js",
89-
// "json",
90-
// "jsx",
91-
// "node"
92-
// ],
87+
moduleFileExtensions: ['js', 'json', 'jsx', 'node', 'ts', 'tsx'],
9388

9489
// A map from regular expressions to module names that allow to stub out resources with a single module
9590
moduleNameMapper: {
@@ -160,7 +155,12 @@ module.exports = {
160155
// testLocationInResults: false,
161156

162157
// The glob patterns Jest uses to detect test files
163-
testMatch: ['<rootDir>/**/*.test.js'],
158+
testMatch: [
159+
'<rootDir>/**/*.test.js',
160+
'<rootDir>/**/*.test.jsx',
161+
'<rootDir>/**/*.test.ts',
162+
'<rootDir>/**/*.test.tsx',
163+
],
164164

165165
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
166166
// testPathIgnorePatterns: [
@@ -178,7 +178,7 @@ module.exports = {
178178

179179
// A map from regular expressions to paths to transformers
180180
transform: {
181-
'^.+\\.js$': 'babel-jest',
181+
'^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
182182
'^(?!.*\\.(js|css|json)$)': '<rootDir>/test-utils/transforms/file.js',
183183
},
184184

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
"devDependencies": {
8585
"@babel/core": "^7.19.3",
8686
"@babel/eslint-parser": "^7.19.1",
87+
"@babel/preset-typescript": "^7.23.3",
8788
"@cypress/code-coverage": "^3.10.0",
8889
"@cypress/webpack-preprocessor": "^5.12.0",
8990
"@operation_code/eslint-plugin-custom-rules": "^1.0.1",

0 commit comments

Comments
 (0)