Compare commits

...

7 Commits

Author SHA1 Message Date
79289457c9 39% but error 2024-10-19 10:57:44 +03:00
5f386c0f4e some progress 2024-10-19 10:48:21 +03:00
33c8f863a1 AccountButton done 2024-10-19 10:28:37 +03:00
Nikolai Petukhov
dd16f42995 working tests 2024-10-19 10:13:06 +03:00
f3e93bae19 coverage 2024-10-19 08:44:11 +03:00
07728cbbb0 tests 2024-10-19 08:16:51 +03:00
17697d7f77 tests 2024-10-19 07:48:30 +03:00
20 changed files with 4732 additions and 632 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
node_modules
.idea
.idea
coverage/

1
__mocks__/fileMock.js Normal file
View File

@ -0,0 +1 @@
module.exports = 'test-file-stub';

View File

@ -0,0 +1,11 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import AccountButtons from '../src/components/account/AccountButtons.jsx';
describe('AccountButtons Component', () => {
it('should render the Back link', () => {
render(<AccountButtons registered={false} />);
const backLinkElement = screen.getByRole('link', { name: /back/i });
expect(backLinkElement).toBeInTheDocument();
});
});

View File

@ -0,0 +1,18 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import ActionButton from '../src/components/account/ActionButton.jsx';
describe('ActionButton Component', () => {
it('should render with the correct title and call the action when clicked', () => {
const mockAction = jest.fn();
const title = 'Click Me';
render(<ActionButton action={mockAction} title={title} />);
const buttonElement = screen.getByText(title);
expect(buttonElement).toBeInTheDocument();
fireEvent.click(buttonElement);
expect(mockAction).toHaveBeenCalledTimes(1);
});
});

23
__tests__/Card.test.tsx Normal file
View File

@ -0,0 +1,23 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import Card from '../src/components/home/Card.jsx';
describe('Card Component', () => {
it('should render the Card component with the given ID', () => {
const testId = '123';
render(<Card id={testId} color={"FFA500FF"}/>);
const cardElement = screen.getByText(/123/i);
expect(cardElement).toBeInTheDocument();
});
it('should store the ID in local storage when clicked', () => {
const testId = '456';
render(<Card id={testId} color={"FFA500FF"}/>);
const cardElement = screen.getByText(/456/i);
fireEvent.click(cardElement);
expect(localStorage.setItem).toHaveBeenCalledWith('selectedId', testId);
});
});

View File

@ -0,0 +1,24 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import HelloItem from '../src/components/account/HelloItem.jsx';
describe('HelloItem Component', () => {
it('should display a personalized greeting when nickname is provided', () => {
const nickname = 'JohnDoe';
const id = '12345';
render(<HelloItem nickname={nickname} id={id} />);
const greetingElement = screen.getByText(`Hello, ${nickname}!`);
const idElement = screen.getByText(`Your ID: ${id}`);
expect(greetingElement).toBeInTheDocument();
expect(idElement).toBeInTheDocument();
});
it('should display a default message when nickname is not provided', () => {
render(<HelloItem nickname="" id="12345" />);
const defaultMessage = screen.getByText("You don't have an account :(");
expect(defaultMessage).toBeInTheDocument();
});
});

60
__tests__/Home.test.jsx Normal file
View File

@ -0,0 +1,60 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import { Provider } from "react-redux";
import configureStore from "redux-mock-store";
import Home from "src/pages/Home";
import { useGetChatsQuery } from "src/backend/redux/api_slice";
// Mock Redux store
const mockStore = configureStore([]);
// Mock the useGetChatsQuery hook
jest.mock("src/backend/redux/api_slice", () => ({
useGetChatsQuery: jest.fn(),
}));
describe("Home Page", () => {
let store;
beforeEach(() => {
store = mockStore({});
});
test("renders Home page with loading state", () => {
useGetChatsQuery.mockReturnValue({ isLoading: true });
render(
<Provider store={store}>
<Home />
</Provider>
);
expect(screen.getByText(/loading/i)).toBeInTheDocument();
});
test("renders Home page with chat data", () => {
const chatsData = [{ id: 1, name: "Chat 1" }, { id: 2, name: "Chat 2" }];
useGetChatsQuery.mockReturnValue({ data: chatsData, isLoading: false });
render(
<Provider store={store}>
<Home />
</Provider>
);
expect(screen.getByText("Chat 1")).toBeInTheDocument();
expect(screen.getByText("Chat 2")).toBeInTheDocument();
});
test("renders error message when fetching chats fails", () => {
useGetChatsQuery.mockReturnValue({ error: true, isLoading: false });
render(
<Provider store={store}>
<Home />
</Provider>
);
expect(screen.getByText(/error/i)).toBeInTheDocument();
});
});

