Skip to content

Commit

Permalink
MNT LinkField Jest tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Sabina Talipova committed Feb 14, 2024
1 parent 2bf91ca commit 62f2c2b
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 41 deletions.
69 changes: 61 additions & 8 deletions client/src/components/LinkField/tests/LinkField-test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* global jest, test, expect, document */
import React from 'react';
import { render, act, screen } from '@testing-library/react';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom';
import { Component as LinkField } from '../LinkField';
Expand Down Expand Up @@ -57,6 +57,61 @@ function makeProps(obj = {}) {
};
}

test('LinkField returns list of links if they exist', async () => {
const { container } = render(<LinkField {...makeProps({
isMulti: true,
value: [1, 2],
types: {
sitetree: { key: 'sitetree', title: 'Page', icon: 'font-icon-page', allowed: true },
email: { key: 'email', title: 'Email', icon: 'font-icon-email', allowed: true },
},
})}
/>);

await doResolve({ json: () => ({
1: {
Title: 'Page title',
typeKey: 'sitetree',
},
2: {
Title: 'Email title',
typeKey: 'email',
},
}) });

await waitFor(() => {
expect(container.querySelectorAll('.link-picker__button')).toHaveLength(2);
expect(container.querySelectorAll('.link-picker__button.font-icon-page')[0]).toHaveTextContent('Page title');
expect(container.querySelectorAll('.link-picker__button.font-icon-email')[0]).toHaveTextContent('Email title');
});
});

test('LinkField will render disabled state if disabled is true', async () => {
const { container } = render(<LinkField {...makeProps({
ownerID: 1,
disabled: true
})}
/>);
doResolve();
await waitFor(() => {
expect(container.querySelectorAll('.link-picker')).toHaveLength(1);
expect(container.querySelectorAll('.link-picker')[0]).toHaveTextContent('Cannot create link');
});
});

test('LinkField will render readonly state if readonly is true', async () => {
const { container } = render(<LinkField {...makeProps({
ownerID: 1,
readonly: true
})}
/>);
doResolve();
await waitFor(() => {
expect(container.querySelectorAll('.link-picker')).toHaveLength(1);
expect(container.querySelectorAll('.link-picker')[0]).toHaveTextContent('Cannot create link');
});
});

test('LinkField tab order', async () => {
const user = userEvent.setup();
const { container } = render(<LinkField {...makeProps({
Expand Down Expand Up @@ -135,11 +190,9 @@ test('LinkField will render link-picker if ownerID is not 0 and has finished loa
})}
/>);
doResolve();
// Short wait - we can't use screen.find* because we're waiting for something to be removed, not added to the DOM
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 100));
});
expect(container.querySelectorAll('.link-field__save-record-first')).toHaveLength(0);
expect(container.querySelectorAll('.link-field__loading')).toHaveLength(0);
expect(container.querySelectorAll('.link-picker')).toHaveLength(1);
await waitFor(() => {
expect(container.querySelectorAll('.link-field__save-record-first')).toHaveLength(0);
expect(container.querySelectorAll('.link-field__loading')).toHaveLength(0);
expect(container.querySelectorAll('.link-picker')).toHaveLength(1);
}, { timeout: 100 });
});
18 changes: 11 additions & 7 deletions client/src/components/LinkPicker/tests/LinkPicker-test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* global jest, test */
import React from 'react';
import { render, fireEvent, act } from '@testing-library/react';
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom';
import { LinkFieldContext } from 'components/LinkField/LinkField';
import LinkPicker from '../LinkPicker';

Expand All @@ -22,6 +24,7 @@ test('LinkPickerMenu render() should display toggle if can create', () => {
<LinkPicker {...makeProps({ canCreate: true })} />
</LinkFieldContext.Provider>);
expect(container.querySelectorAll('.link-picker__menu-toggle')).toHaveLength(1);
expect(container.querySelector('.link-picker__menu-toggle')).toHaveTextContent('Add Link');
expect(container.querySelectorAll('.link-picker__cannot-create')).toHaveLength(0);
});

