Files
remark42/frontend/app/components/comment/comment.test.tsx
T
2022-05-10 14:47:34 -05:00

259 lines
6.5 KiB
TypeScript

import { h } from 'preact';
import '@testing-library/jest-dom';
import { fireEvent, screen, waitFor } from '@testing-library/preact';
import { useIntl, IntlShape } from 'react-intl';
import { render } from 'tests/utils';
import { StaticStore } from 'common/static-store';
import { Comment, CommentProps } from './comment';
import { CommentMode } from 'common/types';
function CommentWithIntl(props: CommentProps) {
const intl = useIntl();
return <Comment {...props} intl={intl} />;
}
function getProps(): CommentProps {
return {
isCommentsDisabled: false,
theme: 'light',
post_info: {
url: 'http://localhost/post/1',
count: 2,
read_only: false,
},
view: 'main',
data: {
id: 'comment_id',
text: 'test comment',
vote: 0,
time: new Date().toString(),
pid: 'parent_id',
score: 0,
voted_ips: [],
locator: {
url: 'somelocatorurl',
site: 'remark',
},
user: {
id: 'someone',
picture: 'http://localhost/somepicture-url',
name: 'username',
ip: '',
admin: false,
block: false,
verified: false,
},
},
user: {
id: 'testuser',
picture: 'http://localhost/testuser-url',
name: 'test',
ip: '',
admin: false,
block: false,
verified: false,
},
intl: {} as IntlShape,
};
}
describe('<Comment />', () => {
let props = getProps();
beforeEach(() => {
props = getProps();
});
it('should render patreon subscriber icon', async () => {
const props = getProps();
props.data.user.paid_sub = true;
render(<CommentWithIntl {...props} />);
const patreonSubscriberIcon = await screen.findByAltText('Patreon Paid Subscriber');
expect(patreonSubscriberIcon).toBeVisible();
expect(patreonSubscriberIcon.tagName).toBe('IMG');
});
describe('verification', () => {
it('should render active verification icon', () => {
props.data.user.verified = true;
render(<CommentWithIntl {...props} />);
expect(screen.getByTitle('Verified user')).toBeVisible();
});
it('should not render verification icon', () => {
const props = getProps();
render(<CommentWithIntl {...props} />);
expect(screen.queryByTitle('Verified user')).not.toBeInTheDocument();
});
it('should render verification button for admin', () => {
props.user!.admin = true;
render(<CommentWithIntl {...props} />);
expect(screen.getByTitle('Toggle verification')).toBeVisible();
});
it('should render active verification icon for admin', () => {
props.user!.admin = true;
props.data.user.verified = true;
render(<CommentWithIntl {...props} />);
expect(screen.queryByTitle('Verified user')).toBeVisible();
});
});
describe('voting', () => {
let props = getProps();
beforeEach(() => {
props = getProps();
});
it('should render vote component', () => {
render(<CommentWithIntl {...props} />);
expect(screen.getByTitle('Votes score')).toBeVisible();
});
it.each([
[
'when the comment is pinned',
() => {
props.view = 'pinned';
},
],
[
'when rendered in profile',
() => {
props.view = 'user';
},
],
[
'when rendered in preview',
() => {
props.view = 'preview';
},
],
[
'when post is read only',
() => {
props.post_info!.read_only = true;
},
],
[
'when comment was deleted',
() => {
props.data.delete = true;
},
],
[
'on current user comments',
() => {
props.user!.id = 'testuser';
props.data.user.id = 'testuser';
},
],
[
'for guest users',
() => {
props.user = null;
},
],
[
'for anonymous users',
() => {
props.user!.id = 'anonymous_1';
},
],
])('should not render vote component %s', (_, action) => {
action();
render(<CommentWithIntl {...props} />);
expect(screen.queryByText('Votes score')).not.toBeInTheDocument();
});
});
it('should render action buttons', () => {
render(<CommentWithIntl {...props} />);
expect(screen.getByText('Reply')).toBeVisible();
});
it.each([
[
'pinned',
() => {
props.view = 'pinned';
},
],
[
'deleted',
() => {
props.data.delete = true;
},
],
[
'collapsed',
() => {
props.collapsed = true;
},
],
])('should not render actions when comment is %s', (_, mutateProps) => {
mutateProps();
render(<CommentWithIntl {...props} />);
expect(screen.queryByTitle('Reply')).not.toBeInTheDocument();
});
it('should be editable', async () => {
StaticStore.config.edit_duration = 300;
props.repliesCount = 0;
props.user!.id = '100';
props.data.user.id = '100';
Object.assign(props.data, {
id: '101',
vote: 1,
time: Date.now(),
delete: false,
orig: 'test',
});
render(<CommentWithIntl {...props} />);
expect(screen.getByText('Edit')).toBeVisible();
});
it('should not be editable', () => {
StaticStore.config.edit_duration = 300;
Object.assign(props.data, {
user: props.user,
id: '100',
vote: 1,
time: new Date(new Date().getDate() - 300).toString(),
orig: 'test',
});
render(<CommentWithIntl {...props} />);
expect(screen.queryByRole('timer')).not.toBeInTheDocument();
});
it('toggles edit mode', async () => {
props = getProps();
props.repliesCount = 0;
props.data.user = props.user!;
props.data.time = new Date().toString();
props.setReplyEditState = jest.fn().mockImplementation(() => {
props.editMode = props.editMode === undefined ? CommentMode.Edit : CommentMode.None;
});
StaticStore.config.edit_duration = 300;
const { rerender } = render(<CommentWithIntl {...props} />);
fireEvent(screen.getByText('Edit'), new MouseEvent('click', { bubbles: true }));
rerender(<CommentWithIntl {...props} />);
await waitFor(() => {
expect(screen.getByText('Cancel')).toBeVisible();
});
fireEvent(screen.getByText('Cancel'), new MouseEvent('click', { bubbles: true }));
rerender(<CommentWithIntl {...props} />);
await waitFor(() => {
expect(screen.getByText('Edit')).toBeVisible();
});
});
});