advanced-games-library
Version:
Advanced Gaming Library for React Native - Four Complete Games with iOS Compatibility Fixes
311 lines (243 loc) • 10.3 kB
text/typescript
import { DefaultStorageService, MemoryStorage } from '../services/StorageService';
import { PlayerData, GameResult, GameDifficulty } from '../core/types';
// Mock AsyncStorage
const mockAsyncStorage = {
setItem: jest.fn(),
getItem: jest.fn(),
removeItem: jest.fn(),
getAllKeys: jest.fn(),
multiRemove: jest.fn(),
clear: jest.fn()
};
// Mock the import
jest.mock('@react-native-async-storage/async-storage', () => mockAsyncStorage);
describe('StorageService', () => {
let storageService: DefaultStorageService;
beforeEach(() => {
storageService = new DefaultStorageService();
jest.clearAllMocks();
});
describe('Initialization', () => {
it('should initialize with AsyncStorage', async () => {
await expect(storageService.initialize()).resolves.not.toThrow();
});
});
describe('Player Data Storage', () => {
const samplePlayerData: PlayerData = {
playerId: 'test123',
firstName: 'Test',
lastName: 'User',
age: 25,
createdAt: new Date('2023-01-01'),
lastActive: new Date('2023-01-02'),
totalGamesPlayed: 5,
achievements: []
};
it('should save player data', async () => {
mockAsyncStorage.setItem.mockResolvedValue(undefined);
await expect(storageService.savePlayerData(samplePlayerData)).resolves.not.toThrow();
expect(mockAsyncStorage.setItem).toHaveBeenCalledWith(
'@games_library_player',
JSON.stringify(samplePlayerData)
);
});
it('should get player data', async () => {
const storedData = JSON.stringify(samplePlayerData);
mockAsyncStorage.getItem.mockResolvedValue(storedData);
const result = await storageService.getPlayerData();
expect(result).not.toBeNull();
expect(result!.playerId).toBe('test123');
expect(result!.firstName).toBe('Test');
expect(result!.createdAt).toBeInstanceOf(Date);
});
it('should return null when no player data exists', async () => {
mockAsyncStorage.getItem.mockResolvedValue(null);
const result = await storageService.getPlayerData();
expect(result).toBeNull();
});
it('should handle corrupted player data gracefully', async () => {
mockAsyncStorage.getItem.mockResolvedValue('invalid json');
const result = await storageService.getPlayerData();
expect(result).toBeNull();
});
it('should clear player data', async () => {
mockAsyncStorage.removeItem.mockResolvedValue(undefined);
await expect(storageService.clearPlayerData()).resolves.not.toThrow();
expect(mockAsyncStorage.removeItem).toHaveBeenCalledWith('@games_library_player');
});
});
describe('Game Results Storage', () => {
const sampleGameResult: GameResult = {
gameId: 'memory-match',
playerId: 'test123',
score: 850,
maxScore: 1000,
timeSpent: 120000,
completed: true,
difficulty: GameDifficulty.MEDIUM,
customData: { moves: 15 },
timestamp: new Date('2023-01-01'),
sessionId: 'session123'
};
it('should save game result', async () => {
// Mock existing empty results
mockAsyncStorage.getItem.mockResolvedValue('[]');
mockAsyncStorage.setItem.mockResolvedValue(undefined);
await expect(storageService.saveGameResult(sampleGameResult)).resolves.not.toThrow();
expect(mockAsyncStorage.setItem).toHaveBeenCalled();
});
it('should append to existing game results', async () => {
const existingResult: GameResult = {
...sampleGameResult,
sessionId: 'session122'
};
mockAsyncStorage.getItem.mockResolvedValue(JSON.stringify([existingResult]));
mockAsyncStorage.setItem.mockResolvedValue(undefined);
await storageService.saveGameResult(sampleGameResult);
const setItemCall = mockAsyncStorage.setItem.mock.calls[0];
const savedData = JSON.parse(setItemCall[1]);
expect(savedData).toHaveLength(2);
});
it('should limit results to last 100', async () => {
// Create 101 results
const manyResults = Array.from({ length: 101 }, (_, i) => ({
...sampleGameResult,
sessionId: `session${i}`
}));
mockAsyncStorage.getItem.mockResolvedValue(JSON.stringify(manyResults));
mockAsyncStorage.setItem.mockResolvedValue(undefined);
await storageService.saveGameResult(sampleGameResult);
const setItemCall = mockAsyncStorage.setItem.mock.calls[0];
const savedData = JSON.parse(setItemCall[1]);
expect(savedData).toHaveLength(100);
});
it('should get game results', async () => {
const results = [sampleGameResult];
mockAsyncStorage.getItem.mockResolvedValue(JSON.stringify(results));
const retrievedResults = await storageService.getGameResults();
expect(retrievedResults).toHaveLength(1);
expect(retrievedResults[0].gameId).toBe('memory-match');
expect(retrievedResults[0].timestamp).toBeInstanceOf(Date);
});
it('should filter results by player ID', async () => {
const results = [
{ ...sampleGameResult, playerId: 'player1' },
{ ...sampleGameResult, playerId: 'player2' },
{ ...sampleGameResult, playerId: 'player1' }
];
mockAsyncStorage.getItem.mockResolvedValue(JSON.stringify(results));
const filteredResults = await storageService.getGameResults('player1');
expect(filteredResults).toHaveLength(2);
filteredResults.forEach(result => {
expect(result.playerId).toBe('player1');
});
});
it('should return empty array when no results exist', async () => {
mockAsyncStorage.getItem.mockResolvedValue(null);
const results = await storageService.getGameResults();
expect(results).toEqual([]);
});
it('should clear game results', async () => {
mockAsyncStorage.removeItem.mockResolvedValue(undefined);
await expect(storageService.clearGameResults()).resolves.not.toThrow();
expect(mockAsyncStorage.removeItem).toHaveBeenCalledWith('@games_library_results');
});
});
describe('Generic Data Storage', () => {
it('should save and retrieve generic data', async () => {
const testData = { test: 'value', number: 42 };
const testKey = 'test_key';
mockAsyncStorage.setItem.mockResolvedValue(undefined);
mockAsyncStorage.getItem.mockResolvedValue(JSON.stringify(testData));
await storageService.saveData(testKey, testData);
const retrievedData = await storageService.getData(testKey);
expect(mockAsyncStorage.setItem).toHaveBeenCalledWith(testKey, JSON.stringify(testData));
expect(retrievedData).toEqual(testData);
});
it('should remove data', async () => {
const testKey = 'test_key';
mockAsyncStorage.removeItem.mockResolvedValue(undefined);
await expect(storageService.removeData(testKey)).resolves.not.toThrow();
expect(mockAsyncStorage.removeItem).toHaveBeenCalledWith(testKey);
});
it('should get all keys', async () => {
const keys = ['key1', 'key2', '@games_library_player'];
mockAsyncStorage.getAllKeys.mockResolvedValue(keys);
const retrievedKeys = await storageService.getAllKeys();
expect(retrievedKeys).toEqual(keys);
});
it('should clear all library data', async () => {
const allKeys = ['key1', '@games_library_player', '@games_library_results', 'key2'];
mockAsyncStorage.getAllKeys.mockResolvedValue(allKeys);
mockAsyncStorage.multiRemove.mockResolvedValue(undefined);
await storageService.clear();
expect(mockAsyncStorage.multiRemove).toHaveBeenCalledWith([
'@games_library_player',
'@games_library_results'
]);
});
});
describe('Error Handling', () => {
it('should handle save errors', async () => {
const playerData: PlayerData = {
playerId: 'test123',
firstName: 'Test',
lastName: 'User',
createdAt: new Date(),
lastActive: new Date(),
totalGamesPlayed: 0,
achievements: []
};
mockAsyncStorage.setItem.mockRejectedValue(new Error('Storage full'));
await expect(storageService.savePlayerData(playerData)).rejects.toThrow('Failed to save player data');
});
it('should handle retrieval errors', async () => {
mockAsyncStorage.getItem.mockRejectedValue(new Error('Storage error'));
const result = await storageService.getPlayerData();
expect(result).toBeNull();
});
});
});
describe('MemoryStorage', () => {
let memoryStorage: MemoryStorage;
beforeEach(() => {
memoryStorage = new MemoryStorage();
});
it('should store and retrieve items', async () => {
await memoryStorage.setItem('key1', 'value1');
const retrieved = await memoryStorage.getItem('key1');
expect(retrieved).toBe('value1');
});
it('should return null for non-existent keys', async () => {
const retrieved = await memoryStorage.getItem('non-existent');
expect(retrieved).toBeNull();
});
it('should remove items', async () => {
await memoryStorage.setItem('key1', 'value1');
await memoryStorage.removeItem('key1');
const retrieved = await memoryStorage.getItem('key1');
expect(retrieved).toBeNull();
});
it('should get all keys', async () => {
await memoryStorage.setItem('key1', 'value1');
await memoryStorage.setItem('key2', 'value2');
const keys = await memoryStorage.getAllKeys();
expect(keys.sort()).toEqual(['key1', 'key2']);
});
it('should remove multiple items', async () => {
await memoryStorage.setItem('key1', 'value1');
await memoryStorage.setItem('key2', 'value2');
await memoryStorage.setItem('key3', 'value3');
await memoryStorage.multiRemove(['key1', 'key3']);
expect(await memoryStorage.getItem('key1')).toBeNull();
expect(await memoryStorage.getItem('key2')).toBe('value2');
expect(await memoryStorage.getItem('key3')).toBeNull();
});
it('should clear all items', async () => {
await memoryStorage.setItem('key1', 'value1');
await memoryStorage.setItem('key2', 'value2');
await memoryStorage.clear();
const keys = await memoryStorage.getAllKeys();
expect(keys).toHaveLength(0);
});
});