Expand All @@ -31,6 +34,7 @@ test('LinkPickerMenu render() should display cannot create message if cannot cre
</LinkFieldContext.Provider>);
expect(container.querySelectorAll('.link-picker__menu-toggle')).toHaveLength(0);
expect(container.querySelectorAll('.link-picker__cannot-create')).toHaveLength(1);
expect(container.querySelector('.link-picker__cannot-create')).toHaveTextContent('Cannot create link');
});

test('LinkPickerMenu render() should display cannot create message if types is empty', () => {
Expand Down Expand Up @@ -60,18 +64,18 @@ test('LinkPickerMenu should open dropdown on click when not loading', async () =
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPicker {...makeProps()} />
</LinkFieldContext.Provider>);
await act(async () => {
await fireEvent.click(container.querySelector('button.link-picker__menu-toggle'));
userEvent.click(container.querySelector('button.link-picker__menu-toggle'));
await waitFor(() => {
expect(container.querySelectorAll('.dropdown-menu.show')).toHaveLength(1);
});
expect(container.querySelectorAll('.dropdown-menu.show')).toHaveLength(1);
});

test('LinkPickerMenu should not open dropdown on click while loading', async () => {
const { container } = render(<LinkFieldContext.Provider value={{ loading: true }}>
<LinkPicker {...makeProps()} />
</LinkFieldContext.Provider>);
await act(async () => {
await fireEvent.click(container.querySelector('button.link-picker__menu-toggle'));
userEvent.click(container.querySelector('button.link-picker__menu-toggle'));
await waitFor(() => {
expect(container.querySelectorAll('.dropdown-menu.show')).toHaveLength(0);
});
expect(container.querySelectorAll('.dropdown-menu.show')).toHaveLength(0);
});
73 changes: 73 additions & 0 deletions client/src/components/LinkPicker/tests/LinkPickerMenu-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* global jest, test */

import React from 'react';
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom';
import { LinkFieldContext } from 'components/LinkField/LinkField';
import LinkPickerMenu from '../LinkPickerMenu';

function makeProps(obj = {}) {
return {
types: [
{ key: 'sitetree', title: 'Page', icon: 'font-icon-page', allowed: true },
{ key: 'external', title: 'External URL', icon: 'font-icon-link', allowed: true },
{ key: 'email', title: 'Email', icon: 'font-icon-email', allowed: true },
{ key: 'phone', title: 'Phone', icon: 'font-icon-phone', allowed: true },
],
onSelect: jest.fn(),
onKeyDownEdit: jest.fn(),
...obj
};
}

test('LinkPickerMenu render() should display link list', () => {
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPickerMenu {...makeProps()} />
</LinkFieldContext.Provider>);
expect(container.querySelectorAll('.dropdown-item')).toHaveLength(4);
expect(container.querySelectorAll('.dropdown-item')[0]).toHaveTextContent('Page');
expect(container.querySelectorAll('.dropdown-item')[1]).toHaveTextContent('External URL');
expect(container.querySelectorAll('.dropdown-item')[2]).toHaveTextContent('Email');
expect(container.querySelectorAll('.dropdown-item')[3]).toHaveTextContent('Phone');
});

test('LinkPickerMenu render() should display link list with allowed SiteTreeLink and EmailLink', () => {
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPickerMenu {...makeProps(
{ types: [
{ key: 'sitetree', title: 'Page', icon: 'font-icon-page', allowed: true },
{ key: 'email', title: 'Email', icon: 'font-icon-email', allowed: true },
{ key: 'phone', title: 'Phone', icon: 'font-icon-phone', allowed: false },
{ key: 'external', title: 'External URL', icon: 'font-icon-link', allowed: false },
] })}
/>
</LinkFieldContext.Provider>);
expect(container.querySelectorAll('.dropdown-item')).toHaveLength(2);
expect(container.querySelectorAll('.dropdown-item')[0]).toHaveTextContent('Page');
expect(container.querySelectorAll('.dropdown-item')[0].firstChild).toHaveClass('font-icon-page');
expect(container.querySelectorAll('.dropdown-item')[1]).toHaveTextContent('Email');
expect(container.querySelectorAll('.dropdown-item')[1].firstChild).toHaveClass('font-icon-email');
});

test('LinkPickerMenu onSelect() should call onSelect with selected type', async () => {
const onSelect = jest.fn();
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPickerMenu {...makeProps({ onSelect })} />
</LinkFieldContext.Provider>);
userEvent.click(container.querySelectorAll('.dropdown-item')[1]);
await waitFor(() => {
expect(onSelect).toHaveBeenCalledTimes(1);
expect(onSelect).toHaveBeenCalledWith('external');
});
});

test('LinkPickerMenu onKeyDownEdit() should call onKeyDownEdit with selected type', async () => {
const onKeyDownEdit = jest.fn();
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPickerMenu {...makeProps({ onKeyDownEdit })} />
</LinkFieldContext.Provider>);
container.querySelector('.dropdown-item').focus();
userEvent.keyboard('{enter}');
await waitFor(() => expect(onKeyDownEdit).toHaveBeenCalledTimes(1));
});
91 changes: 74 additions & 17 deletions client/src/components/LinkPicker/tests/LinkPickerTitle-test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/* global jest, test */

