grafana/public/app/core/components/Page/EditableTitle.test.tsx
Ashley Harrison 10adebd7b3
Page: Add inline rename functionality (#68828)
* initial attempt at inline rename

* handle version correctly

* refactor

* minor tweaks

* add unit tests

* prettier...

* add to other tabs, remove settings tab when feature toggle is enabled

* fix truncation

* allow title to span full width of page

* fix h1 styling when no renderTitle/onEditTitle is present

* better layout

* use input from grafana/ui, fix imports

* fix unit test

* better error handling

* don't use autosavefield

* undo changes to AutoSaveField

* remove timeout

* remove maxWidth now we're not using AutoSaveField

* rename isEditInProgress to isLoading

* sync localValue with value

* better responsive css
2023-05-31 17:03:54 +01:00

148 lines
4.9 KiB
TypeScript

import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { FetchError } from '@grafana/runtime';
import { EditableTitle } from './EditableTitle';
describe('EditableTitle', () => {
let user: ReturnType<typeof userEvent.setup>;
const value = 'Test';
beforeEach(() => {
jest.useFakeTimers();
user = userEvent.setup({ delay: null });
jest.clearAllMocks();
});
afterEach(() => {
jest.useRealTimers();
});
const mockEdit = jest.fn().mockImplementation((newValue: string) => Promise.resolve(newValue));
it('displays the provided text correctly', () => {
render(<EditableTitle value={value} onEdit={mockEdit} />);
expect(screen.getByRole('heading', { name: value })).toBeInTheDocument();
});
it('displays an edit button', () => {
render(<EditableTitle value={value} onEdit={mockEdit} />);
expect(screen.getByRole('button', { name: 'Edit title' })).toBeInTheDocument();
});
it('clicking the edit button changes the text to an input and autofocuses', async () => {
render(<EditableTitle value={value} onEdit={mockEdit} />);
expect(screen.queryByRole('textbox')).not.toBeInTheDocument();
const editButton = screen.getByRole('button', { name: 'Edit title' });
await user.click(editButton);
expect(screen.getByRole('textbox')).toBeInTheDocument();
expect(screen.queryByRole('button', { name: 'Edit title' })).not.toBeInTheDocument();
expect(document.activeElement).toBe(screen.getByRole('textbox'));
});
it('blurring the input calls the onEdit callback and reverts back to text', async () => {
render(<EditableTitle value={value} onEdit={mockEdit} />);
const editButton = screen.getByRole('button', { name: 'Edit title' });
await user.click(editButton);
const input = screen.getByRole('textbox');
await user.clear(input);
await user.type(input, 'New value');
await user.click(document.body);
expect(mockEdit).toHaveBeenCalledWith('New value');
act(() => {
jest.runAllTimers();
});
await waitFor(() => {
expect(screen.queryByRole('textbox')).not.toBeInTheDocument();
expect(screen.getByRole('heading')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Edit title' })).toBeInTheDocument();
});
});
it('pressing enter calls the onEdit callback and reverts back to text', async () => {
render(<EditableTitle value={value} onEdit={mockEdit} />);
const editButton = screen.getByRole('button', { name: 'Edit title' });
await user.click(editButton);
const input = screen.getByRole('textbox');
await user.clear(input);
await user.type(input, 'New value');
await user.keyboard('{enter}');
expect(mockEdit).toHaveBeenCalledWith('New value');
act(() => {
jest.runAllTimers();
});
await waitFor(() => {
expect(screen.queryByRole('textbox')).not.toBeInTheDocument();
expect(screen.getByRole('heading')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Edit title' })).toBeInTheDocument();
});
});
it('displays an error message when attempting to save an empty value', async () => {
render(<EditableTitle value={value} onEdit={mockEdit} />);
const editButton = screen.getByRole('button', { name: 'Edit title' });
await user.click(editButton);
const input = screen.getByRole('textbox');
await user.clear(input);
await user.keyboard('{enter}');
expect(screen.getByText('Please enter a title')).toBeInTheDocument();
});
it('displays a regular error message', async () => {
const mockEditError = jest.fn().mockImplementation(() => {
throw new Error('Uh oh spaghettios');
});
render(<EditableTitle value={value} onEdit={mockEditError} />);
const editButton = screen.getByRole('button', { name: 'Edit title' });
await user.click(editButton);
const input = screen.getByRole('textbox');
await user.clear(input);
await user.type(input, 'New value');
await user.keyboard('{enter}');
expect(screen.getByText('Uh oh spaghettios')).toBeInTheDocument();
});
it('displays a detailed fetch error message', async () => {
const mockEditError = jest.fn().mockImplementation(() => {
const fetchError: FetchError = {
status: 500,
config: {
url: '',
},
data: {
message: 'Uh oh spaghettios a fetch error',
},
};
throw fetchError;
});
render(<EditableTitle value={value} onEdit={mockEditError} />);
const editButton = screen.getByRole('button', { name: 'Edit title' });
await user.click(editButton);
const input = screen.getByRole('textbox');
await user.clear(input);
await user.type(input, 'New value');
await user.keyboard('{enter}');
expect(screen.getByText('Uh oh spaghettios a fetch error')).toBeInTheDocument();
});
});