Skip to content

Commit

Permalink
Merge pull request #16 from bvandercar-vt/accessibility-fixes
Browse files Browse the repository at this point in the history
fix(a11y): accessibility fixes
  • Loading branch information
AnyRoad committed Oct 29, 2023
2 parents 0827b7d + e9c0052 commit 1b88419
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 72 deletions.
123 changes: 55 additions & 68 deletions src/DataRenderer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@ const commonProps: JsonRenderProps<any> = {

const collapseAll = () => false;

const testButtonsCollapsed = () => {
const buttons = screen.getAllByRole('button', { hidden: true });
expect(buttons.length).toBe(2);
expect(buttons[0]).toHaveClass('expand-icon-light');
expect(buttons[1]).toHaveClass('collapsed-content-light');
return buttons;
};

const testButtonsExpanded = () => {
const buttons = screen.getAllByRole('button', { hidden: true });
expect(buttons.length).toBe(1);
expect(buttons[0]).toHaveClass('collapse-icon-light');
return buttons;
};

describe('DataRender', () => {
it('should render booleans: true', () => {
render(<DataRender {...commonProps} value={{ test: true }} />);
Expand Down Expand Up @@ -170,114 +185,86 @@ describe('DataRender', () => {
expect(screen.queryByText('123')).not.toBeInTheDocument();
});

it('should collapse ojbects', () => {
it('should collapse and expand objects by clicking on icon', () => {
render(<DataRender {...commonProps} value={{ test: true }} />);
expect(screen.getByText(/test/)).toBeInTheDocument();
fireEvent.click(screen.getByRole('button'));
let buttons = testButtonsExpanded();
fireEvent.click(buttons[0]);
expect(screen.queryByText(/test/)).not.toBeInTheDocument();
const buttons = screen.getAllByRole('button');
expect(buttons[0]).toHaveClass('expand-icon-light');
expect(buttons[1]).toHaveClass('collapsed-content-light');
buttons = testButtonsCollapsed();
fireEvent.click(buttons[0]);
expect(screen.getByText(/test/)).toBeInTheDocument();
});

it('should collapse arrays', () => {
it('should expand objects by clicking on collapsed content', () => {
render(<DataRender {...commonProps} value={{ test: true }} shouldExpandNode={collapseAll} />);
expect(screen.queryByText(/test/)).not.toBeInTheDocument();
const buttons = testButtonsCollapsed();
fireEvent.click(buttons[1]);
testButtonsExpanded();
expect(screen.getByText(/test/)).toBeInTheDocument();
});

it('should collapse and expand arrays by clicking on icon', () => {
render(<DataRender {...commonProps} value={[1, 2, 3]} />);
expect(screen.getByText('1')).toBeInTheDocument();
fireEvent.click(screen.getByRole('button'));
let buttons = testButtonsExpanded();
fireEvent.click(buttons[0]);
expect(screen.queryByText('1')).not.toBeInTheDocument();
const buttons = screen.getAllByRole('button');
expect(buttons[0]).toHaveClass('expand-icon-light');
expect(buttons[1]).toHaveClass('collapsed-content-light');
buttons = testButtonsCollapsed();
fireEvent.click(buttons[0]);
expect(screen.getByText('1')).toBeInTheDocument();
});

it('should expand objects by clicking on', () => {
render(<DataRender {...commonProps} value={{ test: true }} shouldExpandNode={collapseAll} />);
expect(screen.queryByText(/test/)).not.toBeInTheDocument();
const buttons = screen.getAllByRole('button');
expect(buttons[0]).toHaveClass('expand-icon-light');
expect(buttons[1]).toHaveClass('collapsed-content-light');
fireEvent.keyDown(buttons[0], { key: ' ', code: 'Space' });
expect(screen.getByText(/test/)).toBeInTheDocument();
it('should expand arrays by clicking on collapsed content', () => {
render(<DataRender {...commonProps} value={[1, 2, 3]} shouldExpandNode={collapseAll} />);
expect(screen.queryByText('1')).not.toBeInTheDocument();
const buttons = testButtonsCollapsed();
fireEvent.click(buttons[1]);
testButtonsExpanded();
expect(screen.getByText('1')).toBeInTheDocument();
});

it('should expand objects by pressing Spacebar on', () => {
it('should expand objects by pressing Spacebar on icon', () => {
render(<DataRender {...commonProps} value={{ test: true }} shouldExpandNode={collapseAll} />);
expect(screen.queryByText(/test/)).not.toBeInTheDocument();
const buttons = screen.getAllByRole('button');
expect(buttons[0]).toHaveClass('expand-icon-light');
expect(buttons[1]).toHaveClass('collapsed-content-light');
fireEvent.keyDown(buttons[1], { key: ' ', code: 'Space' });

const buttons = testButtonsCollapsed();
fireEvent.keyDown(buttons[0], { key: ' ', code: 'Space' });
testButtonsExpanded();
expect(screen.getByText(/test/)).toBeInTheDocument();
});

it('should not expand objects by pressing other keys on', () => {
it('should not expand objects by pressing other keys on icon', () => {
render(<DataRender {...commonProps} value={{ test: true }} shouldExpandNode={collapseAll} />);
expect(screen.queryByText(/test/)).not.toBeInTheDocument();
let buttons = screen.getAllByRole('button');
expect(buttons[0]).toHaveClass('expand-icon-light');
expect(buttons[1]).toHaveClass('collapsed-content-light');
fireEvent.keyDown(buttons[1], { key: 'Enter', code: 'Enter' });
buttons = screen.getAllByRole('button');
expect(buttons[0]).toHaveClass('expand-icon-light');
expect(buttons[1]).toHaveClass('collapsed-content-light');
expect(screen.queryByText(/test/)).not.toBeInTheDocument();
});

it('should expand arrays by clicking on', () => {
render(
<DataRender {...commonProps} value={['test', 'array']} shouldExpandNode={collapseAll} />
);
let buttons = screen.getAllByRole('button');
expect(buttons[0]).toHaveClass('expand-icon-light');
expect(buttons[1]).toHaveClass('collapsed-content-light');
const buttons = testButtonsCollapsed();
fireEvent.keyDown(buttons[0], { key: 'Enter', code: 'Enter' });
testButtonsCollapsed();
expect(screen.queryByText(/test/)).not.toBeInTheDocument();
expect(screen.queryByText(/array/)).not.toBeInTheDocument();
fireEvent.click(buttons[0]);
buttons = screen.getAllByRole('button');
expect(buttons.length).toBe(1);
expect(buttons[0]).toHaveClass('collapse-icon-light');
expect(screen.getByText(/test/)).toBeInTheDocument();
expect(screen.getByText(/array/)).toBeInTheDocument();
});

it('should expand arrays by pressing Spacebar on', () => {
it('should expand arrays by pressing Spacebar on icon', () => {
render(
<DataRender {...commonProps} value={['test', 'array']} shouldExpandNode={collapseAll} />
);
let buttons = screen.getAllByRole('button');
expect(buttons[0]).toHaveClass('expand-icon-light');
expect(buttons[1]).toHaveClass('collapsed-content-light');
const buttons = testButtonsCollapsed();
expect(screen.queryByText(/test/)).not.toBeInTheDocument();
expect(screen.queryByText(/array/)).not.toBeInTheDocument();

fireEvent.keyDown(buttons[1], { key: ' ', code: 'Space' });
buttons = screen.getAllByRole('button');
expect(buttons.length).toBe(1);
expect(buttons[0]).toHaveClass('collapse-icon-light');
fireEvent.keyDown(buttons[0], { key: ' ', code: 'Space' });
testButtonsExpanded();
expect(screen.getByText(/test/)).toBeInTheDocument();
expect(screen.getByText(/array/)).toBeInTheDocument();
});

it('should not expand arrays by pressing other keys on', () => {
it('should not expand arrays by pressing other keys on icon', () => {
render(
<DataRender {...commonProps} value={['test', 'array']} shouldExpandNode={collapseAll} />
);
let buttons = screen.getAllByRole('button');
expect(buttons[0]).toHaveClass('expand-icon-light');
expect(buttons[1]).toHaveClass('collapsed-content-light');
const buttons = testButtonsCollapsed();
expect(screen.queryByText(/test/)).not.toBeInTheDocument();
expect(screen.queryByText(/array/)).not.toBeInTheDocument();

fireEvent.keyDown(buttons[1], { key: 'Enter', code: 'Enter' });
buttons = screen.getAllByRole('button');
expect(buttons[0]).toHaveClass('expand-icon-light');
expect(buttons[1]).toHaveClass('collapsed-content-light');

fireEvent.keyDown(buttons[0], { key: 'Enter', code: 'Enter' });
testButtonsCollapsed();
expect(screen.queryByText(/test/)).not.toBeInTheDocument();
expect(screen.queryByText(/array/)).not.toBeInTheDocument();
});
Expand Down
16 changes: 12 additions & 4 deletions src/DataRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ function ExpandableObject({
}, [shouldExpandNode]);

const expanderIconStyle = expanded ? style.collapseIcon : style.expandIcon;
const ariaLabel = expanded ? 'collapse JSON' : 'expand JSON';
const contentsId = React.useId();
const childLevel = level + 1;
const lastIndex = data.length - 1;

Expand All @@ -78,16 +80,19 @@ function ExpandableObject({
<div className={style.basicChildStyle} role='list'>
<span
className={expanderIconStyle}
role='button'
onClick={toggleExpanded}
onKeyDown={onKeyDown}
role='button'
tabIndex={0}
aria-label={ariaLabel}
aria-expanded={expanded}
aria-controls={expanded ? contentsId : undefined}
/>
{field && <span className={style.label}>{field}:</span>}
<span className={style.punctuation}>{openBracket}</span>

{expanded ? (
<div>
<div id={contentsId}>
{data.map((dataElement, index) => (
<DataRender
key={dataElement[0] || index}
Expand All @@ -103,10 +108,13 @@ function ExpandableObject({
) : (
<span
className={style.collapsedContent}
role='button'
tabIndex={0}
onClick={toggleExpanded}
onKeyDown={onKeyDown}
role='button'
tabIndex={-1} // No need to be able to tab to this button, can just use the other button
aria-hidden={true} // No need for screen readers to see this button, they can just use the other button
aria-label={ariaLabel}
aria-expanded={expanded}
/>
)}

Expand Down

0 comments on commit 1b88419

Please sign in to comment.