View File

@ -0,0 +1,41 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import InputField from '../src/components/reg/InputField.jsx';
describe('InputField Component', () => {
it('should render with the correct title and placeholder', () => {
const title = 'Username';
const placeholder = 'Enter your username';
render(<InputField title={title} placeholder={placeholder} value="" setValue={() => {}} />);
const titleElement = screen.getByText(title);
const inputElement = screen.getByPlaceholderText(placeholder);
expect(titleElement).toBeInTheDocument();
expect(inputElement).toBeInTheDocument();
});
it('should call setValue on input change', () => {
const mockSetValue = jest.fn();
const newValue = 'testUser';
render(<InputField title="Username" value="" setValue={mockSetValue} />);
const inputElement = screen.getByRole('textbox');
fireEvent.change(inputElement, { target: { value: newValue } });
expect(mockSetValue).toHaveBeenCalledWith(newValue);
});
it('should call submit function when Enter key is pressed', () => {
const mockSubmit = jest.fn();
render(<InputField title="Username" value="" setValue={() => {}} submit={mockSubmit} />);
const inputElement = screen.getByRole('textbox');
fireEvent.keyDown(inputElement, { key: 'Enter', code: 'Enter' });
expect(mockSubmit).toHaveBeenCalledTimes(1);
});
});

View File

@ -0,0 +1,16 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import NavButton from '../src/components/init/NavButton.jsx';
describe('NavButton Component', () => {
it('should render the NavButton with the correct text and link', () => {
const navLink = '/home';
const buttonText = 'Go Home';
render(<NavButton nav={navLink} text={buttonText} />);
const linkElement = screen.getByText(buttonText);
expect(linkElement).toBeInTheDocument();
expect(linkElement.closest('a')).toHaveAttribute('href', navLink);
});
});

23
__tests__/Search.test.tsx Normal file
View File

@ -0,0 +1,23 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import Search from '../src/components/home/Search.jsx';
describe('Search Component', () => {
it('should render the Search button', () => {
render(<Search search={() => {}} item="testItem" />);
const searchButton = screen.getByText(/find/i);
expect(searchButton).toBeInTheDocument();
});
it('should call the search function with the correct item when clicked', () => {
const mockSearch = jest.fn();
const item = 'testItem';
render(<Search search={mockSearch} item={item} />);
const searchButton = screen.getByText(/find/i);
fireEvent.click(searchButton);
expect(mockSearch).toHaveBeenCalledWith(item);
});
});

52
__tests__/SignIn.test.jsx Normal file
View File

@ -0,0 +1,52 @@
import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import SignIn from "src/pages/SignIn";
import { displayMessage } from "src/backend/notifications/notifications";
import { post } from "src/backend/api";
// Mock the displayMessage and post functions
jest.mock("src/backend/notifications/notifications", () => ({
displayMessage: jest.fn(),
}));
jest.mock("src/backend/api", () => ({
post: jest.fn(),
}));
describe("SignIn Page", () => {
beforeEach(() => {
jest.clearAllMocks();
});
test("renders SignIn form", () => {
render(<SignIn />);
expect(screen.getByLabelText(/username/i)).toBeInTheDocument();
expect(screen.getByLabelText(/password/i)).toBeInTheDocument();
expect(screen.getByText(/sign in/i)).toBeInTheDocument();
});
test("displays error message on failed login", async () => {
post.mockResolvedValueOnce({ ok: false, data: { message: "Invalid credentials" } });
render(<SignIn />);
fireEvent.change(screen.getByLabelText(/username/i), { target: { value: "user" } });
fireEvent.change(screen.getByLabelText(/password/i), { target: { value: "password" } });
fireEvent.click(screen.getByText(/sign in/i));
expect(await screen.findByText(/invalid credentials/i)).toBeInTheDocument();
expect(displayMessage).toHaveBeenCalledWith("Invalid credentials", "error");
});
test("displays additional info message after multiple login attempts", async () => {
post.mockResolvedValueOnce({ ok: false, data: { message: "Invalid credentials" } });
render(<SignIn />);
fireEvent.change(screen.getByLabelText(/username/i), { target: { value: "user" } });
fireEvent.change(screen.getByLabelText(/password/i), { target: { value: "password" } });
// Simulate two failed login attempts
fireEvent.click(screen.getByText(/sign in/i));
fireEvent.click(screen.getByText(/sign in/i));
expect(displayMessage).toHaveBeenCalledWith("Note that you need to enter your ID name", "info");
});
});

