Skip to content

Commit

Permalink
Add tests for ShareDialog, various accessibility improvements for forms
Browse files Browse the repository at this point in the history
  • Loading branch information
maksis committed Dec 31, 2024
1 parent 2105765 commit cb6bf3b
Show file tree
Hide file tree
Showing 34 changed files with 1,096 additions and 372 deletions.
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module.exports = {
'\\.(css|less)$': '<rootDir>/jest/stubs/CSSStub.js',
},
setupFiles: ['./jest/setup.js'],
setupFilesAfterEnv: ['./jest/setup-after-env.js'],
cacheDirectory: './jest/cache/',
testEnvironment: 'jsdom',
transformIgnorePatterns: ['node_modules/(?!(escape-string-regexp|airdcpp-apisocket))$'],
Expand Down
1 change: 1 addition & 0 deletions jest/setup-after-env.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@testing-library/jest-dom';
507 changes: 303 additions & 204 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@gfx/zopfli": "^1.0.15",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.8",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.1.0",
"@testing-library/user-event": "^14.5.2",
"@types/express": "^5.0.0",
Expand All @@ -68,7 +69,7 @@
"@types/webpack": "^5.28.0",
"@typescript-eslint/eslint-plugin": "^8.2.0",
"@typescript-eslint/parser": "^8.2.0",
"airdcpp-apisocket": "^3.0.0-beta",
"airdcpp-apisocket": "^3.0.0-beta.6",
"apexcharts": "^4.3.0",
"babel-jest": "^29.2.2",
"babel-loader": "^9.0.1",
Expand Down Expand Up @@ -125,7 +126,6 @@
"react-refresh": "^0.16.0",
"react-router": "^7.0.2",
"react-select": "^5.5.6",
"react-select-event": "^5.5.1",
"react-toastify": "^11.0.0",
"react-transition-group": "^4.4.5",
"reflux": "^6.0.0",
Expand All @@ -136,7 +136,6 @@
"ts-jest": "^29.0.3",
"ts-loader": "^9.4.1",
"typescript": "^5.0.4",
"wait-for-expect": "^3.0.2",
"webpack": "^5.74.0",
"webpack-cli": "^6.0.1",
"webpack-dev-middleware": "^7.0.0",
Expand Down
6 changes: 6 additions & 0 deletions src/components/autosuggest/base/SuggestField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export type SuggestFieldProps<SuggestionT> = Omit<
// The same submitHandler is called but without suggestion object
button?: React.ReactElement<ButtonProps>;

name?: string;

autoFocus?: boolean;
placeholder?: string;
className?: string;
Expand Down Expand Up @@ -127,6 +129,8 @@ class SuggestField<SuggestionT = any> extends React.Component<
placeholder,
defaultValue,
button,
name,
id,
children,
...other
} = this.props;
Expand All @@ -138,6 +142,8 @@ class SuggestField<SuggestionT = any> extends React.Component<
autoFocus,
value: text,
onKeyDown: this.onKeyDown,
name,
id,
};

