Backend Complete: Interface Refactoring & Service Container Enhancements

Repository Interface Optimization:
- Created IBaseRepository.ts and IPaginatedRepository.ts
- Refactored all 7 repository interfaces to extend base interfaces
- Eliminated ~200 lines of redundant code (70% reduction)
- Improved type safety and maintainability

 Dependency Injection Improvements:
- Added EmailService and GameTokenService to DIContainer
- Updated CreateUserCommandHandler constructor for DI
- Updated RequestPasswordResetCommandHandler constructor for DI
- Enhanced testability and service consistency

 Environment Configuration:
- Created comprehensive .env.example with 40+ variables
- Organized into 12 logical sections (Database, Security, Email, etc.)
- Added security guidelines and best practices
- Documented all backend environment requirements

 Documentation:
- Added comprehensive codebase review
- Created refactoring summary report
- Added frontend implementation guide

Impact: Improved code quality, reduced maintenance overhead, enhanced developer experience
This commit is contained in:
2025-09-21 03:27:57 +02:00
parent 5b7c3ba4b2
commit 86211923db
306 changed files with 52956 additions and 0 deletions
+115
View File
@@ -0,0 +1,115 @@
#!/usr/bin/env node
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
/**
* Build System Helper - Shows available build commands and their descriptions
*/
const commands = {
'Development Commands': {
'npm run dev': 'Start development server with hot reload',
'npm run watch': 'Watch mode TypeScript compilation',
'npm run typecheck': 'Type checking without code generation'
},
'Build Commands': {
'npm run build': 'Standard build: clean → compile → copy assets',
'npm run build:clean': 'Clean the dist directory',
'npm run build:compile': 'Compile TypeScript to JavaScript',
'npm run build:copy-assets': 'Copy non-TS files to dist directory',
'npm run build:docker': 'Build for Docker (no tests/migrations)'
},
'Production Build Commands': {
'npm run build:production': 'Full production build with linting, tests, and migrations',
'npm run build:advanced': 'Advanced build script with custom options',
'npm run build:advanced:prod': 'Advanced production build with all validations',
'npm run build:advanced:ci': 'CI/CD friendly build (skips linting)',
'npm run deploy:prod': 'Build for production deployment'
},
'Database Commands': {
'npm run migration:run': 'Run pending database migrations',
'npm run migration:show': 'Show migration status',
'npm run migration:generate <name>': 'Generate new migration',
'npm run migration:create <name>': 'Create empty migration',
'npm run migration:revert': 'Revert last migration',
'npm run migration:full <name>': 'Create, generate, and run migration'
},
'Testing Commands': {
'npm test': 'Run all tests',
'npm run test:watch': 'Run tests in watch mode',
'npm run test:coverage': 'Run tests with coverage report',
'npm run test:redis': 'Run Redis-specific tests'
},
'Deployment Scripts': {
'scripts/deploy.sh': 'Full Linux/Mac deployment script',
'scripts/deploy.bat': 'Full Windows deployment script'
}
};
function showCommands() {
console.log('🔧 SerpentRace Backend Build System\n');
Object.entries(commands).forEach(([category, categoryCommands]) => {
console.log(`\x1b[36m${category}\x1b[0m`);
console.log('=' .repeat(category.length));
Object.entries(categoryCommands).forEach(([command, description]) => {
console.log(` \x1b[32m${command.padEnd(35)}\x1b[0m ${description}`);
});
console.log('');
});
console.log('\x1b[33mQuick Start:\x1b[0m');
console.log(' npm run build # Basic build');
console.log(' npm run build:production # Production build');
console.log(' npm run dev # Development server\n');
console.log('\x1b[33mDocumentation:\x1b[0m');
console.log(' See BUILD.md for detailed documentation');
}
function checkBuildStatus() {
const distPath = path.join(__dirname, '..', 'dist');
if (fs.existsSync(distPath)) {
const stats = fs.statSync(distPath);
console.log(`\x1b[32m✅ Last build:\x1b[0m ${stats.mtime.toLocaleString()}`);
const indexPath = path.join(distPath, 'Api', 'index.js');
if (fs.existsSync(indexPath)) {
console.log('\x1b[32m✅ Main entry point built successfully\x1b[0m');
} else {
console.log('\x1b[31m❌ Main entry point missing\x1b[0m');
}
} else {
console.log('\x1b[33m⚠️ No build found - run "npm run build" first\x1b[0m');
}
}
// Handle command line arguments
const args = process.argv.slice(2);
if (args.includes('--help') || args.includes('-h')) {
showCommands();
} else if (args.includes('--status') || args.includes('-s')) {
checkBuildStatus();
} else if (args.includes('--quick') || args.includes('-q')) {
console.log('🚀 Quick build starting...');
try {
execSync('npm run build', { stdio: 'inherit' });
} catch (error) {
console.error('❌ Quick build failed');
process.exit(1);
}
} else {
showCommands();
checkBuildStatus();
console.log('\n\x1b[33mOptions:\x1b[0m');
console.log(' --help, -h Show this help');
console.log(' --status, -s Show build status only');
console.log(' --quick, -q Run quick build');
}
+187
View File
@@ -0,0 +1,187 @@
import { execSync } from 'child_process';
import { existsSync, rmSync } from 'fs';
import { join } from 'path';
/**
* Comprehensive Build Script for SerpentRace Backend
* Handles TypeScript compilation, migrations, asset copying, and validation
*/
interface BuildOptions {
runMigrations?: boolean;
runTests?: boolean;
skipLinting?: boolean;
production?: boolean;
}
class BuildManager {
private distDir = join(__dirname, '..', 'dist');
constructor(private options: BuildOptions = {}) {}
private log(message: string, level: 'info' | 'error' | 'warn' = 'info') {
const timestamp = new Date().toISOString();
const prefix = {
info: '🔧',
error: '❌',
warn: '⚠️'
}[level];
console.log(`${prefix} [${timestamp}] ${message}`);
}
private execute(command: string, description: string) {
this.log(`${description}...`);
try {
execSync(command, {
stdio: 'inherit',
cwd: join(__dirname, '..')
});
this.log(`${description} completed successfully`);
} catch (error) {
this.log(`${description} failed`, 'error');
throw error;
}
}
async clean() {
this.log('Cleaning previous build...');
if (existsSync(this.distDir)) {
rmSync(this.distDir, { recursive: true, force: true });
this.log('✅ Previous build cleaned');
} else {
this.log('No previous build found');
}
}
async typecheck() {
this.execute('npx tsc --noEmit', 'Type checking');
}
async lint() {
if (this.options.skipLinting) {
this.log('Skipping linting...', 'warn');
return;
}
// For now, just check if TypeScript compiles without errors
this.log('Linting (basic type checking)...');
await this.typecheck();
}
async runTests() {
if (!this.options.runTests) {
this.log('Skipping tests...', 'warn');
return;
}
this.execute('npm test', 'Running tests');
}
async runMigrations() {
if (!this.options.runMigrations) {
this.log('Skipping database migrations...', 'warn');
return;
}
try {
this.log('Checking migration status...');
execSync('npm run migration:show', {
stdio: 'pipe',
cwd: join(__dirname, '..')
});
this.execute('npm run migration:run', 'Running database migrations');
} catch (error) {
this.log('Migration check/run failed - this might be expected in CI/CD environments', 'warn');
if (this.options.production) {
throw error; // In production builds, migrations should work
}
}
}
async compile() {
this.execute('npx tsc', 'Compiling TypeScript');
}
async copyAssets() {
this.execute('node scripts/copy-assets.js', 'Copying assets');
}
async validateBuild() {
this.log('Validating build output...');
const expectedFiles = [
'dist/Api/index.js',
'dist/Api/index.d.ts'
];
const missingFiles = expectedFiles.filter(file =>
!existsSync(join(__dirname, '..', file))
);
if (missingFiles.length > 0) {
this.log(`Missing expected build files: ${missingFiles.join(', ')}`, 'error');
throw new Error('Build validation failed');
}
this.log('✅ Build validation completed');
}
async build() {
const startTime = Date.now();
try {
this.log('🚀 Starting SerpentRace Backend build process...');
// Step 1: Clean previous build
await this.clean();
// Step 2: Lint code (if not skipped)
await this.lint();
// Step 3: Run tests (if enabled)
await this.runTests();
// Step 4: Run migrations (if enabled)
await this.runMigrations();
// Step 5: Compile TypeScript
await this.compile();
// Step 6: Copy assets
await this.copyAssets();
// Step 7: Validate build
await this.validateBuild();
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
this.log(`🎉 Build completed successfully in ${duration}s`);
} catch (error) {
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
this.log(`💥 Build failed after ${duration}s`, 'error');
if (error instanceof Error) {
this.log(`Error: ${error.message}`, 'error');
}
process.exit(1);
}
}
}
// Parse command line arguments
const args = process.argv.slice(2);
const options: BuildOptions = {
runMigrations: args.includes('--migrations'),
runTests: args.includes('--test'),
skipLinting: args.includes('--skip-lint'),
production: args.includes('--production')
};
// Create and run build
const buildManager = new BuildManager(options);
buildManager.build().catch(error => {
console.error('Unhandled build error:', error);
process.exit(1);
});
@@ -0,0 +1,62 @@
const fs = require('fs');
const path = require('path');
/**
* Copy Assets Script for SerpentRace Backend
* Copies non-TypeScript files to the dist directory
*/
const srcDir = path.join(__dirname, '..', 'src');
const distDir = path.join(__dirname, '..', 'dist');
// File extensions to copy
const assetExtensions = ['.json', '.html', '.css', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.woff', '.woff2', '.ttf', '.eot'];
// Directories to exclude from copying
const excludeDirs = ['node_modules', '.git', 'tests', '__tests__'];
function copyAssets(srcPath, distPath) {
if (!fs.existsSync(srcPath)) {
console.log(`Source directory ${srcPath} does not exist`);
return;
}
if (!fs.existsSync(distPath)) {
fs.mkdirSync(distPath, { recursive: true });
}
const items = fs.readdirSync(srcPath);
items.forEach(item => {
const srcItemPath = path.join(srcPath, item);
const distItemPath = path.join(distPath, item);
const stat = fs.statSync(srcItemPath);
if (stat.isDirectory()) {
// Skip excluded directories
if (excludeDirs.includes(item)) {
return;
}
// Recursively copy subdirectories
copyAssets(srcItemPath, distItemPath);
} else {
const ext = path.extname(item).toLowerCase();
// Copy asset files
if (assetExtensions.includes(ext)) {
console.log(`Copying asset: ${srcItemPath} -> ${distItemPath}`);
fs.copyFileSync(srcItemPath, distItemPath);
}
}
});
}
try {
console.log('Copying assets from src to dist...');
copyAssets(srcDir, distDir);
console.log('Asset copying completed successfully!');
} catch (error) {
console.error('Error copying assets:', error);
process.exit(1);
}
+233
View File
@@ -0,0 +1,233 @@
@echo off
REM SerpentRace Backend Production Deployment Script for Windows
REM This script handles the complete deployment process
setlocal EnableDelayedExpansion
set "SCRIPT_START=%TIME%"
REM Colors simulation for Windows (using echo with different prefixes)
set "LOG_PREFIX=[INFO]"
set "ERROR_PREFIX=[ERROR]"
set "WARN_PREFIX=[WARN]"
:log
echo %LOG_PREFIX% [%DATE% %TIME%] %~1
goto :eof
:error
echo %ERROR_PREFIX% [%DATE% %TIME%] %~1
goto :eof
:warn
echo %WARN_PREFIX% [%DATE% %TIME%] %~1
goto :eof
:check_env
call :log "Checking environment variables..."
set "required_vars=DB_HOST DB_PORT DB_USERNAME DB_PASSWORD DB_NAME JWT_SECRET REDIS_HOST REDIS_PORT"
set "missing_vars="
for %%v in (%required_vars%) do (
call set "var_value=%%!%%v!%%"
if "!var_value!"=="" (
set "missing_vars=!missing_vars! %%v"
)
)
if not "!missing_vars!"==" " (
call :error "Missing required environment variables:!missing_vars!"
call :error "Please set these variables before running the deployment"
exit /b 1
)
call :log "All required environment variables are set"
goto :eof
:install_dependencies
call :log "Installing production dependencies..."
npm ci --only=production
if !errorlevel! neq 0 (
call :error "Failed to install dependencies"
exit /b 1
)
call :log "Dependencies installed successfully"
goto :eof
:run_build
call :log "Running production build..."
npm run build:production
if !errorlevel! neq 0 (
call :error "Build failed"
exit /b 1
)
call :log "Build completed successfully"
goto :eof
:test_database
call :log "Testing database connectivity..."
echo import { AppDataSource } from './src/Infrastructure/ormconfig'; > test-db-temp.ts
echo. >> test-db-temp.ts
echo async function testConnection() { >> test-db-temp.ts
echo try { >> test-db-temp.ts
echo await AppDataSource.initialize(); >> test-db-temp.ts
echo console.log('✅ Database connection successful'^); >> test-db-temp.ts
echo await AppDataSource.destroy(); >> test-db-temp.ts
echo process.exit(0^); >> test-db-temp.ts
echo } catch (error^) { >> test-db-temp.ts
echo console.error('❌ Database connection failed:', error^); >> test-db-temp.ts
echo process.exit(1^); >> test-db-temp.ts
echo } >> test-db-temp.ts
echo } >> test-db-temp.ts
echo. >> test-db-temp.ts
echo testConnection(); >> test-db-temp.ts
npx ts-node test-db-temp.ts
set "db_test_result=!errorlevel!"
del test-db-temp.ts 2>nul
if !db_test_result! neq 0 (
call :error "Database connectivity test failed"
exit /b 1
)
call :log "Database connectivity test passed"
goto :eof
:test_redis
call :log "Testing Redis connectivity..."
echo import { createClient } from 'redis'; > test-redis-temp.ts
echo. >> test-redis-temp.ts
echo async function testRedis() { >> test-redis-temp.ts
echo const client = createClient({ >> test-redis-temp.ts
echo socket: { >> test-redis-temp.ts
echo host: process.env.REDIS_HOST ^|^| 'localhost', >> test-redis-temp.ts
echo port: parseInt(process.env.REDIS_PORT ^|^| '6379'^) >> test-redis-temp.ts
echo } >> test-redis-temp.ts
echo }^); >> test-redis-temp.ts
echo. >> test-redis-temp.ts
echo try { >> test-redis-temp.ts
echo await client.connect(); >> test-redis-temp.ts
echo await client.ping(); >> test-redis-temp.ts
echo console.log('✅ Redis connection successful'^); >> test-redis-temp.ts
echo await client.disconnect(); >> test-redis-temp.ts
echo process.exit(0^); >> test-redis-temp.ts
echo } catch (error^) { >> test-redis-temp.ts
echo console.error('❌ Redis connection failed:', error^); >> test-redis-temp.ts
echo process.exit(1^); >> test-redis-temp.ts
echo } >> test-redis-temp.ts
echo } >> test-redis-temp.ts
echo. >> test-redis-temp.ts
echo testRedis(); >> test-redis-temp.ts
npx ts-node test-redis-temp.ts
set "redis_test_result=!errorlevel!"
del test-redis-temp.ts 2>nul
if !redis_test_result! neq 0 (
call :warn "Redis connectivity test failed - continuing anyway"
) else (
call :log "Redis connectivity test passed"
)
goto :eof
:setup_directories
call :log "Setting up required directories..."
if not exist "logs" mkdir logs
if not exist "uploads" mkdir uploads
call :log "Directories created"
goto :eof
:start_app
call :log "Starting application for validation..."
REM Start the app in background
start /B "" npm start
REM Wait for app to start
timeout /t 10 /nobreak >nul
REM Test if the health endpoint responds (using curl if available)
set "PORT_VAR=!PORT!"
if "!PORT_VAR!"=="" set "PORT_VAR=3000"
curl -f http://localhost:!PORT_VAR!/health >nul 2>&1
if !errorlevel! equ 0 (
call :log "Application health check passed"
REM Try to stop the background process (this is tricky in batch)
taskkill /F /IM node.exe /FI "WINDOWTITLE eq npm start*" >nul 2>&1
) else (
call :error "Application health check failed"
taskkill /F /IM node.exe /FI "WINDOWTITLE eq npm start*" >nul 2>&1
exit /b 1
)
goto :eof
:deploy
call :log "🚀 Starting SerpentRace Backend production deployment..."
call :check_env
if !errorlevel! neq 0 exit /b 1
call :install_dependencies
if !errorlevel! neq 0 exit /b 1
call :run_build
if !errorlevel! neq 0 exit /b 1
call :setup_directories
if !errorlevel! neq 0 exit /b 1
call :test_database
if !errorlevel! neq 0 exit /b 1
call :test_redis
REM Redis test failure is not fatal
if not "%SKIP_APP_TEST%"=="true" (
call :start_app
if !errorlevel! neq 0 exit /b 1
) else (
call :warn "Skipping application startup test"
)
call :log "🎉 Deployment completed successfully!"
call :log "You can now start the application with: npm start"
goto :eof
:build_only
call :log "Running build-only deployment..."
call :check_env
if !errorlevel! neq 0 exit /b 1
call :install_dependencies
if !errorlevel! neq 0 exit /b 1
call :run_build
if !errorlevel! neq 0 exit /b 1
call :setup_directories
call :log "Build-only deployment completed"
goto :eof
:test_connections
call :log "Testing connections only..."
call :check_env
if !errorlevel! neq 0 exit /b 1
call :test_database
if !errorlevel! neq 0 exit /b 1
call :test_redis
call :log "Connection tests completed"
goto :eof
REM Main script logic
if "%1"=="" goto deploy
if "%1"=="deploy" goto deploy
if "%1"=="build-only" goto build_only
if "%1"=="test-connections" goto test_connections
echo Usage: %0 [deploy^|build-only^|test-connections]
echo deploy - Full deployment (default)
echo build-only - Only build, skip tests
echo test-connections - Test database and Redis connections
exit /b 1
+237
View File
@@ -0,0 +1,237 @@
#!/bin/bash
# SerpentRace Backend Production Deployment Script
# This script handles the complete deployment process
set -e # Exit on any error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
log() {
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}"
}
error() {
echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}"
}
warn() {
echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: $1${NC}"
}
info() {
echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')] INFO: $1${NC}"
}
# Check if required environment variables are set
check_env() {
log "Checking environment variables..."
required_vars=(
"DB_HOST"
"DB_PORT"
"DB_USERNAME"
"DB_PASSWORD"
"DB_NAME"
"JWT_SECRET"
"REDIS_HOST"
"REDIS_PORT"
)
missing_vars=()
for var in "${required_vars[@]}"; do
if [ -z "${!var}" ]; then
missing_vars+=("$var")
fi
done
if [ ${#missing_vars[@]} -ne 0 ]; then
error "Missing required environment variables: ${missing_vars[*]}"
error "Please set these variables before running the deployment"
exit 1
fi
log "All required environment variables are set"
}
# Install dependencies
install_dependencies() {
log "Installing production dependencies..."
npm ci --only=production
log "Dependencies installed successfully"
}
# Run the comprehensive build process
run_build() {
log "Running production build..."
npm run build:production
log "Build completed successfully"
}
# Test database connectivity
test_database() {
log "Testing database connectivity..."
# Use a simple TypeScript script to test connection
cat > /tmp/test-db.ts << 'EOF'
import { AppDataSource } from './src/Infrastructure/ormconfig';
async function testConnection() {
try {
await AppDataSource.initialize();
console.log('✅ Database connection successful');
await AppDataSource.destroy();
process.exit(0);
} catch (error) {
console.error('❌ Database connection failed:', error);
process.exit(1);
}
}
testConnection();
EOF
npx ts-node /tmp/test-db.ts || {
error "Database connectivity test failed"
exit 1
}
rm -f /tmp/test-db.ts
log "Database connectivity test passed"
}
# Test Redis connectivity
test_redis() {
log "Testing Redis connectivity..."
# Use a simple script to test Redis connection
cat > /tmp/test-redis.ts << 'EOF'
import { createClient } from 'redis';
async function testRedis() {
const client = createClient({
socket: {
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT || '6379')
}
});
try {
await client.connect();
await client.ping();
console.log('✅ Redis connection successful');
await client.disconnect();
process.exit(0);
} catch (error) {
console.error('❌ Redis connection failed:', error);
process.exit(1);
}
}
testRedis();
EOF
npx ts-node /tmp/test-redis.ts || {
warn "Redis connectivity test failed - continuing anyway"
}
rm -f /tmp/test-redis.ts
log "Redis connectivity test completed"
}
# Create required directories
setup_directories() {
log "Setting up required directories..."
mkdir -p logs
mkdir -p uploads
log "Directories created"
}
# Start the application (for testing)
start_app() {
log "Starting application for validation..."
# Start the app in background and test if it responds
npm start &
APP_PID=$!
# Wait for app to start
sleep 10
# Test if the health endpoint responds
if curl -f http://localhost:${PORT:-3000}/health > /dev/null 2>&1; then
log "Application health check passed"
kill $APP_PID
wait $APP_PID 2>/dev/null
else
error "Application health check failed"
kill $APP_PID 2>/dev/null || true
wait $APP_PID 2>/dev/null || true
exit 1
fi
}
# Main deployment function
deploy() {
log "🚀 Starting SerpentRace Backend production deployment..."
# Check environment
check_env
# Install dependencies
install_dependencies
# Run build process
run_build
# Setup directories
setup_directories
# Test connections
test_database
test_redis
# Test application startup
if [ "${SKIP_APP_TEST}" != "true" ]; then
start_app
else
warn "Skipping application startup test"
fi
log "🎉 Deployment completed successfully!"
info "You can now start the application with: npm start"
}
# Handle script arguments
case "${1:-deploy}" in
"deploy")
deploy
;;
"build-only")
log "Running build-only deployment..."
check_env
install_dependencies
run_build
setup_directories
log "Build-only deployment completed"
;;
"test-connections")
log "Testing connections only..."
check_env
test_database
test_redis
log "Connection tests completed"
;;
*)
echo "Usage: $0 [deploy|build-only|test-connections]"
echo " deploy - Full deployment (default)"
echo " build-only - Only build, skip tests"
echo " test-connections - Test database and Redis connections"
exit 1
;;
esac
@@ -0,0 +1,28 @@
import { execSync } from 'child_process';
const migrationName = process.argv[2];
if (!migrationName) {
console.error('Please provide a migration name: npm run migration:full <migration_name>');
process.exit(1);
}
try {
console.log(`Creating migration: ${migrationName}`);
execSync(`npx ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli migration:create ./src/Infrastructure/Migrationsettings/${migrationName}`, { stdio: 'inherit' });
console.log(`Generating migration: ${migrationName}`);
execSync(`npx ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli -d ./src/Infrastructure/ormconfig.ts migration:generate ./src/Infrastructure/Migrations/${migrationName}`, { stdio: 'inherit' });
console.log('Migration generated successfully!');
console.log('Running migration...');
execSync(`npx ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli -d ./src/Infrastructure/ormconfig.ts migration:run`, { stdio: 'inherit' });
} catch (error) {
if (error instanceof Error) {
console.error('Migration failed:', error.message);
} else {
console.error('Migration failed:', error);
}
process.exit(1);
}
@@ -0,0 +1,21 @@
# PowerShell script to start Redis and run tests
Write-Host "Starting Redis with Docker Compose..." -ForegroundColor Green
docker-compose up -d redis
# Wait for Redis to be ready
Write-Host "Waiting for Redis to be ready..." -ForegroundColor Yellow
do {
Write-Host "Checking Redis connection..." -ForegroundColor Gray
$result = docker-compose exec redis redis-cli ping 2>$null
if ($result -ne "PONG") {
Start-Sleep -Seconds 2
}
} while ($result -ne "PONG")
Write-Host "Redis is ready!" -ForegroundColor Green
# Run Redis tests
Write-Host "Running Redis tests..." -ForegroundColor Cyan
npm test -- --testNamePattern="RedisService"
Write-Host "Done!" -ForegroundColor Green
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash
# Script to start Redis and run tests
echo "Starting Redis with Docker Compose..."
docker-compose up -d redis
# Wait for Redis to be ready
echo "Waiting for Redis to be ready..."
until docker-compose exec redis redis-cli ping; do
echo "Waiting for Redis..."
sleep 2
done
echo "Redis is ready!"
# Run Redis tests
echo "Running Redis tests..."
npm test -- --testNamePattern="RedisService"
echo "Done!"