mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-10-29 18:28:28 -04:00
- Updated post actions menu to link directly to the edit post path. - Enhanced post form to include a React-based body editor using Tiptap, with a fallback to a plain textarea. - Added Tiptap dependencies to package.json and updated yarn.lock. - Created a feature spec to verify navigation to the edit page from the post actions menu.
108 lines
4.5 KiB
React
108 lines
4.5 KiB
React
import {render, screen, waitFor} from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import {beforeAll, describe, expect, it} from 'vitest';
|
|
|
|
import PostEditor from './PostEditor';
|
|
|
|
const hidden = (container) => container.querySelector('input[type="hidden"]');
|
|
|
|
async function setup(props = {}) {
|
|
const view = render(<PostEditor name="post[body]" {...props} />);
|
|
await screen.findByRole('toolbar', {name: 'Formatting'});
|
|
return view;
|
|
}
|
|
|
|
describe('PostEditor', () => {
|
|
// jsdom has no layout, which ProseMirror asks for when it scrolls the cursor into view.
|
|
beforeAll(() => {
|
|
const rects = () => ({length: 0, item: () => null, [Symbol.iterator]: [][Symbol.iterator]});
|
|
Range.prototype.getClientRects = rects;
|
|
Range.prototype.getBoundingClientRect = () => ({top: 0, bottom: 0, left: 0, right: 0, width: 0, height: 0});
|
|
Element.prototype.getClientRects = rects;
|
|
});
|
|
|
|
it('submits the markdown under the given name', async () => {
|
|
const {container} = await setup({value: 'Hello **world**'});
|
|
expect(hidden(container)).toHaveAttribute('name', 'post[body]');
|
|
});
|
|
|
|
it('starts with the markdown it was given', async () => {
|
|
const {container} = await setup({value: 'Hello **world**'});
|
|
expect(hidden(container)).toHaveValue('Hello **world**');
|
|
});
|
|
|
|
it('shows the markdown as formatted text', async () => {
|
|
await setup({value: '## Pick from the plants'});
|
|
expect(await screen.findByRole('heading', {level: 2, name: 'Pick from the plants'})).toBeInTheDocument();
|
|
});
|
|
|
|
it('starts empty without a value', async () => {
|
|
const {container} = await setup();
|
|
expect(hidden(container)).toHaveValue('');
|
|
});
|
|
|
|
it('opens on the Write tab', async () => {
|
|
await setup();
|
|
expect(screen.getByRole('tab', {name: 'Write'})).toHaveAttribute('aria-selected', 'true');
|
|
});
|
|
|
|
it('lists the formatting buttons', async () => {
|
|
await setup();
|
|
const names = screen.getAllByRole('button').map((b) => b.getAttribute('aria-label'));
|
|
expect(names).toEqual(['Bold', 'Italic', 'Link', 'Bulleted list', 'Quote']);
|
|
});
|
|
|
|
it('updates the markdown when a list is started', async () => {
|
|
const {container} = await setup();
|
|
await userEvent.click(screen.getByRole('button', {name: 'Bulleted list'}));
|
|
await waitFor(() => expect(hidden(container).value).toMatch(/^-/));
|
|
});
|
|
|
|
it('marks the list button pressed inside a list', async () => {
|
|
await setup({value: '- one'});
|
|
expect(await screen.findByRole('button', {name: 'Bulleted list', pressed: true})).toBeInTheDocument();
|
|
});
|
|
|
|
it('turns a paragraph into a heading from the style menu', async () => {
|
|
const {container} = await setup({value: 'Title'});
|
|
await userEvent.selectOptions(screen.getByRole('combobox', {name: 'Text style'}), 'h2');
|
|
await waitFor(() => expect(hidden(container)).toHaveValue('## Title'));
|
|
});
|
|
|
|
describe('Markdown tab', () => {
|
|
it('shows the raw markdown', async () => {
|
|
await setup({value: 'Hello **world**'});
|
|
await userEvent.click(screen.getByRole('tab', {name: 'Markdown'}));
|
|
expect(screen.getByRole('textbox', {name: 'Post body as markdown'})).toHaveValue('Hello **world**');
|
|
});
|
|
|
|
it('hides the formatting toolbar', async () => {
|
|
await setup();
|
|
await userEvent.click(screen.getByRole('tab', {name: 'Markdown'}));
|
|
expect(screen.queryByRole('toolbar')).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('updates the markdown as it is typed', async () => {
|
|
const {container} = await setup();
|
|
await userEvent.click(screen.getByRole('tab', {name: 'Markdown'}));
|
|
await userEvent.type(screen.getByRole('textbox', {name: 'Post body as markdown'}), 'plain words');
|
|
expect(hidden(container)).toHaveValue('plain words');
|
|
});
|
|
|
|
it('formats what was typed when going back to Write', async () => {
|
|
await setup();
|
|
await userEvent.click(screen.getByRole('tab', {name: 'Markdown'}));
|
|
await userEvent.type(screen.getByRole('textbox', {name: 'Post body as markdown'}), '## Seeds');
|
|
await userEvent.click(screen.getByRole('tab', {name: 'Write'}));
|
|
expect(await screen.findByRole('heading', {level: 2, name: 'Seeds'})).toBeInTheDocument();
|
|
});
|
|
|
|
it('keeps the growstuff crop link syntax', async () => {
|
|
const {container} = await setup({value: 'Grow [tomato](crop) here'});
|
|
await userEvent.click(screen.getByRole('tab', {name: 'Markdown'}));
|
|
await userEvent.click(screen.getByRole('tab', {name: 'Write'}));
|
|
expect(hidden(container)).toHaveValue('Grow [tomato](crop) here');
|
|
});
|
|
});
|
|
});
|