2023-10-30 22:45:17 +01:00
|
|
|
/* eslint-disable @typescript-eslint/naming-convention */
|
2023-10-27 23:48:24 +02:00
|
|
|
import "reflect-metadata";
|
2023-10-28 21:40:11 +02:00
|
|
|
import { container } from "tsyringe";
|
2023-11-10 23:21:20 +01:00
|
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
2023-10-28 05:55:34 +02:00
|
|
|
|
2023-10-27 23:48:24 +02:00
|
|
|
import { PaymentService } from "@spt-aki/services/PaymentService";
|
|
|
|
|
2023-10-30 22:45:17 +01:00
|
|
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
2023-11-10 23:21:20 +01:00
|
|
|
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
|
|
|
import { ITraderBase } from "@spt-aki/models/eft/common/tables/ITrader";
|
2023-10-30 22:45:17 +01:00
|
|
|
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
2023-11-10 23:21:20 +01:00
|
|
|
import { IProcessBuyTradeRequestData } from "@spt-aki/models/eft/trade/IProcessBuyTradeRequestData";
|
2023-10-30 22:45:17 +01:00
|
|
|
import { HashUtil } from "@spt-aki/utils/HashUtil";
|
|
|
|
|
2023-10-27 23:48:24 +02:00
|
|
|
describe("PaymentService", () =>
|
|
|
|
{
|
2023-11-04 12:22:07 +01:00
|
|
|
let paymentService: any; // Using "any" to access private/protected methods without type errors.
|
2023-10-27 23:48:24 +02:00
|
|
|
|
2023-11-06 20:39:12 +01:00
|
|
|
beforeEach(() =>
|
2023-10-27 23:48:24 +02:00
|
|
|
{
|
|
|
|
paymentService = container.resolve<PaymentService>("PaymentService");
|
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(() =>
|
|
|
|
{
|
2023-10-28 05:55:34 +02:00
|
|
|
vi.restoreAllMocks();
|
2023-10-27 23:48:24 +02:00
|
|
|
});
|
|
|
|
|
2023-10-30 22:45:17 +01:00
|
|
|
describe("payMoney", () =>
|
2023-10-27 23:48:24 +02:00
|
|
|
{
|
2023-10-30 22:45:17 +01:00
|
|
|
it("should output a currency change when a single non-barter item is purchased from a trader", () =>
|
2023-10-27 23:48:24 +02:00
|
|
|
{
|
2023-10-30 22:45:17 +01:00
|
|
|
const hashUtil = container.resolve<HashUtil>("HashUtil");
|
|
|
|
|
|
|
|
const traderId = "54cb57776803fa99248b456e"; // Therapist
|
|
|
|
const purchaseItemId = hashUtil.generate(); // Inconsequential ID
|
|
|
|
const purchaseQuantity = 1; // The amount of the items that the player is purchasing.
|
|
|
|
const costItemId = hashUtil.generate(); // Inconsequential ID
|
|
|
|
const costItemTpl = "5449016a4bdc2d6f028b456f"; // Roubles
|
|
|
|
const costAmount = 17896; // The amount of roubles that the item costs.
|
|
|
|
|
|
|
|
// Object representing a money item.
|
|
|
|
const moneyItem = {
|
|
|
|
_id: costItemId,
|
|
|
|
_tpl: costItemTpl,
|
|
|
|
upd: {
|
2023-11-10 23:21:20 +01:00
|
|
|
StackObjectsCount: costAmount * 4, // More than enough.
|
|
|
|
},
|
2023-10-30 22:45:17 +01:00
|
|
|
} as Item;
|
|
|
|
|
|
|
|
// Object representing the player's PMC inventory.
|
|
|
|
const pmcData = {
|
|
|
|
TradersInfo: {
|
|
|
|
[traderId]: {
|
|
|
|
salesSum: 0,
|
|
|
|
unlocked: true,
|
2023-11-10 23:21:20 +01:00
|
|
|
disabled: false,
|
|
|
|
},
|
2023-10-30 22:45:17 +01:00
|
|
|
},
|
|
|
|
Inventory: {
|
2023-11-10 23:21:20 +01:00
|
|
|
items: [moneyItem],
|
|
|
|
},
|
2023-10-30 22:45:17 +01:00
|
|
|
} as unknown as IPmcData;
|
|
|
|
|
|
|
|
// Buy a factory map from Therapist... although it doesn't really matter what the item is as there's no
|
|
|
|
// template ID provided in the request data, just the ID.
|
|
|
|
const processBuyTradeRequestData = {
|
|
|
|
Action: "TradingConfirm",
|
|
|
|
type: "buy_from_trader",
|
|
|
|
tid: traderId,
|
|
|
|
item_id: purchaseItemId,
|
|
|
|
count: purchaseQuantity,
|
|
|
|
scheme_id: 0,
|
|
|
|
scheme_items: [
|
|
|
|
{
|
|
|
|
id: costItemId,
|
2023-11-10 23:21:20 +01:00
|
|
|
count: costAmount,
|
|
|
|
},
|
|
|
|
],
|
2023-10-30 22:45:17 +01:00
|
|
|
} as IProcessBuyTradeRequestData;
|
|
|
|
|
|
|
|
// Inconsequential profile ID
|
|
|
|
const sessionID = hashUtil.generate();
|
|
|
|
|
|
|
|
const itemEventRouterResponse = {
|
|
|
|
warnings: [],
|
|
|
|
profileChanges: {
|
|
|
|
sessionID: {
|
|
|
|
_id: sessionID,
|
|
|
|
items: {
|
|
|
|
new: [],
|
|
|
|
change: [],
|
2023-11-10 23:21:20 +01:00
|
|
|
del: [],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2023-10-30 22:45:17 +01:00
|
|
|
} as unknown as IItemEventRouterResponse;
|
|
|
|
|
|
|
|
// Mock the logger debug method to return void.
|
|
|
|
vi.spyOn((paymentService as any).logger, "debug").mockImplementation(() =>
|
|
|
|
{});
|
|
|
|
|
|
|
|
// Mock the trader helper to return a trader with the currency of Roubles.
|
2023-11-10 23:21:20 +01:00
|
|
|
const traderHelperGetTraderSpy = vi.spyOn((paymentService as any).traderHelper, "getTrader")
|
|
|
|
.mockReturnValue({
|
|
|
|
tid: traderId,
|
|
|
|
currency: "RUB",
|
|
|
|
} as unknown as ITraderBase);
|
2023-10-30 22:45:17 +01:00
|
|
|
|
|
|
|
// Mock the addPaymentToOutput method to subtract the item cost from the money stack.
|
2023-11-10 23:21:20 +01:00
|
|
|
const addPaymentToOutputSpy = vi.spyOn(paymentService as any, "addPaymentToOutput").mockImplementation(() =>
|
2023-10-30 22:45:17 +01:00
|
|
|
{
|
|
|
|
moneyItem.upd.StackObjectsCount -= costAmount;
|
|
|
|
return {
|
|
|
|
warnings: [],
|
|
|
|
profileChanges: {
|
|
|
|
[sessionID]: {
|
|
|
|
items: {
|
2023-11-10 23:21:20 +01:00
|
|
|
change: [moneyItem],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2023-10-30 22:45:17 +01:00
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
// Mock the traderHelper lvlUp method to return void.
|
2023-11-10 23:21:20 +01:00
|
|
|
const traderHelperLvlUpSpy = vi.spyOn((paymentService as any).traderHelper, "lvlUp").mockImplementation(
|
|
|
|
() =>
|
|
|
|
{},
|
|
|
|
);
|
|
|
|
|
|
|
|
const output = paymentService.payMoney(
|
|
|
|
pmcData,
|
|
|
|
processBuyTradeRequestData,
|
|
|
|
sessionID,
|
|
|
|
itemEventRouterResponse,
|
|
|
|
);
|
2023-10-30 22:45:17 +01:00
|
|
|
|
|
|
|
// Check for absence of output warnings.
|
|
|
|
expect(output.warnings).toHaveLength(0);
|
|
|
|
|
|
|
|
// Check that the currency change was correctly handled.
|
|
|
|
expect(output.profileChanges[sessionID].items.change).toHaveLength(1);
|
|
|
|
expect(output.profileChanges[sessionID].items.change[0]._id).toBe(costItemId);
|
|
|
|
expect(output.profileChanges[sessionID].items.change[0]._tpl).toBe(costItemTpl);
|
|
|
|
expect(output.profileChanges[sessionID].items.change[0].upd.StackObjectsCount).toBe(costAmount * 3);
|
|
|
|
|
|
|
|
// Check if mocked methods were called as expected.
|
|
|
|
expect(traderHelperGetTraderSpy).toBeCalledTimes(1);
|
2023-11-10 23:21:20 +01:00
|
|
|
expect(addPaymentToOutputSpy).toBeCalledWith(
|
|
|
|
expect.anything(),
|
|
|
|
costItemTpl,
|
|
|
|
costAmount,
|
|
|
|
sessionID,
|
|
|
|
expect.anything(),
|
|
|
|
);
|
2023-10-30 22:45:17 +01:00
|
|
|
expect(traderHelperLvlUpSpy).toBeCalledTimes(1);
|
2023-10-27 23:48:24 +02:00
|
|
|
});
|
|
|
|
});
|
2023-11-04 12:22:07 +01:00
|
|
|
|
|
|
|
describe("isInStash", () =>
|
|
|
|
{
|
|
|
|
it("should return true when item is direct parent of stash", () =>
|
|
|
|
{
|
|
|
|
const hashUtil = container.resolve<HashUtil>("HashUtil");
|
|
|
|
const stashItem: Item = {
|
|
|
|
_id: "stashid",
|
2023-11-10 23:21:20 +01:00
|
|
|
_tpl: "55d7217a4bdc2d86028b456d", // standard stash id
|
2023-11-04 12:22:07 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
const inventoryItemToFind: Item = {
|
|
|
|
_id: hashUtil.generate(),
|
|
|
|
_tpl: "544fb6cc4bdc2d34748b456e", // Slickers chocolate bar
|
|
|
|
parentId: stashItem._id,
|
2023-11-10 23:21:20 +01:00
|
|
|
slotId: "hideout",
|
2023-11-04 12:22:07 +01:00
|
|
|
};
|
|
|
|
const playerInventory = [stashItem, inventoryItemToFind];
|
|
|
|
|
|
|
|
const result = paymentService.isInStash(inventoryItemToFind._id, playerInventory, stashItem._id);
|
|
|
|
|
|
|
|
expect(result).toBe(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should return true when item is indirect parent of inventory", () =>
|
|
|
|
{
|
|
|
|
const hashUtil = container.resolve<HashUtil>("HashUtil");
|
|
|
|
const stashItem: Item = {
|
|
|
|
_id: "stashId",
|
2023-11-10 23:21:20 +01:00
|
|
|
_tpl: "55d7217a4bdc2d86028b456d", // standard stash id
|
2023-11-04 12:22:07 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
const foodBagToHoldItemToFind: Item = {
|
|
|
|
_id: hashUtil.generate(),
|
|
|
|
_tpl: "5c093db286f7740a1b2617e3",
|
|
|
|
parentId: stashItem._id,
|
2023-11-10 23:21:20 +01:00
|
|
|
slotId: "hideout",
|
2023-11-04 12:22:07 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
const inventoryItemToFind: Item = {
|
|
|
|
_id: hashUtil.generate(),
|
|
|
|
_tpl: "544fb6cc4bdc2d34748b456e", // Slickers chocolate bar
|
2023-11-10 23:21:20 +01:00
|
|
|
parentId: foodBagToHoldItemToFind._id,
|
2023-11-04 12:22:07 +01:00
|
|
|
};
|
|
|
|
const playerInventory = [stashItem, foodBagToHoldItemToFind, inventoryItemToFind];
|
|
|
|
|
|
|
|
const result = paymentService.isInStash(inventoryItemToFind._id, playerInventory, stashItem._id);
|
|
|
|
|
|
|
|
expect(result).toBe(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should return false when desired item is not in inventory", () =>
|
|
|
|
{
|
|
|
|
const hashUtil = container.resolve<HashUtil>("HashUtil");
|
|
|
|
const stashItem: Item = {
|
|
|
|
_id: "stashId",
|
2023-11-10 23:21:20 +01:00
|
|
|
_tpl: "55d7217a4bdc2d86028b456d", // standard stash id
|
2023-11-04 12:22:07 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
const inventoryItemToFind: Item = {
|
|
|
|
_id: hashUtil.generate(),
|
|
|
|
_tpl: "544fb6cc4bdc2d34748b456e", // Slickers chocolate bar
|
|
|
|
parentId: stashItem._id,
|
2023-11-10 23:21:20 +01:00
|
|
|
slotId: "hideout",
|
2023-11-04 12:22:07 +01:00
|
|
|
};
|
|
|
|
const playerInventory = [stashItem, inventoryItemToFind];
|
|
|
|
|
|
|
|
const result = paymentService.isInStash("notCorrectId", playerInventory, stashItem._id);
|
|
|
|
|
|
|
|
expect(result).toBe(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should return false when player inventory array has no inventory item", () =>
|
|
|
|
{
|
|
|
|
const hashUtil = container.resolve<HashUtil>("HashUtil");
|
|
|
|
const stashItem: Item = {
|
|
|
|
_id: "stashId",
|
2023-11-10 23:21:20 +01:00
|
|
|
_tpl: "55d7217a4bdc2d86028b456d", // standard stash id
|
2023-11-04 12:22:07 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
const inventoryItemToFind: Item = {
|
|
|
|
_id: hashUtil.generate(),
|
|
|
|
_tpl: "544fb6cc4bdc2d34748b456e", // Slickers chocolate bar
|
|
|
|
parentId: stashItem._id,
|
2023-11-10 23:21:20 +01:00
|
|
|
slotId: "hideout",
|
2023-11-04 12:22:07 +01:00
|
|
|
};
|
2023-11-10 23:21:20 +01:00
|
|
|
const playerInventory = [inventoryItemToFind];
|
2023-11-04 12:22:07 +01:00
|
|
|
|
|
|
|
const result = paymentService.isInStash("notCorrectId", playerInventory, stashItem._id);
|
|
|
|
|
|
|
|
expect(result).toBe(false);
|
|
|
|
});
|
|
|
|
});
|
2023-10-27 23:48:24 +02:00
|
|
|
});
|