View File

@ -0,0 +1,13 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
describe('Hello World Test', () => {
it('should display hello world', () => {
// Render a simple component
render(<div>Hello World</div>);
// Check if "Hello World" is in the document
const helloWorldElement = screen.getByText(/hello world/i);
expect(helloWorldElement).toBeInTheDocument();
});
});

7
babel.config.js Normal file
View File

@ -0,0 +1,7 @@
module.exports = {
presets: [
'@babel/preset-env',
'@babel/preset-react',
'@babel/preset-typescript'],
};

28
jest.config.ts Normal file
View File

@ -0,0 +1,28 @@
import type { Config } from 'jest';
import { defaults } from 'jest-config';
const config: Config = {
clearMocks: true,
collectCoverage: true,
collectCoverageFrom: [
"src/components/**/*.{js,jsx,ts,tsx}", // Include all components
"src/pages/**/*.{js,jsx,ts,tsx}",
"!src/**/*.test.{js,jsx,ts,tsx}", // Exclude test files
"!src/**/index.{js,jsx,ts,tsx}", // Optionally exclude index files
],
coverageDirectory: "coverage",
coverageProvider: "v8",
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
testEnvironment: "jsdom",
// transform: {
// '^.+\\.(ts|tsx|js|jsx)$': 'babel-jest',
// },
moduleNameMapper: {
"^@/src/(.*)$": "<rootDir>/src/$1", // Map '@/src' to the 'src' folder
"^src/(.*)$": "<rootDir>/src/$1", // Map 'src' to the 'src' folder
"\\.(svg|png|jpg|jpeg|gif)$": "<rootDir>/__mocks__/fileMock.js", // Add this line
},
moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts', 'tsx', 'js', 'jsx'],
};
export default config;

17
jest.setup.ts Normal file
View File

@ -0,0 +1,17 @@
import { jest } from '@jest/globals';
import '@testing-library/jest-dom';
import mockedConfig from './bro.config.js'
jest.mock('@brojs/cli', () => {
return {
getNavigations() {
return mockedConfig.navigations
},
getNavigationsValue(key) {
return mockedConfig.navigations[key]
},
getConfigValue(key) {
return mockedConfig.config[key]
}
}
})

5000
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -28,8 +28,25 @@
"start": "brojs server --port=8099 --with-open-browser",
"build": "npm run clean && brojs build --dev",
"build:prod": "npm run clean && brojs build",
"clean": "rimraf dist"
"clean": "rimraf dist",
"test": "jest",
"test:watch": "jest --watchAll"
},
"name": "enterfront",
"version": "0.5.4"
"version": "0.5.4",
"devDependencies": {
"@babel/core": "^7.25.8",
"@babel/preset-env": "^7.25.8",
"@babel/preset-react": "^7.25.7",
"@babel/preset-typescript": "^7.25.7",
"@testing-library/jest-dom": "^6.6.2",
"@testing-library/react": "^16.0.1",
"@types/jest": "^29.5.13",
"babel-jest": "^29.7.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"redux-mock-store": "^1.5.4",
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2"
}
}

View File

@ -4,7 +4,7 @@ import {getConfigValue} from "@brojs/cli";
const LOCAL = "http://localhost:8099";
const DEV = "https://dev.bro-js.ru";
export const BASE_API_URL = DEV + getConfigValue("enterfront.api");
export const BASE_API_URL = LOCAL + getConfigValue("enterfront.api");
// fetch(`${BASE_API_URL}/books/list`)

View File

@ -13,7 +13,7 @@ const InputField = (props) => {
onKeyDown={(e) => {
if (e.key === 'Enter') {
if (props.submit) {
props.enter(props.submit);
props.submit();
}
}
}}

View File

@ -13,7 +13,7 @@
"target": "es6",
"jsx": "react",
"typeRoots": ["node_modules/@types", "src/typings"],
"types" : ["webpack-env", "node"],
"types" : ["webpack-env", "node", "jest"],
"resolveJsonModule": true
},
"exclude": [