UNPKG

@myria/leaderboard-ts-sdk

Version:

Myria Leaderboard typescripts SDK which will manage leaderboard for game developers

451 lines 30.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const LeaderboardManager_1 = require("../modules/LeaderboardManager"); const LeaderboardAPI_1 = require("../core/apis/LeaderboardAPI"); const ILeaderboard_types_1 = require("../types/ILeaderboard.types"); const myria_core_sdk_1 = require("myria-core-sdk"); // Mock the LeaderboardAPI class jest.mock('../core/apis/LeaderboardAPI'); const mockLeaderboardsData = { items: [ { name: 'Leaderboard 1', description: 'Test leaderboard 1', updateScoreStrategy: 'ACCUMULATE', gameName: 'Test Game', totalPeriods: 10, livePeriodInDays: 30, availableAt: '2024-01-01T00:00:00Z', status: 'active', currentPeriod: 1, dataPersistenceInDays: 365, expireAt: '2025-01-01T00:00:00Z', id: 1, airdropContractAddress: '', daysToNextPeriod: '', gameMetadata: {}, configMetadata: {}, isApplyRewardAllPeriods: false, }, ], meta: { totalItems: 1, itemCount: 1, itemsPerPage: 10, totalPages: 1, currentPage: 1, }, }; const mockApiResponse = { status: 'success', data: mockLeaderboardsData, }; describe('LeaderboardManager', () => { let leaderboardManager; let mockLeaderboardAPI; const env = myria_core_sdk_1.EnvTypes.STAGING; // Example environment const developerApiKey = 'Developer_Api_Key'; beforeEach(() => { mockLeaderboardAPI = new LeaderboardAPI_1.LeaderboardAPI(env); const leaderboardParams = { env: myria_core_sdk_1.EnvTypes.STAGING, apiKey: developerApiKey, }; leaderboardManager = new LeaderboardManager_1.LeaderboardManager(leaderboardParams); leaderboardManager['leaderboardAPI'] = mockLeaderboardAPI; }); afterEach(() => { jest.clearAllMocks(); // Reset mocks }); // Get List score by leaderId it('should getScoreByLeaderboardId a leaderboard successfully', async () => { // Given const queryScoreParams = { page: 1, limit: 10, leaderboardId: 1, sortingField: 'score', orderBy: ILeaderboard_types_1.EOrderBy.DESC, filters: { period: 1, userId: '0x5eb1a04db9190230f231627c1b673cdb19f77374ff4780158322f23177e801', }, }; const queryScoreLeaderboardData = { items: [ { id: 5, userId: '0x5eb1a04db9190230f231627c1b673cdb19f77374ff4780158322f23177e801', leaderboardId: 21, period: 1, score: 130, createdAt: '2024-08-12T08:34:32.291Z', updatedAt: '2024-08-16T03:27:59.919Z', rank: 1, }, ], meta: { totalItems: 1, itemCount: 1, itemsPerPage: 10, totalPages: 1, currentPage: 1, }, }; // Act mockLeaderboardAPI.getScoresByLeaderboardId.mockResolvedValue({ status: 'success', data: queryScoreLeaderboardData, }); // Act const result = await leaderboardManager.queryScoresByLeaderboardId(queryScoreParams); // Assert expect(result.data).toEqual(queryScoreLeaderboardData); }); it('should throw an error if leaderboard query fails', async () => { // Given const queryScoreParams = { page: 1, limit: 10, leaderboardId: 19, sortingField: 'score', orderBy: ILeaderboard_types_1.EOrderBy.DESC, filters: { period: 1, userId: '2', }, }; mockLeaderboardAPI.getScoresByLeaderboardId.mockRejectedValue({ status: 'error', data: null, }); // Act & Assert await expect(leaderboardManager.queryScoresByLeaderboardId(queryScoreParams)).rejects.toThrow('Failed to query scores'); }); it('should validate missing query parameters', async () => { const invalidParams = [ { page: 0, leaderboardId: 1, }, { page: 1, leaderboardId: 0, }, ]; for (const params of invalidParams) { await expect(leaderboardManager.queryScoresByLeaderboardId(params)).rejects.toThrow(); } }); it('should validate missing query filters userId parameters', async () => { const invalidParams = [ { page: 1, leaderboardId: 21, filters: { userId: '', score: 0, }, }, ]; for (const params of invalidParams) { await expect(leaderboardManager.queryScoresByLeaderboardId(params)).rejects.toThrow(); } }); // Get list scores by leaderboard id and user id it('should getScoreByLeaderboardIdAndUserId a leaderboard successfully', async () => { // Given const queryScoreParams = { leaderboardId: 21, userId: '0x5eb1a04db9190230f231627c1b673cdb19f77374ff4780158322f23177e801', period: 1, }; const queryScoreLeaderboardData = { leaderboardId: 21, userId: '0x5eb1a04db9190230f231627c1b673cdb19f77374ff4780158322f23177e803', score: 24, period: 1, leaderboard: { id: 21, name: 'weekly-demo-function', description: 'Testing weekly-demo-function', updateScoreStrategy: 'ACCUMULATE', gameName: 'Demo', status: 'ACTIVE', livePeriodInDays: 7, enablePeriodRefresh: false, currentPeriod: 1, dataPersistenceInDays: 14, expireAt: '2024-08-19T08:31:54.891Z', availableAt: '2024-08-12T08:31:54.891Z', airdropContractAddress: '', daysToNextPeriod: '', gameMetadata: {}, configMetadata: {}, isApplyRewardAllPeriods: false, }, user: { userId: '0x5eb1a04db9190230f231627c1b673cdb19f77374ff4780158322f23177e803', username: '', displayName: '', }, }; // Act mockLeaderboardAPI.getScoresByLeaderboardIdAndUserId.mockResolvedValue({ status: 'success', data: queryScoreLeaderboardData, }); // Act const result = await leaderboardManager.getScoresByPlayerId(queryScoreParams); // Assert expect(result.data).toEqual(queryScoreLeaderboardData); }); it('should throw an error if leaderboard id and userId query fails', async () => { // Given const queryScoreParams = { leaderboardId: 19, userId: '0x5eb1a04db9190230f231627c1b673cdb19f77374ff4780158322f23177e801', }; mockLeaderboardAPI.getScoresByLeaderboardIdAndUserId.mockRejectedValue({ status: 'error', data: null, }); // Act & Assert await expect(leaderboardManager.getScoresByPlayerId(queryScoreParams)).rejects.toThrow('Failed to query scores by player id: error'); }); it('should validate missing query score by leaderboard and user id parameters', async () => { const invalidParams = [ { leaderboardId: 0, userId: '0x5eb1a04db9190230f231627c1b673cdb19f77374ff4780158322f23177e801', }, { leaderboardId: 21, userId: '', }, ]; for (const params of invalidParams) { await expect(leaderboardManager.getScoresByPlayerId(params)).rejects.toThrow(); } }); // Create leaderboard it('should create a leaderboard successfully', async () => { // Given const leaderboardParams = { name: 'Test Leaderboard', description: 'A test leaderboard', gameName: 'Test Game', livePeriodInDays: 10, totalPeriods: 5, updateScoreStrategy: 'ACCUMULATE', availableAt: '', enableMetadata: false, }; const leaderboardData = { id: 1, ...leaderboardParams, status: 'ACTIVE', currentPeriod: 5, dataPersistenceInDays: 10, expireAt: '', updatedAt: '', createdAt: '', enablePeriodRefresh: false, developerId: '', metadata: undefined, airdropContractAddress: '', daysToNextPeriod: '', whitelist: undefined, rewards: undefined, gameMetadata: {}, configMetadata: {}, isApplyRewardAllPeriods: false, }; mockLeaderboardAPI.createLeaderboard.mockResolvedValue({ status: 'success', data: leaderboardData, }); // Act const result = await leaderboardManager.createLeaderboard(leaderboardParams); // Assert expect(result).toEqual(leaderboardData); expect(mockLeaderboardAPI.createLeaderboard).toHaveBeenCalledWith(leaderboardParams, developerApiKey); }); it('should throw an error if leaderboard creation fails', async () => { // Given const leaderboardParams = { name: 'Test Leaderboard', description: 'A test leaderboard', gameName: 'Test Game', livePeriodInDays: 10, totalPeriods: 5, updateScoreStrategy: 'OVERWRITE', availableAt: '', enableMetadata: false, }; mockLeaderboardAPI.createLeaderboard.mockResolvedValue({ status: 'error', data: null, }); // Act & Assert await expect(leaderboardManager.createLeaderboard(leaderboardParams)).rejects.toThrow('Create leaderboard failed: {"status":"error","data":null}'); }); it('should validate missing parameters', async () => { const invalidParams = [ { name: '', description: 'desc', gameName: 'game', livePeriodInDays: 10, totalPeriods: 5, updateScoreStrategy: 'ACCUMULATE', }, { name: 'name', description: '', gameName: 'game', livePeriodInDays: 10, totalPeriods: 5, updateScoreStrategy: 'ACCUMULATE', }, { name: 'name', description: 'desc', gameName: '', livePeriodInDays: 10, totalPeriods: 5, updateScoreStrategy: 'ACCUMULATE', }, { name: 'name', description: 'desc', gameName: 'game', livePeriodInDays: 0, totalPeriods: 5, updateScoreStrategy: 'ACCUMULATE', }, { name: 'name', description: 'desc', gameName: 'game', livePeriodInDays: 10, totalPeriods: 0, updateScoreStrategy: 'ACCUMULATE', }, { name: 'name', description: 'desc', gameName: 'game', livePeriodInDays: 10, totalPeriods: 5, updateScoreStrategy: '', }, ]; for (const params of invalidParams) { await expect(leaderboardManager.createLeaderboard(params)).rejects.toThrow(); } }); // Post score it('should postscore a leaderboard successfully', async () => { // Given const newScoreParams = { leaderboardId: 21, items: [ { score: 240, displayName: 'userDisplayname', userId: 'userId', username: 'username', }, ], }; const newScoreLeaderboardData = { success: [ { score: 240, userId: '0x724f337bf0fa934db9aa3ec6dea49b03c54ad3cc', username: 'vule', id: 39, displayName: 'Test', }, ], failed: [], }; // Act mockLeaderboardAPI.postNewScore.mockResolvedValue({ status: 'success', data: newScoreLeaderboardData, }); // Act const result = await leaderboardManager.postPlayerScore(newScoreParams); // Assert expect(result.data).toEqual(newScoreLeaderboardData); }); it('should throw an error if post score fails', async () => { // Given const newScoreParams = { leaderboardId: 19, items: [ { score: 0, userId: 'userId', displayName: 'username', username: 'username', }, ], }; mockLeaderboardAPI.postNewScore.mockRejectedValue({ status: 'error', data: null, }); // Act & Assert await expect(leaderboardManager.postPlayerScore(newScoreParams)).rejects.toThrow('Failed to post score for player'); }); it('should validate missing post score parameters', async () => { const invalidParams = [ { leaderboardId: 0, items: [ { score: 20, userId: '0x724f337bF0Fa934dB9aa3ec6dEa49B03c54AD3cc', username: 'username', displayName: 'displayname', }, ], }, { leaderboardId: 21, items: [ { score: 20, userId: '', username: 'username', displayName: 'displayname', }, ], }, ]; for (const params of invalidParams) { await expect(leaderboardManager.postPlayerScore(params)).rejects.toThrow(); } }); it('should retrieve leaderboards successfully', async () => { mockLeaderboardAPI.getLeaderboards.mockResolvedValue(mockApiResponse); const params = { page: 1, limit: 10 }; // Act const result = await leaderboardManager.getLeaderboards(params); // Assert expect(mockLeaderboardAPI.getLeaderboards).toHaveBeenCalledWith(params, 'Developer_Api_Key'); expect(result).toEqual(mockApiResponse); }); it('should throw an error if the API call for retrieve leaderboards fails', async () => { const errorMessage = 'Failed to retrieve leaderboard with Params {"page":1,"limit":10}'; mockLeaderboardAPI.getLeaderboards.mockRejectedValue(new Error(errorMessage)); const params = { page: 1, limit: 10 }; // Act & Assert await expect(leaderboardManager.getLeaderboards(params)).rejects.toThrow(`Failed to retrieve leaderboard with Params ${JSON.stringify(params)}`); expect(mockLeaderboardAPI.getLeaderboards).toHaveBeenCalledWith(params, 'Developer_Api_Key'); }); }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGVhZGVyYm9hcmQudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy90ZXN0cy9MZWFkZXJib2FyZC50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsc0VBQW1FO0FBQ25FLGdFQUE2RDtBQUM3RCxvRUFXcUM7QUFDckMsbURBQTBDO0FBSTFDLGdDQUFnQztBQUNoQyxJQUFJLENBQUMsSUFBSSxDQUFDLDZCQUE2QixDQUFDLENBQUM7QUFFekMsTUFBTSxvQkFBb0IsR0FBK0M7SUFDdkUsS0FBSyxFQUFFO1FBQ0w7WUFDRSxJQUFJLEVBQUUsZUFBZTtZQUNyQixXQUFXLEVBQUUsb0JBQW9CO1lBQ2pDLG1CQUFtQixFQUFFLFlBQVk7WUFDakMsUUFBUSxFQUFFLFdBQVc7WUFDckIsWUFBWSxFQUFFLEVBQUU7WUFDaEIsZ0JBQWdCLEVBQUUsRUFBRTtZQUNwQixXQUFXLEVBQUUsc0JBQXNCO1lBQ25DLE1BQU0sRUFBRSxRQUFRO1lBQ2hCLGFBQWEsRUFBRSxDQUFDO1lBQ2hCLHFCQUFxQixFQUFFLEdBQUc7WUFDMUIsUUFBUSxFQUFFLHNCQUFzQjtZQUNoQyxFQUFFLEVBQUUsQ0FBQztZQUNMLHNCQUFzQixFQUFFLEVBQUU7WUFDMUIsZ0JBQWdCLEVBQUUsRUFBRTtZQUNwQixZQUFZLEVBQUUsRUFBRTtZQUNoQixjQUFjLEVBQUUsRUFBRTtZQUNsQix1QkFBdUIsRUFBRSxLQUFLO1NBQy9CO0tBQ0Y7SUFDRCxJQUFJLEVBQUU7UUFDSixVQUFVLEVBQUUsQ0FBQztRQUNiLFNBQVMsRUFBRSxDQUFDO1FBQ1osWUFBWSxFQUFFLEVBQUU7UUFDaEIsVUFBVSxFQUFFLENBQUM7UUFDYixXQUFXLEVBQUUsQ0FBQztLQUNmO0NBQ0YsQ0FBQztBQUVGLE1BQU0sZUFBZSxHQUVqQjtJQUNGLE1BQU0sRUFBRSxTQUFTO0lBQ2pCLElBQUksRUFBRSxvQkFBb0I7Q0FDM0IsQ0FBQztBQUVGLFFBQVEsQ0FBQyxvQkFB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