@myria/leaderboard-ts-sdk
Version:
Myria Leaderboard typescripts SDK which will manage leaderboard for game developers
451 lines • 30.1 kB
JavaScript
"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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