import React, { createRef } from 'react';
import { render, fireEvent } from '@testing-library/react';
import { render, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom';
import { LinkFieldContext } from 'components/LinkField/LinkField';
import LinkPickerTitle from '../LinkPickerTitle';

Expand Down Expand Up @@ -30,11 +32,26 @@ function makeProps(obj = {}) {
};
}

test('LinkPickerTitle render() should display link type title and link type icon', () => {
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPickerTitle {...makeProps({ canDelete: false })} />
</LinkFieldContext.Provider>);
expect(container.querySelectorAll('.link-picker__title')).toHaveLength(1);
expect(container.querySelector('.link-picker__title')).toHaveTextContent('My title');
expect(container.querySelectorAll('.font-icon-phone')).toHaveLength(1);
expect(container.querySelector('.link-picker__type')).toHaveTextContent('Phone');
expect(container.querySelector('.link-picker__url')).toHaveTextContent('My description');
expect(container.querySelector('.link-picker__title > .badge')).toHaveTextContent('Draft');
expect(container.querySelectorAll('.link-picker__title > .status-draft')).toHaveLength(1);
});

test('LinkPickerTitle render() should display clear button if can delete', () => {
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPickerTitle {...makeProps({ canDelete: true })} />
</LinkFieldContext.Provider>);
expect(container.querySelectorAll('.link-picker__delete')).toHaveLength(1);
expect(container.querySelector('.link-picker__delete')).toHaveTextContent('Archive');
expect(container.querySelector('.link-picker__delete').getAttribute('aria-label')).toBe('Archive');
expect(container.querySelectorAll('.font-icon-phone')).toHaveLength(1);
});

Expand All @@ -59,13 +76,6 @@ test('LinkPickerTitle render() should not display clear button if disabled', ()
expect(container.querySelectorAll('.link-picker__delete')).toHaveLength(0);
});

test('LinkPickerTitle render() should display link type icon', () => {
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPickerTitle {...makeProps({ canDelete: false })} />
</LinkFieldContext.Provider>);
expect(container.querySelectorAll('.font-icon-phone')).toHaveLength(1);
});

test('LinkPickerTitle delete button should fire the onDelete callback when not loading', async () => {
const mockOnDelete = jest.fn();
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
Expand All @@ -75,11 +85,13 @@ test('LinkPickerTitle delete button should fire the onDelete callback when not l
})}
/>
</LinkFieldContext.Provider>);
fireEvent.click(container.querySelector('.link-picker__delete'));
expect(mockOnDelete).toHaveBeenCalledTimes(1);
userEvent.click(container.querySelector('.link-picker__delete'));
await waitFor(() => {
expect(mockOnDelete).toHaveBeenCalledTimes(1);
});
});

