Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -194,19 +194,105 @@ Line 3: Final line with conclusion`,
},
};

export const InteractiveActions: Story = {
export const EditAndSave: Story = {
args: defaultArgs,
parameters: {
docs: {
description: {
story: 'Hover over the message to see the action buttons (More actions menu and Mark button).',
},
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);

await userEvent.click(canvas.getByRole('button', { name: /more actions/i }));
await userEvent.click(screen.getByRole('menuitem', { name: /edit/i }));

const textarea = canvas.getByRole('textbox');
await expect(textarea).toHaveValue('This is a sample message in the comment thread.');

await userEvent.clear(textarea);
await userEvent.type(textarea, 'Updated message content');

await userEvent.click(canvas.getByRole('button', { name: /save/i }));

await expect(args.onEdit).toHaveBeenCalledWith('msg-1', 'Updated message content');
},
};

export const EditSaveDisabledWhenEmpty: Story = {
args: defaultArgs,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

await userEvent.click(canvas.getByRole('button', { name: /more actions/i }));
await userEvent.click(screen.getByRole('menuitem', { name: /edit/i }));

const textarea = canvas.getByRole('textbox');
await userEvent.clear(textarea);

const saveButton = canvas.getByRole('button', { name: /save/i });
await expect(saveButton).toBeDisabled();
},
};

export const EditSaveDisabledWhenUnchanged: Story = {
args: defaultArgs,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

await expect(canvas.getByText('This is a sample message in the comment thread.')).toBeInTheDocument();
await userEvent.click(canvas.getByRole('button', { name: /more actions/i }));
await userEvent.click(screen.getByRole('menuitem', { name: /edit/i }));

const saveButton = canvas.getByRole('button', { name: /save/i });
await expect(saveButton).toBeDisabled();
},
};

export const DeleteAction: Story = {
args: defaultArgs,
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);

await userEvent.click(canvas.getByRole('button', { name: /more actions/i }));
await userEvent.click(screen.getByRole('menuitem', { name: /delete/i }));

await expect(args.onDelete).toHaveBeenCalledWith('msg-1');
},
};

export const MarkUnreadAction: Story = {
args: defaultArgs,
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);

await userEvent.click(canvas.getByRole('button', { name: /more actions/i }));
await userEvent.click(screen.getByRole('menuitem', { name: /mark as/i }));

await expect(args.onMarkUnread).toHaveBeenCalledWith('msg-1');
},
};

export const ResolvedAction: Story = {
args: defaultArgs,
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const resolvedButton = canvas.getByRole('button', { name: /mark message as resolved/i });

await userEvent.click(resolvedButton);

await expect(args.onResolved).toHaveBeenCalledWith('msg-1');
},
};

export const NoActionsWhenCannotModify: Story = {
args: {
...defaultArgs,
canModify: false,
onEdit: undefined,
onDelete: undefined,
onMarkUnread: undefined,
onResolved: undefined,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

await expect(canvas.queryByRole('button', { name: /more actions/i })).not.toBeInTheDocument();
await expect(canvas.queryByRole('button', { name: /mark message as resolved/i })).not.toBeInTheDocument();
},
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from '@storybook/react-vite';
import { expect, fn, within } from 'storybook/test';
import { expect, fn, userEvent, within } from 'storybook/test';
import { useState } from 'react';
import { DsCommentBubble } from './index';
import type { CommentData, CommentAuthor } from '../ds-comment-card';
Expand Down Expand Up @@ -198,6 +198,151 @@ export const ThreadWithActionRequired: Story = {
},
};

export const SendButtonClick: Story = {
args: {
value: 'Test message to send',
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const sendButton = canvas.getByRole('button', { name: /send/i });

await userEvent.click(sendButton);

await expect(args.onSend).toHaveBeenCalledWith('Test message to send', false);
},
};

export const SendWithEnterKey: Story = {
args: {
value: 'Enter key message',
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const textarea = canvas.getByRole('textbox');

await userEvent.click(textarea);
await userEvent.keyboard('{Enter}');

await expect(args.onSend).toHaveBeenCalledWith('Enter key message', false);
},
};

export const SendDisabledWhenEmpty: Story = {
args: {
value: '',
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const sendButton = canvas.getByRole('button', { name: /send/i });

await expect(sendButton).toBeDisabled();
},
};

export const ThreadSendDisabledWhenEmpty: Story = {
args: {
comment: createMockComment(),
currentUser,
value: '',
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const sendButton = canvas.getByRole('button', { name: /send/i });

await expect(sendButton).toBeDisabled();
},
};

export const ThreadSendEnabled: Story = {
args: {
comment: createMockComment(),
currentUser,
value: 'A reply',
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const sendButton = canvas.getByRole('button', { name: /send/i });

await expect(sendButton).toBeEnabled();

await userEvent.click(sendButton);

await expect(args.onSend).toHaveBeenCalledWith('A reply', false);
},
};

export const ThreadCloseButton: Story = {
args: {
comment: createMockComment(),
currentUser,
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const closeButton = canvas.getByRole('button', { name: /close/i });

await userEvent.click(closeButton);

await expect(args.onClose).toHaveBeenCalledOnce();
},
};

export const ThreadResolveButton: Story = {
args: {
comment: createMockComment(),
currentUser,
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const resolveButton = canvas.getByRole('button', { name: 'Resolve' });

await userEvent.click(resolveButton);

await expect(args.onResolve).toHaveBeenCalledOnce();
},
};

export const TextareaValueChange: Story = {
args: {
comment: createMockComment(),
currentUser,
value: '',
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const textarea = canvas.getByRole('textbox', { name: /reply/i });

await userEvent.type(textarea, 'new text');

await expect(args.onValueChange).toHaveBeenCalled();
},
};

export const InitialWithReferenceTag: Story = {
args: {
referenceTag: 'My tag',
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const dialog = canvas.getByRole('dialog', { name: /add new comment/i });

await expect(dialog).toBeInTheDocument();
},
};

export const ThreadWithReferenceTag: Story = {
args: {
comment: createMockComment(),
currentUser,
referenceTag: 'Resource allocation',
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

await expect(canvas.getByText('Resource allocation')).toBeInTheDocument();
await expect(canvas.getByText('#63')).toBeInTheDocument();
},
};

export const FullInteractiveFlow: Story = {
render: function FullFlowStory() {
const [value, setValue] = useState('');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from '@storybook/react-vite';
import { expect, fn, within } from 'storybook/test';
import { expect, fn, userEvent, within } from 'storybook/test';
import { DsCommentCard } from './index';
import type { CommentData } from './ds-comment-card.types';
import styles from './ds-comment-card.stories.module.scss';
Expand Down Expand Up @@ -263,6 +263,61 @@ export const Default: Story = {
},
};

export const WithReferenceTag: Story = {
args: {
comment: createMockComment({ referenceTag: 'Resource allocation' }),
overflow: 'hidden',
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

await expect(canvas.getByText('Resource allocation')).toBeInTheDocument();
},
};

export const WithCallbacks: Story = {
args: {
comment: createMockComment(),
overflow: 'hidden',
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const card = canvas.getByRole('button', { name: /Comment #63/i });

await userEvent.click(card);

await expect(args.onClick).toHaveBeenCalledOnce();
},
};

export const SingleReply: Story = {
args: {
comment: createMockComment({
messages: [
{
id: 'msg-1',
author: { id: 'user-1', name: 'Karen J.' },
content: 'Initial message',
createdAt: new Date(Date.now() - 24 * 60 * 60 * 1000),
isInitialMessage: true,
},
{
id: 'msg-2',
author: { id: 'user-2', name: 'John D.' },
content: 'One reply',
createdAt: new Date(Date.now() - 12 * 60 * 60 * 1000),
},
],
}),
overflow: 'hidden',
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

await expect(canvas.getByText('1 reply')).toBeInTheDocument();
},
};

export const CustomFormatter: Story = {
args: {
comment: createMockComment(),
Expand Down
Loading
Loading