Files
tasknote/client/src/__test__/views/NoteAdd.test.tsx
T
rmcamposandGitHub 5fec30fea0 feat: add SDD and DDD filer for AI based development and Spec 001 implementation (#60)
* feat: add initial files and spec 1

* feat: add spec for rich text feature

* chore: restore file from broken AI session

* feat: add project constraints to ai

* chore: update spec feature prompt

* feat: add multiple tags support - wip

* test: fix test cases

* chore: move tag list to below the inputs

* chore: add ngrok files and updates

* fix: session issues and query using HQL

* test: fix test cases
2026-05-26 11:58:04 -03:00

249 lines
7.5 KiB
TypeScript

import React, { act } from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { MemoryRouter } from 'react-router';
import { I18nextProvider } from 'react-i18next';
import NoteAdd from '../../views/NoteAdd';
import AuthContext from '../../context/AuthContext';
import i18n from '../../i18n';
import api from '../../api-service/api';
import ApiConfig from '../../api-service/apiConfig';
import { NoteResponse } from '../../types/NoteResponse';
import SidebarContext from '../../context/SidebarContext';
// Mock the entire api module
vi.mock('../../api-service/api', () => ({
default: {
postJSON: vi.fn(),
getJSON: vi.fn(),
patchJSON: vi.fn(),
}
}));
vi.mock('react-i18next', () => ({
useTranslation: () => ({
i18n: {
changeLanguage: vi.fn(),
language: 'en',
},
t: (key: string) => key,
}),
initReactI18next: {
type: '3rdParty',
init: vi.fn(),
},
I18nextProvider: ({ children }: any) => children,
}));
vi.mock('react-router', async () => {
const actual = await vi.importActual<any>('react-router');
return {
...actual,
useSearchParams: vi.fn(),
useParams: vi.fn()
};
});
import { useSearchParams, useParams } from 'react-router';
const authContextMock = {
signed: true,
user: {
userId: 1,
name: 'Ricardo',
email: 'test@example.com',
admin: false,
createdAt: new Date(),
gravatarImageUrl: 'http://url.com',
lang: 'en'
},
checkCurrentAuthUser: vi.fn(),
signIn: vi.fn(),
signOut: vi.fn(),
register: vi.fn(),
isAdmin: false,
updateUser: vi.fn(),
};
const sidebarContextMock = {
currentPage: '/home',
setNewPage: vi.fn()
};
// Mock the lang handler
vi.mock('../../lang-service/LangHandler', () => ({
handleDefaultLang: vi.fn()
}));
// Mock the translator utils
vi.mock('../../utils/TranslatorUtils', () => ({
translateServerResponse: (message: string) => message
}));
const mockedApi = vi.mocked(api);
const mockedUseParams = vi.mocked(useParams);
const mockedUseSearchParams = vi.mocked(useSearchParams);
describe('NoteAdd Component', () => {
const renderNoteAdd = () => {
return render(
<MemoryRouter>
<AuthContext.Provider value={authContextMock}>
<I18nextProvider i18n={i18n}>
<SidebarContext.Provider value={sidebarContextMock}>
<NoteAdd />
</SidebarContext.Provider>
</I18nextProvider>
</AuthContext.Provider>
</MemoryRouter>
);
};
beforeEach(() => {
// Reset mock between tests
mockedUseSearchParams.mockReturnValue([new URLSearchParams(), vi.fn()]);
mockedUseParams.mockReturnValue({});
vi.clearAllMocks();
});
it('should render the NoteAdd component', async () => {
let result: any;
await act(async () => {
result = renderNoteAdd();
});
const { getByText } = result;
expect(getByText('note_form_title_label')).toBeDefined();
expect(getByText('task_form_url_label')).toBeDefined();
expect(getByText('note_form_content_label')).toBeDefined();
expect(getByText('note_form_submit')).toBeDefined();
});
it('should show error message when form is invalid', async () => {
const { getByText, getByRole } = renderNoteAdd();
const submitButton = getByRole('button', { name: 'note_form_submit' });
fireEvent.click(submitButton);
await waitFor(() => {
expect(getByText('Please fill in all the fields')).toBeDefined();
});
});
it('should add a new note when form is valid', async () => {
mockedUseSearchParams.mockReturnValue([
new URLSearchParams("backTo=home"),
vi.fn(),
]);
const { getByLabelText, getByTestId, getByRole } = renderNoteAdd();
const descriptionInput = getByLabelText('note_form_title_label') as HTMLInputElement;
const noteContentInput = getByTestId('note-content-input-area') as HTMLAreaElement;
const submitButton = getByRole('button', { name: 'note_form_submit' });
fireEvent.change(descriptionInput, { target: { value: 'New Note' } });
fireEvent.change(noteContentInput, { target: { value: 'Note content' } });
fireEvent.click(submitButton);
await waitFor(() => {
const newNote: NoteResponse = {
id: 0,
title: 'New Note',
description: 'Note content',
url: '',
tags: [],
lastUpdate: '',
shared: false,
shareToken: null
}
expect(api.postJSON).toHaveBeenCalledWith(ApiConfig.notesUrl, newNote);
});
});
it('should render text based on new contentHeader component', async () => {
let result: any;
await act(async () => {
result = renderNoteAdd();
});
const { getByText } = result;
expect(getByText('Add')).toBeDefined();
expect(getByText('Note')).toBeDefined();
expect(getByText('Save your notes in plain text or Markdown format')).toBeDefined();
expect(getByText('Create, Filter, and Easily Find')).toBeDefined();
expect(getByText('Them')).toBeDefined();
});
it('should render a note to edit', async () => {
mockedUseParams.mockReturnValue({ id: '1' });
const toEdit: NoteResponse = {
id: 1,
title: 'Note one',
description: 'Description of note one',
url: 'http://notes.domain.com',
tags: ['dev'],
lastUpdate: '3 minutes ago',
shared: false,
shareToken: null
};
vi.spyOn(api, 'getJSON').mockResolvedValue(toEdit);
const { getByLabelText, getByTestId } = renderNoteAdd();
await waitFor(() => {
const noteTitle = getByLabelText('note_form_title_label') as HTMLInputElement;
const noteUrl = getByLabelText('task_form_url_label') as HTMLInputElement;
const noteContentInput = getByTestId('note-content-input-area') as HTMLAreaElement;
expect(noteTitle.value).toBe(toEdit.title);
expect(noteUrl.value).toBe(toEdit.url);
expect(noteContentInput.innerHTML).toBe(toEdit.description);
});
});
it('should render a cloned note', async () => {
window.history.pushState({}, '', '?cloneFrom=123');
const toClone: NoteResponse = {
id: 11,
title: 'Old title',
description: 'Old description',
url: 'http://notes.domain.com',
tags: ['dev'],
lastUpdate: '1 minute ago',
shared: false,
shareToken: null
};
vi.spyOn(api, 'getJSON').mockResolvedValue(toClone);
const { getByLabelText, getByTestId } = renderNoteAdd();
await waitFor(() => {
const noteTitle = getByLabelText('note_form_title_label') as HTMLInputElement;
const noteUrl = getByLabelText('task_form_url_label') as HTMLInputElement;
const noteContentInput = getByTestId('note-content-input-area') as HTMLAreaElement;
expect(noteTitle.value).toBe(toClone.title);
expect(noteUrl.value).toBe(toClone.url);
expect(noteContentInput.innerHTML).toBe(toClone.description);
});
});
it('should not render a cloned note when user is trying to mess up', async () => {
window.history.pushState({}, '', '?cloneFrom=12345');
const { getByLabelText, getByTestId } = renderNoteAdd();
await waitFor(() => {
const noteTitle = getByLabelText('note_form_title_label') as HTMLInputElement;
const noteUrl = getByLabelText('task_form_url_label') as HTMLInputElement;
const noteContentInput = getByTestId('note-content-input-area') as HTMLAreaElement;
expect(noteTitle.value).toBe('');
expect(noteUrl.value).toBe('');
expect(noteContentInput.innerHTML).toBe('');
});
});
});