const suggestField = (
Expand Down
5 changes: 2 additions & 3 deletions src/components/download/DownloadDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { PathDownloadHandler } from './types';
import './style.css';
import { useSession } from 'context/SessionContext';
import { useSocket } from 'context/SocketContext';
import { getFileName, getFilePath } from 'utils/FileUtils';

export type DownloadDialogProps<
ItemT extends UI.DownloadableItemInfo = UI.DownloadableItemInfo,
Expand Down Expand Up @@ -121,9 +122,7 @@ const DownloadDialog: React.FC<Props> = (props) => {
path="browse/*"
element={
<FileBrowserDialog
onConfirm={(path, directoryPath, fileName) =>
handleDownload(directoryPath, fileName)
}
onConfirm={(path) => handleDownload(getFilePath(path), getFileName(path))}
initialPath={getInitialBrowsePath()}
selectMode={
itemInfo.type.id === 'directory'
Expand Down
28 changes: 18 additions & 10 deletions src/components/download/__tests__/DownloadDialog.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import {
getConnectedSocket,
getMockServer,
waitForExpect,
} from 'airdcpp-apisocket/tests/helpers.js';
} from 'airdcpp-apisocket/tests/mock-server.js';

import { jest } from '@jest/globals';
import ShareConstants from 'constants/ShareConstants';
Expand All @@ -11,7 +10,7 @@ import FavoriteDirectoryConstants from 'constants/FavoriteDirectoryConstants';
import { FavoriteDirectoriesGroupedPathsResponse } from 'tests/mocks/api/favorite-directories';
import HistoryConstants, { HistoryStringEnum } from 'constants/HistoryConstants';
import {
FilelistGetFilelistItemResponse,
FilelistGetFilelistItemFileResponse,
FilelistGetResponse,
MOCK_FILELIST_ITEM_ID,
} from 'tests/mocks/api/filelist';
Expand Down Expand Up @@ -47,28 +46,37 @@ describe('DownloadDialog', () => {
const getSocket = async () => {
const { socket } = await getConnectedSocket(server);

server.addDataHandler(
// Target paths fetch
server.addRequestHandler(
'GET',
ShareConstants.GROUPED_ROOTS_GET_URL,
ShareGetGroupedRootsResponse,
);
server.addDataHandler(
server.addRequestHandler(
'GET',
FavoriteDirectoryConstants.GROUPED_DIRECTORIES_URL,
FavoriteDirectoriesGroupedPathsResponse,
);
server.addDataHandler(
server.addRequestHandler(
'GET',
`${HistoryConstants.STRINGS_URL}/${HistoryStringEnum.DOWNLOAD_DIR}`,
HistoryStringPathResponse,
);

server.addDataHandler(
// Saving of the selected path
server.addRequestHandler(
'POST',
`${HistoryConstants.STRINGS_URL}/${HistoryStringEnum.DOWNLOAD_DIR}`,
undefined,
);

// File browser
server.addRequestHandler(
'POST',
FilesystemConstants.DISK_INFO_URL,
FilesystemDiskInfoResponse,
);
server.addDataHandler(
server.addRequestHandler(
'POST',
FilesystemConstants.LIST_URL,
FilesystemListContentResponse,
Expand All @@ -90,7 +98,7 @@ describe('DownloadDialog', () => {
<DownloadDialog
downloadHandler={handleDownload}
itemDataGetter={() =>
Promise.resolve(FilelistGetFilelistItemResponse as API.FilelistItem)
Promise.resolve(FilelistGetFilelistItemFileResponse as API.FilelistItem)
}
userGetter={() => MockHintedUserResponse as API.HintedUser}
session={FilelistGetResponse}
Expand Down Expand Up @@ -129,7 +137,7 @@ describe('DownloadDialog', () => {
await modalController.openDialog();

// Check content
await waitForExpect(() => expect(getByText('Download')).toBeTruthy());
await waitFor(() => expect(getByText('Download')).toBeTruthy());

await modalController.closeDialogButton('Close');

Expand Down
2 changes: 1 addition & 1 deletion src/components/form/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ class Form<ValueType extends UI.FormValueMap = UI.FormValueMap> extends Componen
};

return (
<div className={classNames('form', className)}>
<div role="form" className={classNames('form', className)}>
{!!title && <div className="ui form header">{title}</div>}
<TcombForm
ref={(c) => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/form/fields/BrowseField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const BrowseFieldInput = ({ locals }: BrowserFieldProps) => {
const { formT } = locals.context;
return (
<div className={fieldStyle}>
<input ref={inputRef} value={locals.value} onChange={onChange} />
<input ref={inputRef} value={locals.value} onChange={onChange} {...locals.attrs} />
{hasFilesystemAccess && (
<Button caption={formT.translate('Browse')} onClick={showBrowseDialog} />
)}
Expand Down
14 changes: 6 additions & 8 deletions src/components/form/fields/HubUrlField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,12 @@ type TCombTemplate = {
const HubUrlTemplate: TCombTemplate = {
renderInput(locals) {
return (
<div className="ui fluid input">
<HubSearchInput
onChange={(hubUrl) => {
locals.onChange(hubUrl);
}}
defaultValue={locals.value || undefined}
/>
</div>
<HubSearchInput
onChange={(hubUrl) => {
locals.onChange(hubUrl);
}}
defaultValue={locals.value || undefined}
/>
);
},
};
Expand Down
19 changes: 10 additions & 9 deletions src/components/form/fields/common/AutoSuggestField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@ type TCombTemplate = {
const AutoSuggestTemplate: TCombTemplate = {
renderInput(locals) {
return (
<div className="ui fluid input">
<LocalSuggestField
placeholder={locals.attrs.placeholder}
data={locals.config.suggestionGetter()}
onChange={locals.onChange}
defaultValue={locals.value ? locals.value : ''}
alwaysRenderSuggestions={locals.config.alwaysList}
/>
</div>
<LocalSuggestField
name={locals.attrs.name}
id={locals.attrs.id}
disabled={locals.disabled}
placeholder={locals.attrs.placeholder}
data={locals.config.suggestionGetter()}
onChange={locals.onChange}
defaultValue={locals.value ? locals.value : ''}
alwaysRenderSuggestions={locals.config.alwaysList}
/>
);
},
};
Expand Down
2 changes: 2 additions & 0 deletions src/components/form/fields/common/SelectField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,15 @@ const SelectTemplate: TCombTemplate = {
const { formT } = locals.context;
return (
<Select
name={locals.attrs.name}
value={value}
options={options}
onChange={onChange}
isMulti={true}
noOptionsMessage={() => formT.translate('No options')}
components={MultiSelectComponents}
menuPlacement="top"
inputId={locals.attrs.id}
/>
);
},
Expand Down
10 changes: 7 additions & 3 deletions src/components/semantic/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export interface CheckboxProps {
style?: React.CSSProperties;
settings?: SemanticUI.CheckboxSettings;
beforeUnchecked?: () => void;

id?: string;
name?: string;
}

class Checkbox extends React.PureComponent<CheckboxProps> {
Expand Down Expand Up @@ -52,7 +55,8 @@ class Checkbox extends React.PureComponent<CheckboxProps> {
}

render() {
const { className, checked, caption, type, disabled, floating, style } = this.props;
const { className, checked, caption, type, disabled, floating, style, id, name } =
this.props;

const checkboxStyle = classNames(
'ui checkbox',
Expand All @@ -70,8 +74,8 @@ class Checkbox extends React.PureComponent<CheckboxProps> {
className={checkboxStyle}
style={style}
>
<input type="checkbox" defaultChecked={checked} />
{!!caption && <label>{caption}</label>}
<input id={id} name={name} type="checkbox" defaultChecked={checked} />
{!!caption && <label htmlFor={id}>{caption}</label>}
</div>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/components/semantic/CheckboxDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const CheckboxDialog: React.FC<CheckboxDialogProps> = ({
<ConfirmDialog onApproved={onApprove} {...other}>
{checkboxCaption && (
<Checkbox
id="confirm-checkbox"
checked={false}
onChange={(state) => (checked.current = state)}
caption={checkboxCaption}
Expand Down
4 changes: 2 additions & 2 deletions src/components/table/Cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,8 @@ export const FileDownloadCell = <

// eslint-disable-next-line max-len
export interface CheckboxCellProps
extends Omit<RowWrapperCellChildProps<boolean, any>, 'onChange'>,
Omit<CheckboxProps, 'onChange' | 'checked'> {
extends Omit<RowWrapperCellChildProps<boolean, any>, 'onChange' | 'id'>,
Omit<CheckboxProps, 'onChange' | 'checked' | 'id'> {
onChange: (checked: boolean, rowData: any) => void;
}

Expand Down
Loading

0 comments on commit cb6bf3b

Please sign in to comment.