Skip to content
Merged
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
291 changes: 277 additions & 14 deletions src/components/HelpButton.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,8 @@ describe('HelpButton', () => {
await user.click(screen.getByRole('tab', { name: /shortcuts/i }));

await waitFor(() => {
expect(screen.getByText('Answering Questions')).toBeInTheDocument();
expect(screen.getByText('Answer Selection')).toBeInTheDocument();
expect(screen.getByText('Navigation')).toBeInTheDocument();
expect(screen.getByText('Tools')).toBeInTheDocument();
});
});

Expand All @@ -108,8 +107,8 @@ describe('HelpButton', () => {
await user.click(screen.getByRole('tab', { name: /shortcuts/i }));

await waitFor(() => {
expect(screen.getByText('Select answer A')).toBeInTheDocument();
expect(screen.getByText('Select answer B')).toBeInTheDocument();
expect(screen.getByText('Answer A')).toBeInTheDocument();
expect(screen.getByText('Answer B')).toBeInTheDocument();
expect(screen.getByText('Next question')).toBeInTheDocument();
});
});
Expand All @@ -127,27 +126,32 @@ describe('HelpButton', () => {
await user.click(screen.getByRole('tab', { name: /shortcuts/i }));

await waitFor(() => {
expect(screen.getByText('Answering Questions')).toBeInTheDocument();
expect(screen.getByText('Answer Selection')).toBeInTheDocument();
expect(screen.getByText('Navigation')).toBeInTheDocument();
});
});
});

