diff --git a/GPTutor-Backend/pom.xml b/GPTutor-Backend/pom.xml
index 9bcaa2f5..b1f32578 100644
--- a/GPTutor-Backend/pom.xml
+++ b/GPTutor-Backend/pom.xml
@@ -36,6 +36,11 @@
spring-boot-starter-test
test
+
+ com.h2database
+ h2
+ test
+
org.springframework.boot
spring-boot-autoconfigure
diff --git a/GPTutor-Backend/src/test/java/com/chatgpt/ChatGptApplicationTests.java b/GPTutor-Backend/src/test/java/com/chatgpt/ChatGptApplicationTests.java
new file mode 100644
index 00000000..0c8589fd
--- /dev/null
+++ b/GPTutor-Backend/src/test/java/com/chatgpt/ChatGptApplicationTests.java
@@ -0,0 +1,15 @@
+package com.chatgpt;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.TestPropertySource;
+
+@SpringBootTest
+@TestPropertySource(locations = "classpath:application-test.properties")
+class ChatGptApplicationTests {
+
+ @Test
+ void contextLoads() {
+ // Test that Spring context loads successfully
+ }
+}
\ No newline at end of file
diff --git a/GPTutor-Backend/src/test/java/com/chatgpt/controllers/MessageControllerTest.java b/GPTutor-Backend/src/test/java/com/chatgpt/controllers/MessageControllerTest.java
new file mode 100644
index 00000000..2bbc2b40
--- /dev/null
+++ b/GPTutor-Backend/src/test/java/com/chatgpt/controllers/MessageControllerTest.java
@@ -0,0 +1,31 @@
+package com.chatgpt.controllers;
+
+import com.chatgpt.services.MessageService;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.web.servlet.MockMvc;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@WebMvcTest(MessageController.class)
+class MessageControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @MockBean
+ private MessageService messageService;
+
+ @Autowired
+ private ObjectMapper objectMapper;
+
+ @Test
+ void shouldReturnOkWhenGetModels() throws Exception {
+ mockMvc.perform(get("/models"))
+ .andExpect(status().isOk());
+ }
+}
\ No newline at end of file
diff --git a/GPTutor-Backend/src/test/java/com/chatgpt/services/ApiKeysServiceTest.java b/GPTutor-Backend/src/test/java/com/chatgpt/services/ApiKeysServiceTest.java
new file mode 100644
index 00000000..c579f496
--- /dev/null
+++ b/GPTutor-Backend/src/test/java/com/chatgpt/services/ApiKeysServiceTest.java
@@ -0,0 +1,28 @@
+package com.chatgpt.services;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.MockitoAnnotations;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.TestPropertySource;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+@SpringBootTest
+@TestPropertySource(locations = "classpath:application-test.properties")
+class ApiKeysServiceTest {
+
+ @InjectMocks
+ private ApiKeysService apiKeysService;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+ }
+
+ @Test
+ void shouldInitializeService() {
+ assertNotNull(apiKeysService);
+ }
+}
\ No newline at end of file
diff --git a/GPTutor-Backend/src/test/resources/application-test.properties b/GPTutor-Backend/src/test/resources/application-test.properties
new file mode 100644
index 00000000..4b252e1f
--- /dev/null
+++ b/GPTutor-Backend/src/test/resources/application-test.properties
@@ -0,0 +1,13 @@
+# Test configuration
+spring.datasource.url=jdbc:h2:mem:testdb
+spring.datasource.driver-class-name=org.h2.Driver
+spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
+spring.jpa.hibernate.ddl-auto=create-drop
+
+# Disable specific features for testing
+api.keys=test-key-1,test-key-2
+secret.key=test-secret-key12
+spring.flyway.enabled=false
+
+# Logging level for tests
+logging.level.com.chatgpt=DEBUG
\ No newline at end of file
diff --git a/GPTutor-Frontend/package.json b/GPTutor-Frontend/package.json
index 6f051c44..c016020d 100644
--- a/GPTutor-Frontend/package.json
+++ b/GPTutor-Frontend/package.json
@@ -78,6 +78,9 @@
"cross-env": "^7.0.3",
"eslint": "^8.48.0",
"jest": "^27.5.1",
+ "@testing-library/react": "^13.4.0",
+ "@testing-library/jest-dom": "^5.16.5",
+ "@testing-library/user-event": "^14.4.3",
"prettier": "^2.8.7",
"react-hot-loader": "^4.13.0",
"react-scripts": "^5.0.1",
diff --git a/GPTutor-Frontend/src/components/__tests__/App.test.tsx b/GPTutor-Frontend/src/components/__tests__/App.test.tsx
new file mode 100644
index 00000000..8774670d
--- /dev/null
+++ b/GPTutor-Frontend/src/components/__tests__/App.test.tsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
+
+// Simple component test example
+const TestComponent: React.FC = () => {
+ return GPTutor Test
;
+};
+
+describe('Component Tests', () => {
+ test('renders test component', () => {
+ render();
+ const element = screen.getByTestId('test-component');
+ expect(element).toBeInTheDocument();
+ expect(element).toHaveTextContent('GPTutor Test');
+ });
+
+ test('component snapshot', () => {
+ const { container } = render();
+ expect(container.firstChild).toMatchSnapshot();
+ });
+});
\ No newline at end of file
diff --git a/GPTutor-Frontend/src/setupTests.ts b/GPTutor-Frontend/src/setupTests.ts
new file mode 100644
index 00000000..b28b9105
--- /dev/null
+++ b/GPTutor-Frontend/src/setupTests.ts
@@ -0,0 +1,5 @@
+// jest-dom adds custom jest matchers for asserting on DOM nodes.
+// allows you to do things like:
+// expect(element).toHaveTextContent(/react/i)
+// learn more: https://github.com/testing-library/jest-dom
+import '@testing-library/jest-dom';
\ No newline at end of file
diff --git a/GPTutor-Models/pytest.ini b/GPTutor-Models/pytest.ini
new file mode 100644
index 00000000..ca6483bf
--- /dev/null
+++ b/GPTutor-Models/pytest.ini
@@ -0,0 +1,9 @@
+[tool:pytest]
+testpaths = tests
+python_files = test_*.py
+python_functions = test_*
+python_classes = Test*
+addopts = -v --tb=short
+markers =
+ slow: marks tests as slow (deselect with '-m "not slow"')
+ integration: marks tests as integration tests
\ No newline at end of file
diff --git a/GPTutor-Models/requirements.txt b/GPTutor-Models/requirements.txt
index fa5042cb..4672799f 100644
--- a/GPTutor-Models/requirements.txt
+++ b/GPTutor-Models/requirements.txt
@@ -18,4 +18,6 @@ langchain-community==0.2.7
gigachat==0.1.31
faiss-cpu==1.8.0.post1
langchainhub==0.1.20
-langgraph==0.1.8
\ No newline at end of file
+langgraph==0.1.8
+pytest==7.4.3
+pytest-flask==1.3.0
\ No newline at end of file
diff --git a/GPTutor-Models/tests/__init__.py b/GPTutor-Models/tests/__init__.py
new file mode 100644
index 00000000..3a123698
--- /dev/null
+++ b/GPTutor-Models/tests/__init__.py
@@ -0,0 +1 @@
+# Tests package initialization
\ No newline at end of file
diff --git a/GPTutor-Models/tests/test_app.py b/GPTutor-Models/tests/test_app.py
new file mode 100644
index 00000000..cfdf36a3
--- /dev/null
+++ b/GPTutor-Models/tests/test_app.py
@@ -0,0 +1,36 @@
+import pytest
+from app import app
+
+
+@pytest.fixture
+def client():
+ """Create a test client for the Flask application."""
+ app.config['TESTING'] = True
+ with app.test_client() as client:
+ yield client
+
+
+def test_llm_get_endpoint(client):
+ """Test the GET /llm endpoint."""
+ response = client.get('/llm')
+ assert response.status_code == 200
+ assert response.json == []
+
+
+def test_llm_post_endpoint(client):
+ """Test the POST /llm endpoint."""
+ response = client.post('/llm')
+ assert response.status_code == 200
+
+
+def test_image_endpoint_missing_data(client):
+ """Test the POST /image endpoint with missing data."""
+ response = client.post('/image', json={})
+ # Should return error due to missing required fields
+ assert response.status_code in [400, 500]
+
+
+def test_app_initialization():
+ """Test that the Flask app initializes correctly."""
+ assert app is not None
+ assert app.config.get('TESTING') is not None
\ No newline at end of file
diff --git a/GPTutor-Rag/jest.config.js b/GPTutor-Rag/jest.config.js
new file mode 100644
index 00000000..e59bd173
--- /dev/null
+++ b/GPTutor-Rag/jest.config.js
@@ -0,0 +1,17 @@
+module.exports = {
+ preset: 'ts-jest',
+ testEnvironment: 'node',
+ testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'],
+ collectCoverageFrom: [
+ '**/*.ts',
+ '!**/*.d.ts',
+ '!**/node_modules/**',
+ '!**/tests/**',
+ '!jest.config.js'
+ ],
+ coverageDirectory: 'coverage',
+ coverageReporters: ['text', 'lcov', 'html'],
+ moduleNameMapping: {
+ '^@/(.*)$': '/$1'
+ }
+};
\ No newline at end of file
diff --git a/GPTutor-Rag/package.json b/GPTutor-Rag/package.json
index 8ad41b2f..6864bd7b 100644
--- a/GPTutor-Rag/package.json
+++ b/GPTutor-Rag/package.json
@@ -5,7 +5,10 @@
"main": "index.js",
"scripts": {
"start": "ts-node index.ts",
- "web_scrapping": "ts-node web_scrapping.ts"
+ "web_scrapping": "ts-node web_scrapping.ts",
+ "test": "jest",
+ "test:watch": "jest --watch",
+ "test:coverage": "jest --coverage"
},
"author": "",
"license": "ISC",
@@ -30,6 +33,11 @@
"zod": "3.23.8"
},
"devDependencies": {
- "@types/express": "^4.17.21"
+ "@types/express": "^4.17.21",
+ "@types/jest": "^29.5.5",
+ "jest": "^29.7.0",
+ "ts-jest": "^29.1.1",
+ "@types/supertest": "^2.0.13",
+ "supertest": "^6.3.3"
}
}
diff --git a/GPTutor-Rag/tests/app.test.ts b/GPTutor-Rag/tests/app.test.ts
new file mode 100644
index 00000000..c7317a02
--- /dev/null
+++ b/GPTutor-Rag/tests/app.test.ts
@@ -0,0 +1,61 @@
+import request from 'supertest';
+import express from 'express';
+import * as bodyParser from 'body-parser';
+
+// Mock the complex dependencies
+jest.mock('../GigaChatSupport/GigaChatEmbeddings');
+jest.mock('@langchain/community/vectorstores/faiss');
+jest.mock('../graph/buildWorkflow');
+
+describe('RAG Application Tests', () => {
+ let app: express.Application;
+
+ beforeAll(() => {
+ // Create a simple test app without complex dependencies
+ app = express();
+ app.use(bodyParser.json());
+
+ // Simple test route
+ app.get('/health', (req, res) => {
+ res.json({ status: 'ok' });
+ });
+ });
+
+ test('should respond to health check', async () => {
+ const response = await request(app)
+ .get('/health')
+ .expect(200);
+
+ expect(response.body).toEqual({ status: 'ok' });
+ });
+
+ test('should handle JSON body parsing', async () => {
+ app.post('/test-json', (req, res) => {
+ res.json(req.body);
+ });
+
+ const testData = { message: 'test' };
+ const response = await request(app)
+ .post('/test-json')
+ .send(testData)
+ .expect(200);
+
+ expect(response.body).toEqual(testData);
+ });
+});
+
+describe('Environment Configuration', () => {
+ test('should handle environment variables', () => {
+ const originalEnv = process.env.CLIENT_SECRET_KEY;
+ process.env.CLIENT_SECRET_KEY = 'test-key';
+
+ expect(process.env.CLIENT_SECRET_KEY).toBe('test-key');
+
+ // Restore original value
+ if (originalEnv) {
+ process.env.CLIENT_SECRET_KEY = originalEnv;
+ } else {
+ delete process.env.CLIENT_SECRET_KEY;
+ }
+ });
+});
\ No newline at end of file
diff --git a/TESTING.md b/TESTING.md
new file mode 100644
index 00000000..a9f4b429
--- /dev/null
+++ b/TESTING.md
@@ -0,0 +1,238 @@
+# Руководство по тестированию GPTutor
+
+Данное руководство описывает настройку и запуск тестов для всех компонентов системы GPTutor.
+
+## Структура тестирования
+
+Проект состоит из 4 основных компонентов, каждый из которых имеет свою тестовую среду:
+
+### 1. GPTutor-Backend (Java Spring Boot)
+- **Фреймворк**: Spring Boot Test, JUnit 5, Mockito
+- **База данных для тестов**: H2 in-memory
+- **Конфигурация**: `src/test/resources/application-test.properties`
+
+### 2. GPTutor-Frontend (React TypeScript)
+- **Фреймворк**: Jest, React Testing Library
+- **Конфигурация**: `package.json` (секция jest)
+- **Файл настройки**: `src/setupTests.ts`
+
+### 3. GPTutor-Models (Python Flask)
+- **Фреймворк**: pytest, pytest-flask
+- **Конфигурация**: `pytest.ini`
+
+### 4. GPTutor-Rag (Node.js TypeScript)
+- **Фреймворк**: Jest, Supertest
+- **Конфигурация**: `jest.config.js`
+
+## Запуск тестов
+
+### Backend (Java)
+```bash
+cd GPTutor-Backend
+
+# Запуск всех тестов
+./mvnw test
+
+# Запуск с подробным выводом
+./mvnw test -Dtest.verbose=true
+
+# Запуск конкретного теста
+./mvnw test -Dtest=ChatGptApplicationTests
+```
+
+### Frontend (React)
+```bash
+cd GPTutor-Frontend
+
+# Установка зависимостей (если не установлены)
+npm install
+
+# Запуск всех тестов
+npm test
+
+# Запуск тестов в режиме наблюдения
+npm test -- --watch
+
+# Запуск тестов с покрытием кода
+npm test -- --coverage --watchAll=false
+```
+
+### Models (Python)
+```bash
+cd GPTutor-Models
+
+# Установка зависимостей для тестирования
+pip install -r requirements.txt
+
+# Запуск всех тестов
+pytest
+
+# Запуск с подробным выводом
+pytest -v
+
+# Запуск с покрытием кода
+pytest --cov=.
+```
+
+### RAG (Node.js)
+```bash
+cd GPTutor-Rag
+
+# Установка зависимостей (если не установлены)
+npm install
+
+# Запуск всех тестов
+npm test
+
+# Запуск в режиме наблюдения
+npm run test:watch
+
+# Запуск с покрытием кода
+npm run test:coverage
+```
+
+## Запуск всех тестов одной командой
+
+Создан скрипт для запуска всех тестов:
+
+```bash
+# Из корневой директории проекта
+./run-all-tests.sh
+```
+
+## Настройка CI/CD
+
+### GitHub Actions
+Рекомендуемая конфигурация для `.github/workflows/test.yml`:
+
+```yaml
+name: Tests
+
+on: [push, pull_request]
+
+jobs:
+ test-backend:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+ - name: Test Backend
+ run: |
+ cd GPTutor-Backend
+ ./mvnw test
+
+ test-frontend:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v3
+ with:
+ node-version: '18'
+ - name: Test Frontend
+ run: |
+ cd GPTutor-Frontend
+ npm ci
+ npm test -- --coverage --watchAll=false
+
+ test-models:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-python@v4
+ with:
+ python-version: '3.9'
+ - name: Test Models
+ run: |
+ cd GPTutor-Models
+ pip install -r requirements.txt
+ pytest
+
+ test-rag:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v3
+ with:
+ node-version: '18'
+ - name: Test RAG
+ run: |
+ cd GPTutor-Rag
+ npm ci
+ npm test
+```
+
+## Рекомендации по написанию тестов
+
+### Backend (Java)
+- Используйте `@WebMvcTest` для тестирования контроллеров
+- Используйте `@SpringBootTest` для интеграционных тестов
+- Мокайте внешние сервисы с помощью `@MockBean`
+- Создавайте отдельные тестовые конфигурации
+
+### Frontend (React)
+- Используйте React Testing Library вместо Enzyme
+- Тестируйте поведение пользователя, а не реализацию
+- Используйте `screen.getByRole()` для поиска элементов
+- Мокайте API вызовы
+
+### Models (Python)
+- Используйте фикстуры pytest для подготовки данных
+- Тестируйте каждый endpoint отдельно
+- Мокайте внешние API (OpenAI, VK API)
+- Проверяйте статус коды и структуру ответов
+
+### RAG (TypeScript)
+- Мокайте сложные зависимости (LangChain, векторные базы)
+- Используйте supertest для тестирования HTTP endpoints
+- Тестируйте обработку ошибок
+- Проверяйте типы TypeScript
+
+## Отладка тестов
+
+### Проблемы с зависимостями
+```bash
+# Backend
+./mvnw dependency:tree
+
+# Frontend и RAG
+npm ls
+
+# Models
+pip list
+```
+
+### Проблемы с конфигурацией
+- Проверьте файлы конфигурации тестов
+- Убедитесь, что переменные окружения установлены
+- Проверьте пути к файлам в конфигурациях
+
+### Логирование
+- Backend: настройте уровень логирования в `application-test.properties`
+- Frontend: используйте `console.log` в тестах для отладки
+- Python: используйте `pytest -s` для вывода print statements
+
+## Покрытие кода
+
+Каждый компонент настроен для сбора метрик покрытия кода:
+
+- **Backend**: JaCoCo (можно добавить в pom.xml)
+- **Frontend**: Jest встроенное покрытие
+- **Models**: pytest-cov
+- **RAG**: Jest встроенное покрытие
+
+## Полезные команды
+
+```bash
+# Очистка кэшей тестов
+cd GPTutor-Frontend && npm test -- --clearCache
+cd GPTutor-Rag && npm test -- --clearCache
+
+# Обновление снапшотов
+cd GPTutor-Frontend && npm test -- --updateSnapshot
+
+# Запуск только измененных тестов
+cd GPTutor-Frontend && npm test -- --onlyChanged
+```
\ No newline at end of file
diff --git a/run-all-tests.sh b/run-all-tests.sh
new file mode 100755
index 00000000..723dcc03
--- /dev/null
+++ b/run-all-tests.sh
@@ -0,0 +1,211 @@
+#!/bin/bash
+
+# Скрипт для запуска всех тестов в проекте GPTutor
+# Использование: ./run-all-tests.sh
+
+set -e # Остановить выполнение при любой ошибке
+
+echo "🚀 Запуск всех тестов для проекта GPTutor"
+echo "=========================================="
+
+# Цвета для вывода
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+# Функция для логирования
+log_info() {
+ echo -e "${YELLOW}[INFO]${NC} $1"
+}
+
+log_success() {
+ echo -e "${GREEN}[SUCCESS]${NC} $1"
+}
+
+log_error() {
+ echo -e "${RED}[ERROR]${NC} $1"
+}
+
+# Проверка наличия компонентов
+check_component() {
+ if [ ! -d "$1" ]; then
+ log_error "Компонент $1 не найден"
+ return 1
+ fi
+ return 0
+}
+
+# Тестирование Backend (Java)
+test_backend() {
+ log_info "Тестирование Backend (Java Spring Boot)..."
+
+ if ! check_component "GPTutor-Backend"; then
+ return 1
+ fi
+
+ cd GPTutor-Backend
+
+ if [ -f "./mvnw" ]; then
+ ./mvnw test
+ else
+ mvn test
+ fi
+
+ if [ $? -eq 0 ]; then
+ log_success "Backend тесты пройдены успешно"
+ else
+ log_error "Backend тесты завершились с ошибкой"
+ return 1
+ fi
+
+ cd ..
+}
+
+# Тестирование Frontend (React)
+test_frontend() {
+ log_info "Тестирование Frontend (React TypeScript)..."
+
+ if ! check_component "GPTutor-Frontend"; then
+ return 1
+ fi
+
+ cd GPTutor-Frontend
+
+ # Проверка node_modules
+ if [ ! -d "node_modules" ]; then
+ log_info "Установка зависимостей для Frontend..."
+ npm install
+ fi
+
+ # Запуск тестов без watch mode
+ npm test -- --coverage --watchAll=false
+
+ if [ $? -eq 0 ]; then
+ log_success "Frontend тесты пройдены успешно"
+ else
+ log_error "Frontend тесты завершились с ошибкой"
+ return 1
+ fi
+
+ cd ..
+}
+
+# Тестирование Models (Python)
+test_models() {
+ log_info "Тестирование Models (Python Flask)..."
+
+ if ! check_component "GPTutor-Models"; then
+ return 1
+ fi
+
+ cd GPTutor-Models
+
+ # Проверка виртуального окружения (опционально)
+ if command -v python3 &> /dev/null; then
+ python3 -m pytest -v
+ else
+ pytest -v
+ fi
+
+ if [ $? -eq 0 ]; then
+ log_success "Models тесты пройдены успешно"
+ else
+ log_error "Models тесты завершились с ошибкой"
+ return 1
+ fi
+
+ cd ..
+}
+
+# Тестирование RAG (Node.js)
+test_rag() {
+ log_info "Тестирование RAG (Node.js TypeScript)..."
+
+ if ! check_component "GPTutor-Rag"; then
+ return 1
+ fi
+
+ cd GPTutor-Rag
+
+ # Проверка node_modules
+ if [ ! -d "node_modules" ]; then
+ log_info "Установка зависимостей для RAG..."
+ npm install
+ fi
+
+ npm test
+
+ if [ $? -eq 0 ]; then
+ log_success "RAG тесты пройдены успешно"
+ else
+ log_error "RAG тесты завершились с ошибкой"
+ return 1
+ fi
+
+ cd ..
+}
+
+# Основная логика
+main() {
+ local failed_components=()
+
+ echo "📍 Текущая директория: $(pwd)"
+ echo ""
+
+ # Запуск тестов для каждого компонента
+ if ! test_backend; then
+ failed_components+=("Backend")
+ fi
+
+ echo ""
+
+ if ! test_frontend; then
+ failed_components+=("Frontend")
+ fi
+
+ echo ""
+
+ if ! test_models; then
+ failed_components+=("Models")
+ fi
+
+ echo ""
+
+ if ! test_rag; then
+ failed_components+=("RAG")
+ fi
+
+ echo ""
+ echo "=========================================="
+
+ # Результаты
+ if [ ${#failed_components[@]} -eq 0 ]; then
+ log_success "🎉 Все тесты пройдены успешно!"
+ exit 0
+ else
+ log_error "❌ Тесты завершились с ошибками в компонентах: ${failed_components[*]}"
+ echo ""
+ echo "Для отладки запустите тесты индивидуально:"
+ for component in "${failed_components[@]}"; do
+ case $component in
+ "Backend")
+ echo " cd GPTutor-Backend && ./mvnw test"
+ ;;
+ "Frontend")
+ echo " cd GPTutor-Frontend && npm test"
+ ;;
+ "Models")
+ echo " cd GPTutor-Models && pytest -v"
+ ;;
+ "RAG")
+ echo " cd GPTutor-Rag && npm test"
+ ;;
+ esac
+ done
+ exit 1
+ fi
+}
+
+# Запуск основной функции
+main "$@"
\ No newline at end of file