2023-10-27 23:48:24 +02:00
|
|
|
import "reflect-metadata";
|
2024-05-21 19:59:04 +02:00
|
|
|
|
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";
|
2024-05-21 19:59:04 +02:00
|
|
|
import { IPmcData } from "@spt/models/eft/common/IPmcData";
|
|
|
|
import { Item } from "@spt/models/eft/common/tables/IItem";
|
|
|
|
import { ITraderBase } from "@spt/models/eft/common/tables/ITrader";
|
|
|
|
import { IItemEventRouterResponse } from "@spt/models/eft/itemEvent/IItemEventRouterResponse";
|
|
|
|
import { IProcessBuyTradeRequestData } from "@spt/models/eft/trade/IProcessBuyTradeRequestData";
|
|
|
|
import { PaymentService } from "@spt/services/PaymentService";
|
|
|
|
import { HashUtil } from "@spt/utils/HashUtil";
|
2023-10-30 22:45:17 +01:00
|
|
|
|
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 = {
|
2023-11-13 18:38:16 +01:00
|
|
|
TradersInfo: { [traderId]: { salesSum: 0, unlocked: true, disabled: false } },
|
|
|
|
Inventory: { 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,
|
2023-11-13 18:38:16 +01:00
|
|
|
scheme_items: [{ id: costItemId, count: costAmount }],
|
2023-10-30 22:45:17 +01:00
|
|
|
} as IProcessBuyTradeRequestData;
|
|
|
|
|
|
|
|
// Inconsequential profile ID
|
|
|
|
const sessionID = hashUtil.generate();
|
|
|
|
|
|
|
|
const itemEventRouterResponse = {
|
|
|
|
warnings: [],
|
2024-04-12 02:56:55 +02:00
|
|
|
profileChanges: { [sessionID]: { _id: sessionID, items: { new: [], change: [], del: [] } } },
|
2023-10-30 22:45:17 +01:00
|
|
|
} as unknown as IItemEventRouterResponse;
|
|
|
|
|
|
|
|
// Mock the logger debug method to return void.
|
2024-04-12 02:56:55 +02:00
|
|
|
vi.spyOn((paymentService as any).logger, "debug").mockResolvedValue(undefined);
|
2023-10-30 22:45:17 +01:00
|
|
|
|
|
|
|
// Mock the trader helper to return a trader with the currency of Roubles.
|
2024-04-12 02:56:55 +02:00
|
|
|
const getTraderSpy = 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.
|
2024-04-12 02:56:55 +02:00
|
|
|
const addPaymentToOutputSpy = vi.spyOn(paymentService as any, "addPaymentToOutput").mockImplementation(
|
|
|
|
(
|
|
|
|
pmcData: IPmcData,
|
|
|
|
currencyTpl: string,
|
|
|
|
amountToPay: number,
|
|
|
|
sessionIdentifier: string,
|
|
|
|
output: IItemEventRouterResponse,
|
|
|
|
) =>
|
|
|
|
{
|
|
|
|
moneyItem.upd.StackObjectsCount -= costAmount;
|
|
|
|
output.profileChanges[sessionIdentifier].items.change.push(moneyItem);
|
|
|
|
},
|
|
|
|
);
|
2023-10-30 22:45:17 +01:00
|
|
|
|
|
|
|
// Mock the traderHelper lvlUp method to return void.
|
2024-04-12 02:56:55 +02:00
|
|
|
const lvlUpSpy = vi.spyOn((paymentService as any).traderHelper, "lvlUp").mockResolvedValue(undefined);
|
2023-11-10 23:21:20 +01:00
|
|
|
|
2024-04-12 02:56:55 +02:00
|
|
|
paymentService.payMoney(pmcData, processBuyTradeRequestData, sessionID, itemEventRouterResponse);
|
2023-10-30 22:45:17 +01:00
|
|
|
|
|
|
|
// Check for absence of output warnings.
|
2024-04-12 02:56:55 +02:00
|
|
|
expect(itemEventRouterResponse.warnings).toHaveLength(0);
|
2023-10-30 22:45:17 +01:00
|
|
|
|
|
|
|
// Check that the currency change was correctly handled.
|
2024-04-12 02:56:55 +02:00
|
|
|
expect(itemEventRouterResponse.profileChanges[sessionID].items.change).toHaveLength(1);
|
|
|
|
expect(itemEventRouterResponse.profileChanges[sessionID].items.change[0]._id).toBe(costItemId);
|
|
|
|
expect(itemEventRouterResponse.profileChanges[sessionID].items.change[0]._tpl).toBe(costItemTpl);
|
|
|
|
expect(itemEventRouterResponse.profileChanges[sessionID].items.change[0].upd.StackObjectsCount).toBe(
|
|
|
|
costAmount * 3,
|
|
|
|
);
|
2023-10-30 22:45:17 +01:00
|
|
|
|
|
|
|
// Check if mocked methods were called as expected.
|
2024-04-12 02:56:55 +02:00
|
|
|
expect(getTraderSpy).toBeCalledTimes(1);
|
2023-11-10 23:21:20 +01:00
|
|
|
expect(addPaymentToOutputSpy).toBeCalledWith(
|
|
|
|
expect.anything(),
|
|
|
|
costItemTpl,
|
|
|
|
costAmount,
|
|
|
|
sessionID,
|
|
|
|
expect.anything(),
|
|
|
|
);
|
2024-04-12 02:56:55 +02:00
|
|
|
expect(lvlUpSpy).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
|
|
|
});
|