import { test } from '@playwright/test'; import { testLogger } from '../shared/utils/test-logger'; import { testDataGenerator, UserData, RoleData, MenuData } from './test-data'; export type DataStrategy = 'real' | 'mock' | 'hybrid'; export interface DataStrategyConfig { strategy: DataStrategy; mockEnabled: boolean; realDataEnabled: boolean; autoCleanup: boolean; } export interface DataSnapshot { name: string; timestamp: number; data: Map; } export class DataStrategyManager { private strategy: DataStrategy; private config: DataStrategyConfig; private snapshots: Map = new Map(); private testData: Map = new Map(); constructor(config?: Partial) { this.config = { strategy: 'hybrid', mockEnabled: true, realDataEnabled: true, autoCleanup: true, ...config }; this.strategy = this.config.strategy; testLogger.info(`DataStrategyManager initialized with strategy: ${this.strategy}`); } setStrategy(strategy: DataStrategy): void { this.strategy = strategy; this.config.strategy = strategy; testLogger.info(`Data strategy changed to: ${strategy}`); } getStrategy(): DataStrategy { return this.strategy; } getConfig(): DataStrategyConfig { return { ...this.config }; } selectDataSource(testTags: string[]): DataStrategy { testLogger.debug(`Selecting data source for tags: ${testTags.join(', ')}`); if (this.config.strategy === 'real') { testLogger.debug('Using real data strategy (forced)'); return 'real'; } if (this.config.strategy === 'mock') { testLogger.debug('Using mock data strategy (forced)'); return 'mock'; } if (this.config.strategy === 'hybrid') { return this.selectHybridDataSource(testTags); } return 'mock'; } private selectHybridDataSource(testTags: string[]): DataStrategy { const hasSmokeTag = testTags.includes('@smoke'); const hasRegressionTag = testTags.includes('@regression'); const hasFullTag = testTags.includes('@full'); const hasCriticalTag = testTags.includes('@critical'); if (hasCriticalTag) { testLogger.debug('Hybrid strategy: Using real data for @critical tests'); return 'real'; } if (hasFullTag) { testLogger.debug('Hybrid strategy: Using real data for @full tests'); return 'real'; } if (hasRegressionTag) { testLogger.debug('Hybrid strategy: Using hybrid data for @regression tests'); return 'hybrid'; } if (hasSmokeTag) { testLogger.debug('Hybrid strategy: Using mock data for @smoke tests'); return 'mock'; } testLogger.debug('Hybrid strategy: Defaulting to mock data'); return 'mock'; } async createData(dataType: string, data: any, testTags: string[] = []): Promise { const dataSource = this.selectDataSource(testTags); testLogger.info(`Creating ${dataType} using ${dataSource} data source`); if (dataSource === 'mock') { return this.createMockData(dataType, data); } if (dataSource === 'real') { return this.createRealData(dataType, data); } return this.createHybridData(dataType, data); } private createMockData(dataType: string, data: any): any { testLogger.debug(`Creating mock data for ${dataType}`); switch (dataType) { case 'user': return testDataGenerator.generateUserData(data); case 'role': return testDataGenerator.generateRoleData(data); case 'menu': return testDataGenerator.generateMenuData(data); case 'permission': return testDataGenerator.generatePermissionData(data); default: return data; } } private createRealData(dataType: string, data: any): any { testLogger.debug(`Creating real data for ${dataType} (requires API connection)`); return data; } private createHybridData(dataType: string, data: any): any { testLogger.debug(`Creating hybrid data for ${dataType}`); const mockData = this.createMockData(dataType, data); const realData = this.createRealData(dataType, data); return { ...mockData, _dataSource: 'hybrid', _mockData: mockData, _realData: realData }; } async cleanupData(dataType: string, dataId: string | number): Promise { testLogger.info(`Cleaning up ${dataType} with id: ${dataId}`); if (this.config.autoCleanup) { this.removeTestData(dataType, dataId); } } async cleanupAll(): Promise { testLogger.info('Cleaning up all test data'); this.testData.clear(); this.snapshots.clear(); testLogger.info('All test data cleaned up'); } async createSnapshot(snapshotName: string): Promise { testLogger.info(`Creating snapshot: ${snapshotName}`); const snapshot: DataSnapshot = { name: snapshotName, timestamp: Date.now(), data: new Map(this.testData) }; this.snapshots.set(snapshotName, snapshot); testLogger.info(`Snapshot created: ${snapshotName} at ${new Date(snapshot.timestamp).toISOString()}`); return snapshot; } async rollbackToSnapshot(snapshotName: string): Promise { testLogger.info(`Rolling back to snapshot: ${snapshotName}`); const snapshot = this.snapshots.get(snapshotName); if (!snapshot) { throw new Error(`Snapshot not found: ${snapshotName}`); } this.testData = new Map(snapshot.data); testLogger.info(`Rolled back to snapshot: ${snapshotName}`); } private addTestData(dataType: string, data: any): void { if (!this.testData.has(dataType)) { this.testData.set(dataType, []); } this.testData.get(dataType)!.push(data); } private removeTestData(dataType: string, dataId: string | number): void { const items = this.testData.get(dataType); if (items) { const index = items.findIndex(item => item.id === dataId); if (index !== -1) { items.splice(index, 1); } } } getTestData(dataType: string): any[] { return this.testData.get(dataType) || []; } getSnapshot(snapshotName: string): DataSnapshot | undefined { return this.snapshots.get(snapshotName); } getAllSnapshots(): DataSnapshot[] { return Array.from(this.snapshots.values()); } deleteSnapshot(snapshotName: string): void { this.snapshots.delete(snapshotName); testLogger.info(`Snapshot deleted: ${snapshotName}`); } getStatistics(): { totalTestData: number; totalSnapshots: number; strategy: DataStrategy; config: DataStrategyConfig; } { let totalTestData = 0; const testDataValues = Array.from(this.testData.values()); for (const items of testDataValues) { totalTestData += items.length; } return { totalTestData, totalSnapshots: this.snapshots.size, strategy: this.strategy, config: this.getConfig() }; } } export const dataStrategyManager = new DataStrategyManager();