describe('Feedback Links', () => {
it('has correct feedback forum link', async () => {
describe('Feedback Options', () => {
it('shows Report a Bug button', async () => {
const user = userEvent.setup();
renderHelpButton();

await user.click(screen.getByRole('button', { name: /open help dialog/i }));

await waitFor(() => {
const feedbackLink = screen.getByRole('link', { name: /give feedback/i });
expect(feedbackLink).toHaveAttribute(
'href',
'https://forum.openhamprep.com/c/feedback/2'
);
expect(feedbackLink).toHaveAttribute('target', '_blank');
expect(feedbackLink).toHaveAttribute('rel', 'noopener noreferrer');
expect(screen.getByRole('button', { name: /report a bug/i })).toBeInTheDocument();
});
});

it('shows Give Feedback button', async () => {
const user = userEvent.setup();
renderHelpButton();

await user.click(screen.getByRole('button', { name: /open help dialog/i }));

await waitFor(() => {
expect(screen.getByRole('button', { name: /give feedback/i })).toBeInTheDocument();
});
});

Expand All @@ -169,6 +173,265 @@ describe('HelpButton', () => {
});
});

describe('Bug Report Form', () => {
it('shows bug report form when Report a Bug is clicked', async () => {
const user = userEvent.setup();
renderHelpButton();

await user.click(screen.getByRole('button', { name: /open help dialog/i }));
await waitFor(() => {
expect(screen.getByRole('button', { name: /report a bug/i })).toBeInTheDocument();
});

await user.click(screen.getByRole('button', { name: /report a bug/i }));

await waitFor(() => {
expect(screen.getByLabelText(/title/i)).toBeInTheDocument();
expect(screen.getByLabelText(/description/i)).toBeInTheDocument();
expect(screen.getByRole('button', { name: /submit to forum/i })).toBeInTheDocument();
});
});

it('shows back button in bug report form', async () => {
const user = userEvent.setup();
renderHelpButton();

await user.click(screen.getByRole('button', { name: /open help dialog/i }));
await waitFor(() => {
expect(screen.getByRole('button', { name: /report a bug/i })).toBeInTheDocument();
});

await user.click(screen.getByRole('button', { name: /report a bug/i }));

await waitFor(() => {
expect(screen.getByRole('button', { name: /back to options/i })).toBeInTheDocument();
});
});

it('returns to options when back button is clicked', async () => {
const user = userEvent.setup();
renderHelpButton();

await user.click(screen.getByRole('button', { name: /open help dialog/i }));
await waitFor(() => {
expect(screen.getByRole('button', { name: /report a bug/i })).toBeInTheDocument();
});

await user.click(screen.getByRole('button', { name: /report a bug/i }));
await waitFor(() => {
expect(screen.getByRole('button', { name: /back to options/i })).toBeInTheDocument();
});

await user.click(screen.getByRole('button', { name: /back to options/i }));

await waitFor(() => {
expect(screen.getByRole('button', { name: /report a bug/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /give feedback/i })).toBeInTheDocument();
});
});

it('disables submit when title is empty', async () => {
const user = userEvent.setup();
renderHelpButton();

await user.click(screen.getByRole('button', { name: /open help dialog/i }));
await waitFor(() => {
expect(screen.getByRole('button', { name: /report a bug/i })).toBeInTheDocument();
});

await user.click(screen.getByRole('button', { name: /report a bug/i }));

await waitFor(() => {
expect(screen.getByRole('button', { name: /submit to forum/i })).toBeDisabled();
});
});

it('disables submit when description is empty', async () => {
const user = userEvent.setup();
renderHelpButton();

await user.click(screen.getByRole('button', { name: /open help dialog/i }));
await waitFor(() => {
expect(screen.getByRole('button', { name: /report a bug/i })).toBeInTheDocument();
});

await user.click(screen.getByRole('button', { name: /report a bug/i }));

await waitFor(() => {
expect(screen.getByLabelText(/title/i)).toBeInTheDocument();
});

await user.type(screen.getByLabelText(/title/i), 'Test bug title');

expect(screen.getByRole('button', { name: /submit to forum/i })).toBeDisabled();
});

it('enables submit when both title and description have content', async () => {
const user = userEvent.setup();
renderHelpButton();

await user.click(screen.getByRole('button', { name: /open help dialog/i }));
await waitFor(() => {
expect(screen.getByRole('button', { name: /report a bug/i })).toBeInTheDocument();
});

await user.click(screen.getByRole('button', { name: /report a bug/i }));

await waitFor(() => {
expect(screen.getByLabelText(/title/i)).toBeInTheDocument();
});

await user.type(screen.getByLabelText(/title/i), 'Test bug title');
await user.type(screen.getByLabelText(/description/i), 'Test bug description');

expect(screen.getByRole('button', { name: /submit to forum/i })).not.toBeDisabled();
});

it('opens forum URL when submit is clicked', async () => {
const mockWindow = {} as Window;
const windowOpenSpy = vi.spyOn(window, 'open').mockImplementation(() => mockWindow);
const user = userEvent.setup();
renderHelpButton();

await user.click(screen.getByRole('button', { name: /open help dialog/i }));
await waitFor(() => {
expect(screen.getByRole('button', { name: /report a bug/i })).toBeInTheDocument();
});

await user.click(screen.getByRole('button', { name: /report a bug/i }));

await waitFor(() => {
expect(screen.getByLabelText(/title/i)).toBeInTheDocument();
});

await user.type(screen.getByLabelText(/title/i), 'Test bug');
await user.type(screen.getByLabelText(/description/i), 'Bug description');
await user.click(screen.getByRole('button', { name: /submit to forum/i }));

expect(windowOpenSpy).toHaveBeenCalledOnce();
expect(windowOpenSpy).toHaveBeenCalledWith(
expect.stringMatching(/https:\/\/forum\.openhamprep\.com\/new-topic.*tags=bug/),
'_blank',
'noopener,noreferrer'
);

windowOpenSpy.mockRestore();
});

it('resets form after submit', async () => {
const windowOpenSpy = vi.spyOn(window, 'open').mockImplementation(() => null);
const user = userEvent.setup();
renderHelpButton();

await user.click(screen.getByRole('button', { name: /open help dialog/i }));
await waitFor(() => {
expect(screen.getByRole('button', { name: /report a bug/i })).toBeInTheDocument();
});

await user.click(screen.getByRole('button', { name: /report a bug/i }));

await waitFor(() => {
expect(screen.getByLabelText(/title/i)).toBeInTheDocument();
});

await user.type(screen.getByLabelText(/title/i), 'Test bug');
await user.type(screen.getByLabelText(/description/i), 'Bug description');
await user.click(screen.getByRole('button', { name: /submit to forum/i }));

// Form should reset and return to options view after submit
await waitFor(() => {
expect(screen.getByRole('button', { name: /report a bug/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /give feedback/i })).toBeInTheDocument();
});

windowOpenSpy.mockRestore();
});
});

describe('Feedback Form', () => {
it('shows feedback form when Give Feedback is clicked', async () => {
const user = userEvent.setup();
renderHelpButton();

await user.click(screen.getByRole('button', { name: /open help dialog/i }));
await waitFor(() => {
expect(screen.getByRole('button', { name: /give feedback/i })).toBeInTheDocument();
});

await user.click(screen.getByRole('button', { name: /give feedback/i }));

await waitFor(() => {
expect(screen.getByLabelText(/title/i)).toBeInTheDocument();
expect(screen.getByLabelText(/description/i)).toBeInTheDocument();
expect(screen.getByRole('button', { name: /submit to forum/i })).toBeInTheDocument();
});
});

it('opens forum URL with feature tag when feedback is submitted', async () => {
const mockWindow = {} as Window;
const windowOpenSpy = vi.spyOn(window, 'open').mockImplementation(() => mockWindow);
const user = userEvent.setup();
renderHelpButton();

await user.click(screen.getByRole('button', { name: /open help dialog/i }));
await waitFor(() => {
expect(screen.getByRole('button', { name: /give feedback/i })).toBeInTheDocument();
});

await user.click(screen.getByRole('button', { name: /give feedback/i }));

await waitFor(() => {
expect(screen.getByLabelText(/title/i)).toBeInTheDocument();
});

await user.type(screen.getByLabelText(/title/i), 'Feature idea');
await user.type(screen.getByLabelText(/description/i), 'Feature description');
await user.click(screen.getByRole('button', { name: /submit to forum/i }));

expect(windowOpenSpy).toHaveBeenCalledOnce();
expect(windowOpenSpy).toHaveBeenCalledWith(
expect.stringMatching(/https:\/\/forum\.openhamprep\.com\/new-topic.*tags=feature/),
'_blank',
'noopener,noreferrer'
);

windowOpenSpy.mockRestore();
});
});

describe('Form Reset', () => {
it('resets form when dialog is closed', async () => {
const user = userEvent.setup();
renderHelpButton();

// Open dialog and fill bug form
await user.click(screen.getByRole('button', { name: /open help dialog/i }));
await waitFor(() => {
expect(screen.getByRole('button', { name: /report a bug/i })).toBeInTheDocument();
});

await user.click(screen.getByRole('button', { name: /report a bug/i }));
await waitFor(() => {
expect(screen.getByLabelText(/title/i)).toBeInTheDocument();
});

await user.type(screen.getByLabelText(/title/i), 'Test title');
await user.type(screen.getByLabelText(/description/i), 'Test description');

// Close dialog by clicking outside or pressing escape
await user.keyboard('{Escape}');

// Re-open dialog
await user.click(screen.getByRole('button', { name: /open help dialog/i }));

// Should show options view, not the form
await waitFor(() => {
expect(screen.getByRole('button', { name: /report a bug/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /give feedback/i })).toBeInTheDocument();
});
});
});

describe('Keyboard Shortcut Display', () => {
it('displays keys in kbd elements when Shortcuts tab is selected', async () => {
const user = userEvent.setup();
Expand Down
Loading
Loading