test('LinkPickerTitle delete button should not fire the onDelete callback while loading', () => {
test('LinkPickerTitle delete button should not fire the onDelete callback while loading', async () => {
const mockOnDelete = jest.fn();
const { container } = render(<LinkFieldContext.Provider value={{ loading: true }}>
<LinkPickerTitle {...makeProps({
Expand All @@ -88,26 +100,32 @@ test('LinkPickerTitle delete button should not fire the onDelete callback while
})}
/>
</LinkFieldContext.Provider>);
fireEvent.click(container.querySelector('.link-picker__delete'));
expect(mockOnDelete).toHaveBeenCalledTimes(0);
userEvent.click(container.querySelector('.link-picker__delete'));
await waitFor(() => {
expect(mockOnDelete).toHaveBeenCalledTimes(0);
});
});

test('LinkPickerTitle main button should fire the onClick callback when not loading', async () => {
const mockOnClick = jest.fn();
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPickerTitle {...makeProps({ onClick: mockOnClick })} />
</LinkFieldContext.Provider>);
fireEvent.click(container.querySelector('.link-picker__button'));
expect(mockOnClick).toHaveBeenCalledTimes(1);
userEvent.click(container.querySelector('.link-picker__button'));
await waitFor(() => {
expect(mockOnClick).toHaveBeenCalledTimes(1);
});
});

test('LinkPickerTitle main button should not fire the onClick callback while loading', async () => {
const mockOnClick = jest.fn();
const { container } = render(<LinkFieldContext.Provider value={{ loading: true }}>
<LinkPickerTitle {...makeProps({ onClick: mockOnClick })} />
</LinkFieldContext.Provider>);
fireEvent.click(container.querySelector('.link-picker__button'));
expect(mockOnClick).toHaveBeenCalledTimes(0);
userEvent.click(container.querySelector('.link-picker__button'));
await waitFor(() => {
expect(mockOnClick).toHaveBeenCalledTimes(0);
});
});

test('LinkPickerTitle render() should have readonly class if set to readonly', () => {
Expand Down Expand Up @@ -137,3 +155,42 @@ test('LinkPickerTitle render() should not have disabled class if set to disabled
</LinkFieldContext.Provider>);
expect(container.querySelectorAll('.link-picker__link--disabled')).toHaveLength(0);
});

test('dnd handler is displayed on LinkPickerTitle on MultiLinkField', () => {
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPickerTitle {...makeProps({ disabled: false, readonly: false, isMulti: true })} />
</LinkFieldContext.Provider>);
expect(container.querySelectorAll('.link-picker__drag-handle')).toHaveLength(1);
});

test('dnd handler is not displayed if link field is disabled', () => {
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPickerTitle {...makeProps({ disabled: true, readonly: false, isMulti: true })} />
</LinkFieldContext.Provider>);
expect(container.querySelectorAll('.link-picker__drag-handle')).toHaveLength(0);
});

test('dnd handler is not displayed if link field is readonly', () => {
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPickerTitle {...makeProps({ disabled: false, readonly: true, isMulti: true })} />
</LinkFieldContext.Provider>);
expect(container.querySelectorAll('.link-picker__drag-handle')).toHaveLength(0);
});

test('dnd handler is not displayed if link field is not MultiLinkField', () => {
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPickerTitle {...makeProps({ disabled: false, readonly: false, isMulti: false })} />
</LinkFieldContext.Provider>);
expect(container.querySelectorAll('.link-picker__drag-handle')).toHaveLength(0);
});

test('keydown on dnd handler', async () => {
const { container } = render(<LinkFieldContext.Provider value={{ loading: false }}>
<LinkPickerTitle {...makeProps({ isMulti: true })}/>
</LinkFieldContext.Provider>);
expect(container.querySelectorAll('.link-picker__drag-handle')).toHaveLength(1);
container.querySelector('.link-picker__drag-handle').focus();
fireEvent.keyDown(document.activeElement || document.body, { key: 'Enter', code: 'Enter', charCode: 13 });
expect(container.querySelector('.link-picker__drag-handle').getAttribute('aria-pressed')).toBe('true');
expect(container.querySelector('.link-picker__drag-handle').getAttribute('aria-label')).toBe('Sort Links');
});
9 changes: 0 additions & 9 deletions client/src/tests/sample-test.js

This file was deleted.

0 comments on commit 62f2c2b

Please sign in to comment.