ed8dbbd195
Boogidy, boogidy, boogidy. Let's go racing! 🏎️ Removes the over-complicated and super-slow setup we had with ESLint & Prettier in favour of Biome. The largest change with the formatting is moving from Allman braces to 1TBS braces. Other than that, it's *pretty much* the same. Ah, and that Biome runs formatting and linting on the entire project about x10 faster than the old system ran formatting on one file. Seriously, the guy who came up with that last solution should be fired. :runs: I've kept all of the formatting and linting commands the same as before, with the main mamma-jamma being: `npm run format`, which applies formatting and linting changes to the entire project. Formatting-on-save works (quickly!) by (1) ensuring that you're working within the VSC workspace (as you should be), and (2) have the recommended Biome VSC extension installed. The link to the Biome extension is in the README. This limits our options on code formatting going forward; Biome, like prettier, is very opinionated with very few formatting options available. But I see this as a good thing. I'd rather spend my time arguing about which gun in Tarkov is the best, rather than coding brace styles... ...It's the TOZ, and it always will be. Don't DM me. Co-authored-by: chomp <chomp@noreply.dev.sp-tarkov.com> Reviewed-on: https://dev.sp-tarkov.com/SPT/Server/pulls/383 Co-authored-by: Refringe <me@refringe.com> Co-committed-by: Refringe <me@refringe.com>
1494 lines
62 KiB
TypeScript
1494 lines
62 KiB
TypeScript
import "reflect-metadata";
|
|
|
|
import { container } from "tsyringe";
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { InsuranceController } from "@spt/controllers/InsuranceController";
|
|
import { Item } from "@spt/models/eft/common/tables/IItem";
|
|
import { Insurance } from "@spt/models/eft/profile/ISptProfile";
|
|
import { MessageType } from "@spt/models/enums/MessageType";
|
|
import { ProfileInsuranceFactory } from "@tests/__factories__/ProfileInsurance.factory";
|
|
|
|
describe("InsuranceController", () =>
|
|
{
|
|
let insuranceController: any; // Using "any" to access private/protected methods without type errors.
|
|
let insuranceFixture: Insurance[];
|
|
|
|
beforeEach(() =>
|
|
{
|
|
insuranceController = container.resolve<InsuranceController>("InsuranceController");
|
|
insuranceFixture = new ProfileInsuranceFactory().adjustPackageDates().get();
|
|
});
|
|
|
|
afterEach(() =>
|
|
{
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
describe("processReturn", () =>
|
|
{
|
|
it("should process return for all profiles", () =>
|
|
{
|
|
const session1 = "session1";
|
|
const session2 = "session2";
|
|
const profiles = { [session1]: {}, [session2]: {} };
|
|
const getProfilesSpy = vi.spyOn(insuranceController.saveServer, "getProfiles").mockReturnValue(profiles);
|
|
const processReturnByProfileSpy = vi.spyOn(insuranceController, "processReturnByProfile").mockReturnValue(
|
|
vi.fn(),
|
|
);
|
|
|
|
// Execute the method.
|
|
insuranceController.processReturn();
|
|
|
|
// Should make a call to get all of the profiles.
|
|
expect(getProfilesSpy).toHaveBeenCalledTimes(1);
|
|
|
|
// Should process each returned profile.
|
|
expect(processReturnByProfileSpy).toHaveBeenCalledTimes(2);
|
|
expect(processReturnByProfileSpy).toHaveBeenCalledWith(session1);
|
|
expect(processReturnByProfileSpy).toHaveBeenCalledWith(session2);
|
|
});
|
|
|
|
it("should not attempt to process profiles if no profiles exist", () =>
|
|
{
|
|
const processReturnByProfileSpy = vi.spyOn(insuranceController, "processReturnByProfile")
|
|
.mockImplementation(vi.fn());
|
|
|
|
// Execute the method.
|
|
insuranceController.processReturn();
|
|
|
|
// Should not process any profiles.
|
|
expect(processReturnByProfileSpy).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("processReturnByProfile", () =>
|
|
{
|
|
it("should process insurance for a profile", () =>
|
|
{
|
|
const sessionId = "session-id";
|
|
|
|
// Mock internal methods.
|
|
const mockFilterInsuredItems = vi.spyOn(insuranceController, "filterInsuredItems").mockReturnValue(
|
|
insuranceFixture,
|
|
);
|
|
const mockProcessInsuredItems = vi.spyOn(insuranceController, "processInsuredItems").mockImplementation(
|
|
vi.fn(),
|
|
);
|
|
|
|
insuranceController.processReturnByProfile(sessionId);
|
|
|
|
// Verify that the correct methods were called.
|
|
expect(mockFilterInsuredItems).toBeCalledTimes(1);
|
|
expect(mockProcessInsuredItems).toHaveBeenNthCalledWith(1, insuranceFixture, sessionId);
|
|
});
|
|
|
|
it("should skip processing if there are no insurance packages found within the profile", () =>
|
|
{
|
|
const sessionId = "session-id";
|
|
|
|
// Mock internal methods.
|
|
const mockFilterInsuredItems = vi.spyOn(insuranceController, "filterInsuredItems").mockReturnValue([]); // Return an empty array.
|
|
const mockProcessInsuredItems = vi.spyOn(insuranceController, "processInsuredItems").mockImplementation(
|
|
vi.fn(),
|
|
);
|
|
|
|
insuranceController.processReturnByProfile(sessionId);
|
|
|
|
// Verify that the correct methods were called.
|
|
expect(mockFilterInsuredItems).toBeCalledTimes(1);
|
|
expect(mockProcessInsuredItems).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("filterInsuredItems", () =>
|
|
{
|
|
it("should return all insurance packages if no time is specified", () =>
|
|
{
|
|
const sessionID = "session-id";
|
|
const insured = JSON.parse(JSON.stringify(insuranceFixture));
|
|
|
|
// Mock getProfile to return the fixture.
|
|
const mockGetProfile = vi.spyOn(insuranceController.saveServer, "getProfile").mockReturnValue({
|
|
insurance: insured,
|
|
});
|
|
const mockLoggerDebug = vi.spyOn(insuranceController.logger, "debug");
|
|
|
|
// Execute the method.
|
|
const insuredFiltered = insuranceController.filterInsuredItems(sessionID);
|
|
|
|
// Verify that the correct methods were called.
|
|
expect(mockGetProfile).toBeCalledTimes(1);
|
|
expect(mockLoggerDebug).toBeCalledTimes(1);
|
|
expect(insuredFiltered.length).toBe(insuranceFixture.length);
|
|
});
|
|
|
|
it("should filter out insurance packages with scheduledTime values in the future", () =>
|
|
{
|
|
const sessionID = "session-id";
|
|
const insured = JSON.parse(JSON.stringify(insuranceFixture));
|
|
|
|
// Set the scheduledTime to 2 hours in the future so it should be skipped over.
|
|
insured[0].scheduledTime = Math.floor((Date.now() / 1000) + (2 * 60 * 60));
|
|
|
|
// Mock getProfile to return the fixture.
|
|
const mockGetProfile = vi.spyOn(insuranceController.saveServer, "getProfile").mockReturnValue({
|
|
insurance: insured,
|
|
});
|
|
const mockLoggerDebug = vi.spyOn(insuranceController.logger, "debug");
|
|
|
|
// Execute the method.
|
|
const insuredFiltered = insuranceController.filterInsuredItems(sessionID);
|
|
|
|
// Verify that the correct methods were called.
|
|
expect(mockGetProfile).toBeCalledTimes(1);
|
|
expect(mockLoggerDebug).toBeCalledTimes(1);
|
|
expect(insuredFiltered.length).toBe(insuranceFixture.length - 1); // Should be 1 less than the original fixture.
|
|
});
|
|
|
|
it("should return an empty array if no insurance packages match the criteria", () =>
|
|
{
|
|
const sessionID = "session-id";
|
|
const insured = JSON.parse(JSON.stringify(insuranceFixture));
|
|
|
|
// Mock getProfile to return the fixture.
|
|
const mockGetProfile = vi.spyOn(insuranceController.saveServer, "getProfile").mockReturnValue({
|
|
insurance: insured,
|
|
});
|
|
const mockLoggerDebug = vi.spyOn(insuranceController.logger, "debug");
|
|
|
|
// Execute the method, passing in a time that's two hours in the past. The function should use this past
|
|
// date as the target to judge if an insurance package is ready to be sent or not.
|
|
const insuredFiltered = insuranceController.filterInsuredItems(
|
|
sessionID,
|
|
Math.floor((Date.now() / 1000) - (2 * 60 * 60)),
|
|
);
|
|
|
|
// Verify that the correct methods were called.
|
|
expect(mockGetProfile).toBeCalledTimes(1);
|
|
expect(mockLoggerDebug).toBeCalledTimes(1);
|
|
|
|
// Verify that the returned array is empty.
|
|
expect(insuredFiltered.length).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("processInsuredItems", () =>
|
|
{
|
|
it("should log information about the insurance package", () =>
|
|
{
|
|
const sessionId = "session-id";
|
|
const numberOfItems = 666;
|
|
|
|
// Spy on the logger.debug method.
|
|
const mockLoggerDebug = vi.spyOn(insuranceController.logger, "debug");
|
|
vi.spyOn(insuranceController, "countAllInsuranceItems").mockReturnValue(numberOfItems);
|
|
vi.spyOn(insuranceController, "findItemsToDelete").mockImplementation(vi.fn());
|
|
vi.spyOn(insuranceController, "removeItemsFromInsurance").mockImplementation(vi.fn());
|
|
vi.spyOn(insuranceController.itemHelper, "adoptOrphanedItems").mockImplementation(vi.fn());
|
|
vi.spyOn(insuranceController, "sendMail").mockImplementation(vi.fn());
|
|
vi.spyOn(insuranceController, "removeInsurancePackageFromProfile").mockImplementation(vi.fn());
|
|
vi.spyOn(insuranceController.insuranceService.saveServer, "getProfile").mockImplementation(vi.fn());
|
|
|
|
// Execute the method.
|
|
insuranceController.processInsuredItems(insuranceFixture, sessionId);
|
|
|
|
// Verify that the log was written.
|
|
expect(mockLoggerDebug).toBeCalledWith(
|
|
`Processing ${insuranceFixture.length} insurance packages, which includes a total of ${numberOfItems} items, in profile ${sessionId}`,
|
|
);
|
|
});
|
|
|
|
it("should call processing methods once per insurance package", () =>
|
|
{
|
|
const sessionId = "session-id";
|
|
const packageCount = insuranceFixture.length;
|
|
|
|
// Spy on the processing methods.
|
|
const mockFindItemsToDelete = vi.spyOn(insuranceController, "findItemsToDelete").mockImplementation(
|
|
vi.fn(),
|
|
);
|
|
const mockRemoveItemsFromInsurance = vi.spyOn(insuranceController, "removeItemsFromInsurance")
|
|
.mockImplementation(vi.fn());
|
|
const mockAdoptOrphanedItems = vi.spyOn(insuranceController.itemHelper, "adoptOrphanedItems")
|
|
.mockImplementation(vi.fn());
|
|
const mockSendMail = vi.spyOn(insuranceController, "sendMail").mockImplementation(vi.fn());
|
|
const mockRemoveInsurancePackageFromProfile = vi.spyOn(
|
|
insuranceController,
|
|
"removeInsurancePackageFromProfile",
|
|
).mockImplementation(vi.fn());
|
|
|
|
vi.spyOn(insuranceController.insuranceService.saveServer, "getProfile").mockReturnValue({});
|
|
|
|
// Execute the method.
|
|
insuranceController.processInsuredItems(insuranceFixture, sessionId);
|
|
|
|
// Verify that the processing methods were called once per insurance package.
|
|
expect(mockFindItemsToDelete).toBeCalledTimes(packageCount);
|
|
expect(mockRemoveItemsFromInsurance).toBeCalledTimes(packageCount);
|
|
expect(mockAdoptOrphanedItems).toBeCalledTimes(packageCount);
|
|
expect(mockSendMail).toBeCalledTimes(packageCount);
|
|
expect(mockRemoveInsurancePackageFromProfile).toBeCalledTimes(packageCount);
|
|
});
|
|
});
|
|
|
|
describe("countAllInsuranceItems", () =>
|
|
{
|
|
it("should return the total number of items in all insurance packages", () =>
|
|
{
|
|
const insurance = [{
|
|
_id: "1",
|
|
upd: 1234567890,
|
|
items: [{ _id: "1", parentId: "1", slotId: "1" }, { _id: "2", parentId: "1", slotId: "2" }],
|
|
}, {
|
|
_id: "2",
|
|
upd: 1234567890,
|
|
items: [{ _id: "3", parentId: "2", slotId: "1" }, { _id: "4", parentId: "2", slotId: "2" }, {
|
|
_id: "5",
|
|
parentId: "2",
|
|
slotId: "3",
|
|
}],
|
|
}];
|
|
const expectedCount = 5; // 2 items in the first package + 3 items in the second package.
|
|
|
|
// Execute the method.
|
|
const actualCount = insuranceController.countAllInsuranceItems(insurance);
|
|
|
|
// Verify that the result is correct.
|
|
expect(actualCount).toBe(expectedCount);
|
|
});
|
|
|
|
it("should return 0 if there are no insurance packages", () =>
|
|
{
|
|
const insurance = [];
|
|
const expectedCount = 0;
|
|
|
|
// Execute the method.
|
|
const actualCount = insuranceController.countAllInsuranceItems(insurance);
|
|
|
|
// Verify that the result is correct.
|
|
expect(actualCount).toBe(expectedCount);
|
|
});
|
|
|
|
it("should return 0 if there are no items in any of the insurance packages", () =>
|
|
{
|
|
const insurance = [{ _id: "1", upd: 1234567890, items: [] }, { _id: "2", upd: 1234567890, items: [] }];
|
|
const expectedCount = 0;
|
|
|
|
// Execute the method.
|
|
const actualCount = insuranceController.countAllInsuranceItems(insurance);
|
|
|
|
// Verify that the result is correct.
|
|
expect(actualCount).toBe(expectedCount);
|
|
});
|
|
});
|
|
|
|
describe("removeInsurancePackageFromProfile", () =>
|
|
{
|
|
it("should remove the specified insurance package from the profile", () =>
|
|
{
|
|
const sessionID = "session-id";
|
|
const packageToRemove = {
|
|
traderId: "54cb50c76803fa8b248b4571",
|
|
systemData: { date: "01.11.2023", time: "11:18", location: "factory4_day" },
|
|
};
|
|
const profile = {
|
|
insurance: [{
|
|
traderId: "54cb50c76803fa8b248b4571",
|
|
systemData: { date: "01.11.2023", time: "11:18", location: "factory4_day" },
|
|
}, {
|
|
traderId: "54cb57776803fa99248b456e",
|
|
systemData: { date: "01.11.2023", time: "10:51", location: "factory4_day" },
|
|
}],
|
|
};
|
|
|
|
// Mock the getProfile method to return the above profile.
|
|
vi.spyOn(insuranceController.saveServer, "getProfile").mockReturnValue(profile);
|
|
|
|
// Execute the method.
|
|
insuranceController.removeInsurancePackageFromProfile(sessionID, packageToRemove);
|
|
|
|
// Verify that the specified insurance package was removed.
|
|
expect(profile.insurance.length).toBe(1);
|
|
expect(profile.insurance).toStrictEqual([{
|
|
traderId: "54cb57776803fa99248b456e",
|
|
systemData: { date: "01.11.2023", time: "10:51", location: "factory4_day" },
|
|
}]);
|
|
});
|
|
|
|
it("should log a message indicating that the package was removed", () =>
|
|
{
|
|
const sessionID = "session-id";
|
|
const packageToRemove = {
|
|
traderId: "54cb50c76803fa8b248b4571",
|
|
systemData: { date: "01.11.2023", time: "11:18", location: "factory4_day" },
|
|
};
|
|
const profile = {
|
|
insurance: [{
|
|
traderId: "54cb50c76803fa8b248b4571",
|
|
systemData: { date: "01.11.2023", time: "11:18", location: "factory4_day" },
|
|
}],
|
|
};
|
|
|
|
// Mock the getProfile method to return the above profile.
|
|
vi.spyOn(insuranceController.saveServer, "getProfile").mockReturnValue(profile);
|
|
|
|
// Spy on the logger.debug method.
|
|
const mockLoggerDebug = vi.spyOn(insuranceController.logger, "debug");
|
|
|
|
// Execute the method.
|
|
insuranceController.removeInsurancePackageFromProfile(sessionID, packageToRemove);
|
|
|
|
// Verify that the log was written.
|
|
expect(mockLoggerDebug).toBeCalledWith(
|
|
`Removed processed insurance package. Remaining packages: ${profile.insurance.length}`,
|
|
);
|
|
});
|
|
|
|
it("should not remove any packages if the specified package is not found", () =>
|
|
{
|
|
const sessionID = "session-id";
|
|
const packageToRemove = {
|
|
traderId: "54cb50c76803fa8b248b4571",
|
|
systemData: { date: "01.11.2023", time: "11:25", location: "factory4_day" },
|
|
};
|
|
const profile = {
|
|
insurance: [{
|
|
traderId: "54cb50c76803fa8b248b4571",
|
|
systemData: { date: "01.11.2023", time: "11:18", location: "factory4_day" },
|
|
}, {
|
|
traderId: "54cb57776803fa99248b456e",
|
|
systemData: { date: "01.11.2023", time: "10:51", location: "factory4_day" },
|
|
}],
|
|
};
|
|
|
|
// Mock the getProfile method to return the above profile.
|
|
vi.spyOn(insuranceController.saveServer, "getProfile").mockReturnValue(profile);
|
|
|
|
// Execute the method.
|
|
insuranceController.removeInsurancePackageFromProfile(sessionID, packageToRemove);
|
|
|
|
// Verify that the specified insurance package was removed.
|
|
expect(profile.insurance.length).toBe(2);
|
|
});
|
|
});
|
|
|
|
describe("findItemsToDelete", () =>
|
|
{
|
|
it("should handle an empty insurance package", () =>
|
|
{
|
|
const insurancePackage = insuranceFixture[0];
|
|
insurancePackage.items = [];
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.findItemsToDelete(
|
|
insuranceController.hashUtil.generate(),
|
|
insurancePackage,
|
|
);
|
|
|
|
// Verify that the result is correct.
|
|
expect(result.size).toBe(0);
|
|
});
|
|
|
|
it("should handle regular items", () =>
|
|
{
|
|
// Remove attachment items from the fixture.
|
|
insuranceFixture = new ProfileInsuranceFactory().adjustPackageDates().removeAttachmentItems().get();
|
|
const insured = insuranceFixture[0];
|
|
const numberOfItems = insured.items.length;
|
|
|
|
// Mock helper methods.
|
|
const mockPopulateParentAttachmentsMap = vi.spyOn(insuranceController, "populateParentAttachmentsMap");
|
|
const mockIsAttachmentAttached = vi.spyOn(insuranceController.itemHelper, "isAttachmentAttached");
|
|
const mockProcessAttachments = vi.spyOn(insuranceController, "processAttachments").mockImplementation(
|
|
vi.fn(),
|
|
);
|
|
|
|
// Add all items to the toDelete set. Not realistic, but it's fine for this test.
|
|
const mockProcessRegularItems = vi.fn((insured, toDelete) =>
|
|
{
|
|
for (const item of insured.items)
|
|
{
|
|
toDelete.add(item._id);
|
|
}
|
|
});
|
|
vi.spyOn(insuranceController, "processRegularItems").mockImplementation(mockProcessRegularItems);
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.findItemsToDelete(insuranceController.hashUtil.generate(), insured);
|
|
|
|
// Verify that the correct methods were called.
|
|
expect(mockPopulateParentAttachmentsMap).toHaveBeenCalledTimes(1);
|
|
expect(mockIsAttachmentAttached).toHaveBeenCalled();
|
|
expect(mockProcessRegularItems).toHaveBeenCalledTimes(1);
|
|
expect(mockProcessAttachments).not.toHaveBeenCalled();
|
|
|
|
// Verify that the result is correct.
|
|
expect(result.size).toBe(numberOfItems);
|
|
expect(result).toEqual(new Set(insured.items.map((item) => item._id)));
|
|
});
|
|
|
|
it("should ignore orphaned attachments", () =>
|
|
{
|
|
// Remove regular items from the fixture, creating orphaned attachments.
|
|
insuranceFixture = new ProfileInsuranceFactory().adjustPackageDates().removeRegularItems().get();
|
|
const insured = insuranceFixture[0];
|
|
|
|
// Mock helper methods.
|
|
const mockProcessRegularItems = vi.spyOn(insuranceController, "processRegularItems");
|
|
const mockProcessAttachments = vi.spyOn(insuranceController, "processAttachments");
|
|
|
|
// Since no parent attachments exist, the map should be empty.
|
|
const mockPopulateParentAttachmentsMap = vi.fn(() =>
|
|
{
|
|
return new Map<string, Item[]>();
|
|
});
|
|
vi.spyOn(insuranceController, "populateParentAttachmentsMap").mockImplementation(
|
|
mockPopulateParentAttachmentsMap,
|
|
);
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.findItemsToDelete(insuranceController.hashUtil.generate(), insured);
|
|
|
|
// Verify that the correct methods were called.
|
|
expect(mockPopulateParentAttachmentsMap).toHaveBeenCalled();
|
|
expect(mockProcessRegularItems).not.toHaveBeenCalled();
|
|
expect(mockProcessAttachments).not.toHaveBeenCalled();
|
|
|
|
// Verify that the result is correct.
|
|
expect(result.size).toBe(0);
|
|
expect(result).toEqual(new Set());
|
|
});
|
|
|
|
it("should handle a mix of regular items and attachments", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
const numberOfItems = insured.items.length;
|
|
|
|
// Mock helper methods.
|
|
const mockPopulateParentAttachmentsMap = vi.spyOn(insuranceController, "populateParentAttachmentsMap");
|
|
|
|
// Add all items to the toDelete set. Not realistic, but it's fine for this test.
|
|
const mockProcessRegularItems = vi.fn((insured, toDelete) =>
|
|
{
|
|
for (const item of insured.items)
|
|
{
|
|
toDelete.add(item._id);
|
|
}
|
|
});
|
|
vi.spyOn(insuranceController, "processRegularItems").mockImplementation(mockProcessRegularItems);
|
|
const mockProcessAttachments = vi.fn((parentAttachmentsMap, itemsMap, traderId, toDelete) =>
|
|
{
|
|
for (const item of insured.items)
|
|
{
|
|
toDelete.add(item._id);
|
|
}
|
|
});
|
|
vi.spyOn(insuranceController, "processAttachments").mockImplementation(mockProcessAttachments);
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.findItemsToDelete(insuranceController.hashUtil.generate(), insured);
|
|
|
|
// Verify that the correct methods were called.
|
|
expect(mockPopulateParentAttachmentsMap).toHaveBeenCalled();
|
|
expect(mockProcessRegularItems).toHaveBeenCalled();
|
|
expect(mockProcessAttachments).toHaveBeenCalled();
|
|
|
|
// Verify that the result is correct.
|
|
expect(result.size).toBe(numberOfItems);
|
|
expect(result).toEqual(new Set(insured.items.map((item) => item._id)));
|
|
});
|
|
|
|
it("should return an empty set if no items are to be deleted", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
|
|
// Mock helper methods.
|
|
const mockPopulateParentAttachmentsMap = vi.spyOn(insuranceController, "populateParentAttachmentsMap");
|
|
|
|
// Don't add any items to the toDelete set.
|
|
const mockProcessRegularItems = vi.spyOn(insuranceController, "processRegularItems").mockImplementation(
|
|
vi.fn(),
|
|
);
|
|
const mockProcessAttachments = vi.spyOn(insuranceController, "processAttachments").mockImplementation(
|
|
vi.fn(),
|
|
);
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.findItemsToDelete(insuranceController.hashUtil.generate(), insured);
|
|
|
|
// Verify that the correct methods were called.
|
|
expect(mockPopulateParentAttachmentsMap).toHaveBeenCalled();
|
|
expect(mockProcessRegularItems).toHaveBeenCalled();
|
|
expect(mockProcessAttachments).toHaveBeenCalled();
|
|
|
|
// Verify that the result is correct.
|
|
expect(result.size).toBe(0);
|
|
expect(result).toEqual(new Set());
|
|
});
|
|
|
|
it("should log the number of items to be deleted", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
const numberOfItems = insured.items.length;
|
|
|
|
// Mock helper methods.
|
|
const mockLoggerDebug = vi.spyOn(insuranceController.logger, "debug");
|
|
|
|
// Add all items to the toDelete set. Not realistic, but it's fine for this test.
|
|
const mockProcessRegularItems = vi.fn((insured, toDelete) =>
|
|
{
|
|
for (const item of insured.items)
|
|
{
|
|
toDelete.add(item._id);
|
|
}
|
|
});
|
|
vi.spyOn(insuranceController, "processRegularItems").mockImplementation(mockProcessRegularItems);
|
|
const mockProcessAttachments = vi.fn((parentAttachmentsMap, itemsMap, traderId, toDelete) =>
|
|
{
|
|
for (const item of insured.items)
|
|
{
|
|
toDelete.add(item._id);
|
|
}
|
|
});
|
|
vi.spyOn(insuranceController, "processAttachments").mockImplementation(mockProcessAttachments);
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.findItemsToDelete(insuranceController.hashUtil.generate(), insured);
|
|
|
|
// Verify that the result is the correct size, and the size is logged.
|
|
expect(result.size).toBe(numberOfItems);
|
|
expect(mockLoggerDebug).toBeCalledWith(`Marked ${numberOfItems} items for deletion from insurance.`);
|
|
});
|
|
});
|
|
|
|
describe("populateParentAttachmentsMap", () =>
|
|
{
|
|
it("should correctly map gun to all of its attachments", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
|
|
// Generate the items map.
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
|
|
// Verify that the map is populated correctly.
|
|
expect(result.size).toBe(9); // There are 9 base-level items in this insurance package.
|
|
|
|
const gun = result.get("35111c9b72a87b6b7d95ad35");
|
|
expect(gun.length).toBe(31); // This gun has 31 attachments.
|
|
|
|
// The attachments should be mapped to the gun properly...
|
|
const validAttachmentTemplates = [
|
|
"7c42d3dce0ddbc4806bce48b",
|
|
"10b97872c5f4e0e1949a0369",
|
|
"a6cd9986dde4cabddcd2dce2",
|
|
"b65635b515712f990fdcc201",
|
|
"0e11045873efe3625695c1ae",
|
|
"94c4161abe8bf654fb986063",
|
|
"9b284ccfd0d535acec1ff58b",
|
|
"d730caa83a11fd01250a7261",
|
|
"24291c7bcf91e362adb6d68b",
|
|
"0d98fd0769cce8e473bbe540",
|
|
"11b174510f039e8217fbd202",
|
|
"c435230e530574b1d7c32300",
|
|
"15666fe6fd2d95206612e418",
|
|
"a54de8b9014eee71fdf1d01d",
|
|
"c34555bc95a9a7a23150a36f",
|
|
"91cae4ae30d1366b87158238",
|
|
"48f23df4509164cf397b9ab5",
|
|
"a55f05f689978ac65c7da654",
|
|
"8ae4ea81a2d6074162d87a9c",
|
|
"312cc0f6687963305457235e",
|
|
"e1e5aaf474b7282a52ac9a14",
|
|
"bb9a34648e08f005db5d7484",
|
|
"dd9ac99d3ea4c9656221bcc9",
|
|
"b22748de8da5f3c1362dd8e0",
|
|
"e3cc1be8954c4889f94b435a",
|
|
"e73f05be5a306168e847da82",
|
|
"847cf35ec92d8af8e4814ea8",
|
|
"bb4b7a4475fea0f0135305f6",
|
|
"d0ac8e688a0bb17668589909",
|
|
"5dbcf8cbbb3f8ef669836320",
|
|
"f996645c809968f8033593a6",
|
|
];
|
|
for (const value of validAttachmentTemplates)
|
|
{
|
|
// Verify that each template is present in the array of attachments.
|
|
expect(gun.some((item) => item._id === value)).toBe(true);
|
|
}
|
|
});
|
|
|
|
it("should correctly map helmet to all of its attachments", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
|
|
// Generate the items map.
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
|
|
// Verify that the map is populated correctly.
|
|
expect(result.size).toBe(9); // There are 9 base-level items in this insurance package.
|
|
|
|
const helmet = result.get("b2405216e5730f3511884a10");
|
|
expect(helmet.length).toBe(4); // This helmet has 2 valid attachments.
|
|
|
|
// The attachments should be mapped to the helmet properly...
|
|
const validAttachmentTemplates = [
|
|
"7a0675280dbbad69ce592d74",
|
|
"c0c182942f54d3c183f0e179",
|
|
"f7066fdfeefb29eca1d2dbeb",
|
|
"ee0ec86e9608abe773175e3a",
|
|
];
|
|
for (const value of validAttachmentTemplates)
|
|
{
|
|
// Verify that each template is present in the array of attachments.
|
|
expect(helmet.some((item) => item._id === value)).toBe(true);
|
|
}
|
|
});
|
|
|
|
it("should correctly map gun to all of its attachments when gun is within a container", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
|
|
// Generate the items map.
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
|
|
// Verify that the map is populated correctly.
|
|
expect(result.size).toBe(9); // There are 9 base-level items in this insurance package.
|
|
|
|
const gun = result.get("26598f88d49198c4a0a9391c");
|
|
expect(insured.items.find((item) => item._id === "26598f88d49198c4a0a9391c").slotId).toBe("main");
|
|
expect(gun.length).toBe(3);
|
|
});
|
|
|
|
it("should not map items that do not have a main-parent", () =>
|
|
{
|
|
// Remove regular items from the fixture.
|
|
insuranceFixture = new ProfileInsuranceFactory().adjustPackageDates().removeRegularItems().get();
|
|
const insured = insuranceFixture[0];
|
|
|
|
// Generate the items map.
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
|
|
// Suppress warnings.
|
|
const mockLoggerWarning = vi.spyOn(insuranceController.logger, "warning").mockImplementation(vi.fn());
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
|
|
// Verify that the map is populated correctly.
|
|
expect(result.size).toBe(0);
|
|
});
|
|
|
|
it("should log a warning when an item does not have a main-parent", () =>
|
|
{
|
|
// Remove regular items from the fixture.
|
|
insuranceFixture = new ProfileInsuranceFactory().adjustPackageDates().removeRegularItems().get();
|
|
const insured = insuranceFixture[0];
|
|
|
|
// Generate the items map.
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
|
|
// Suppress warnings.
|
|
const mockLoggerWarning = vi.spyOn(insuranceController.logger, "warning").mockImplementation(vi.fn());
|
|
|
|
// Execute the method.
|
|
insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
|
|
// Verify that the warning was logged.
|
|
expect(mockLoggerWarning).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("removeNonModdableAttachments", () =>
|
|
{
|
|
it("should return a Map where each parent item ID is mapped to only moddable attachments", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.removeNonModdableAttachments(parentAttachmentsMap, itemsMap);
|
|
|
|
// Verify that the map is populated correctly.
|
|
for (const [parentId, attachments] of result)
|
|
{
|
|
for (const attachment of attachments)
|
|
{
|
|
// Verify that each attachment is moddable.
|
|
const attachmentParentItem = itemsMap.get(parentId);
|
|
expect(insuranceController.itemHelper.isRaidModdable(attachment, attachmentParentItem)).toBe(true);
|
|
}
|
|
}
|
|
});
|
|
|
|
it("should remove parents that do not have any moddable attachments", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
|
|
// Mock isRaidModdable to return false for all attachments.
|
|
vi.spyOn(insuranceController.itemHelper, "isRaidModdable").mockReturnValue(false);
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.removeNonModdableAttachments(parentAttachmentsMap, itemsMap);
|
|
|
|
// Verify that the map is now empty.
|
|
expect(result.size).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("processRegularItems", () =>
|
|
{
|
|
it("should process regular items and their non-attachment children", () =>
|
|
{
|
|
// Remove attachment items from the fixture.
|
|
insuranceFixture = new ProfileInsuranceFactory().adjustPackageDates().removeAttachmentItems().get();
|
|
|
|
const insured = insuranceFixture[0];
|
|
const numberOfItems = insured.items.length;
|
|
const toDelete = new Set<string>();
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
|
|
// Mock helper methods.
|
|
const mockIsAttachmentAttached = vi.spyOn(insuranceController.itemHelper, "isAttachmentAttached");
|
|
const mockFindAndReturnChildrenAsItems = vi.spyOn(
|
|
insuranceController.itemHelper,
|
|
"findAndReturnChildrenAsItems",
|
|
);
|
|
|
|
// Mock rollForDelete to return true for all items. Not realistic, but it's fine for this test.
|
|
const mockRollForDelete = vi.spyOn(insuranceController, "rollForDelete").mockReturnValue(true);
|
|
|
|
// Execute the method.
|
|
insuranceController.processRegularItems(insured, toDelete, parentAttachmentsMap);
|
|
|
|
// Verify that the correct methods were called.
|
|
expect(mockIsAttachmentAttached).toHaveBeenCalledTimes(numberOfItems);
|
|
expect(mockFindAndReturnChildrenAsItems).not.toHaveBeenCalled();
|
|
expect(mockRollForDelete).toHaveBeenCalledTimes(numberOfItems);
|
|
|
|
// Verify that all items were added to the toDelete set.
|
|
expect(toDelete).toEqual(new Set(insured.items.map((item) => item._id)));
|
|
});
|
|
|
|
it("should not roll attached attachments", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
const toDelete = new Set<string>();
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
|
|
// Mock isAttachmentAttached to return true for all items.
|
|
vi.spyOn(insuranceController.itemHelper, "isAttachmentAttached").mockReturnValue(true);
|
|
|
|
// Mock rollForDelete to return true for all items.
|
|
const mockRollForDelete = vi.spyOn(insuranceController, "rollForDelete").mockReturnValue(true);
|
|
|
|
// Execute the method.
|
|
insuranceController.processRegularItems(insured, toDelete, parentAttachmentsMap);
|
|
|
|
// Verify that a roll was not made for any items.
|
|
expect(mockRollForDelete).not.toHaveBeenCalled();
|
|
|
|
// Verify that no items were added to the toDelete set.
|
|
expect(toDelete).toEqual(new Set());
|
|
});
|
|
|
|
it("should mark attachments for deletion when parent is marked for deletion", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
const toDelete = new Set<string>();
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
|
|
// Mock rollForDelete to return true for all base-parent items.
|
|
const mockRollForDelete = vi.fn((traderId, insuredItem) =>
|
|
{
|
|
return !insuranceController.itemHelper.isAttachmentAttached(insuredItem);
|
|
});
|
|
vi.spyOn(insuranceController, "rollForDelete").mockImplementation(mockRollForDelete);
|
|
|
|
// Execute the method.
|
|
insuranceController.processRegularItems(insured, toDelete, parentAttachmentsMap);
|
|
|
|
// Verify that all items were added to the toDelete set.
|
|
expect(toDelete).toEqual(new Set(insured.items.map((item) => item._id)));
|
|
});
|
|
});
|
|
|
|
describe("processAttachments", () =>
|
|
{
|
|
it("should iterate over each parent item", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
const toDelete = new Set<string>();
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
|
|
// Mock helper methods.
|
|
const mockProcessAttachmentByParent = vi.spyOn(insuranceController, "processAttachmentByParent");
|
|
|
|
// Execute the method.
|
|
insuranceController.processAttachments(parentAttachmentsMap, itemsMap, insured.traderId, toDelete);
|
|
|
|
// Verify
|
|
expect(mockProcessAttachmentByParent).toHaveBeenCalledTimes(parentAttachmentsMap.size);
|
|
});
|
|
|
|
it("should log the name of each parent item", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
const toDelete = new Set<string>();
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
|
|
// Mock helper methods.
|
|
const mockLoggerDebug = vi.spyOn(insuranceController.logger, "debug").mockImplementation(vi.fn());
|
|
|
|
// Mock processAttachmentByParent to prevent it from being called.
|
|
vi.spyOn(insuranceController, "processAttachmentByParent").mockImplementation(vi.fn());
|
|
|
|
// Execute the method.
|
|
insuranceController.processAttachments(parentAttachmentsMap, itemsMap, insured.traderId, toDelete);
|
|
|
|
// Verify that the name of each parent item is logged.
|
|
for (const [parentId] of parentAttachmentsMap)
|
|
{
|
|
const parentItem = itemsMap.get(parentId);
|
|
if (parentItem)
|
|
{
|
|
const expectedMessage = `Processing attachments of parent "${
|
|
insuranceController.itemHelper.getItemName(parentItem._tpl)
|
|
}":`;
|
|
expect(mockLoggerDebug).toHaveBeenCalledWith(expectedMessage);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("processAttachmentByParent", () =>
|
|
{
|
|
it("should handle weighing and counting of attachments by calling helper methods", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
const attachments = parentAttachmentsMap.entries().next().value;
|
|
const toDelete = new Set<string>();
|
|
|
|
// Mock helper methods.
|
|
const weightAttachmentsByPrice = vi.spyOn(insuranceController, "weightAttachmentsByPrice");
|
|
const getAttachmentCountToRemove = vi.spyOn(insuranceController, "getAttachmentCountToRemove")
|
|
.mockReturnValue(4);
|
|
const logAttachmentsBeingRemoved = vi.spyOn(insuranceController, "logAttachmentsBeingRemoved");
|
|
|
|
// Execute the method.
|
|
insuranceController.processAttachmentByParent(attachments, insured.traderId, toDelete);
|
|
|
|
// Verify that helper methods are called.
|
|
expect(weightAttachmentsByPrice).toHaveBeenCalledWith(attachments);
|
|
expect(getAttachmentCountToRemove).toHaveBeenCalled();
|
|
expect(logAttachmentsBeingRemoved).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("getAttachmentCountToRemove", () =>
|
|
{
|
|
it("should handle returning a count of attachments that should be removed that is below the total attachment count", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
const attachments = parentAttachmentsMap.entries().next().value;
|
|
const attachmentCount = attachments.length;
|
|
|
|
const result = insuranceController.getAttachmentCountToRemove(attachments, insured.traderId);
|
|
|
|
expect(result).lessThanOrEqual(attachmentCount);
|
|
});
|
|
|
|
it("should handle returning 0 when chanceNoAttachmentsTakenPercent is 100%", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
const attachments = parentAttachmentsMap.entries().next().value;
|
|
insuranceController.insuranceConfig.chanceNoAttachmentsTakenPercent = 100;
|
|
|
|
const result = insuranceController.getAttachmentCountToRemove(attachments, insured.traderId);
|
|
|
|
expect(result).toBe(0);
|
|
});
|
|
|
|
it("should handle returning 0 when all attachments are below configured threshold price", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
const attachments = parentAttachmentsMap.values().next().value;
|
|
insuranceController.insuranceConfig.minAttachmentRoublePriceToBeTaken = 2;
|
|
vi.spyOn(insuranceController.ragfairPriceService, "getDynamicItemPrice").mockReturnValue(1);
|
|
|
|
const weightedAttachments = insuranceController.weightAttachmentsByPrice(attachments);
|
|
const result = insuranceController.getAttachmentCountToRemove(weightedAttachments, insured.traderId);
|
|
|
|
expect(result).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("weightAttachmentsByPrice", () =>
|
|
{
|
|
it("Should create a dictionary of 2 items with weights of 1 for each", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
const itemsMap = insuranceController.itemHelper.generateItemsMap(insured.items);
|
|
const parentAttachmentsMap = insuranceController.populateParentAttachmentsMap(
|
|
insuranceController.hashUtil.generate(),
|
|
insured,
|
|
itemsMap,
|
|
);
|
|
const attachments = parentAttachmentsMap.values().next().value;
|
|
|
|
vi.spyOn(insuranceController.ragfairPriceService, "getDynamicItemPrice").mockReturnValue(1);
|
|
|
|
const result = insuranceController.weightAttachmentsByPrice(attachments);
|
|
expect(Object.keys(result).length).toBe(2);
|
|
expect(Object.values(result)).toStrictEqual([1, 1]);
|
|
});
|
|
});
|
|
|
|
describe("removeItemsFromInsurance", () =>
|
|
{
|
|
it("should remove items from insurance based on the toDelete set", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
|
|
const toDelete = new Set<string>();
|
|
const numberToDelete = 2;
|
|
for (let i = 0; i < numberToDelete; i++)
|
|
{
|
|
toDelete.add(insured.items[i]._id);
|
|
}
|
|
|
|
// Execute the method.
|
|
insuranceController.removeItemsFromInsurance(insured, toDelete);
|
|
|
|
// Ensure that the items in the toDelete set are not present in the insured items array.
|
|
for (const toDeleteId of toDelete)
|
|
{
|
|
expect(insured.items.some((item) => item._id === toDeleteId)).toBe(false);
|
|
}
|
|
});
|
|
|
|
it("should not remove any items if toDelete set is empty", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
const originalCount = insured.items.length;
|
|
const toDelete = new Set<string>();
|
|
|
|
// Execute the method.
|
|
insuranceController.removeItemsFromInsurance(insured, toDelete);
|
|
|
|
// Ensure that no items were removed.
|
|
expect(insured.items.length).toBe(originalCount);
|
|
});
|
|
|
|
it("should leave the insurance items empty if all are to be deleted", () =>
|
|
{
|
|
const insured = insuranceFixture[0];
|
|
const originalCount = insured.items.length;
|
|
const toDelete = new Set<string>();
|
|
for (const item of insured.items)
|
|
{
|
|
toDelete.add(item._id);
|
|
}
|
|
|
|
// All of the items should be added to the toDelete set.
|
|
expect(originalCount).toBe(toDelete.size);
|
|
|
|
// Execute the method.
|
|
insuranceController.removeItemsFromInsurance(insured, toDelete);
|
|
|
|
// Ensure that all items were removed.
|
|
expect(insured.items.length).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("sendMail", () =>
|
|
{
|
|
it("should send insurance failed message when no items are present", () =>
|
|
{
|
|
const insurance = insuranceFixture[0];
|
|
insurance.items = []; // Empty the items array
|
|
const sessionID = "session-id";
|
|
const insuranceFailedTpl = "failed-message-template";
|
|
|
|
// Mock the randomUtil to return a static failed template string.
|
|
const mockGetArrayValue = vi.spyOn(insuranceController.randomUtil, "getArrayValue").mockReturnValue(
|
|
insuranceFailedTpl,
|
|
);
|
|
|
|
// Don't actually send the message.
|
|
const sendMessageSpy = vi.spyOn(insuranceController.mailSendService, "sendLocalisedNpcMessageToPlayer")
|
|
.mockImplementation(vi.fn());
|
|
|
|
// Execute the method.
|
|
insuranceController.sendMail(sessionID, insurance);
|
|
|
|
// Verify that the randomUtil.getArrayValue method was called.
|
|
expect(mockGetArrayValue).toBeCalled();
|
|
|
|
// Verify that the insurance failed message was sent.
|
|
expect(sendMessageSpy).toHaveBeenCalledWith(
|
|
sessionID,
|
|
insuranceController.traderHelper.getTraderById(insurance.traderId),
|
|
MessageType.INSURANCE_RETURN,
|
|
insuranceFailedTpl,
|
|
insurance.items,
|
|
insurance.maxStorageTime,
|
|
insurance.systemData,
|
|
);
|
|
});
|
|
|
|
it("should not send insurance failed message when items are present", () =>
|
|
{
|
|
const insurance = insuranceFixture[0];
|
|
const sessionID = "session-id";
|
|
const insuranceFailedTpl = "failed-message-template";
|
|
|
|
// Mock the randomUtil to return a static failed template string.
|
|
const mockGetArrayValue = vi.spyOn(insuranceController.randomUtil, "getArrayValue").mockReturnValue(
|
|
insuranceFailedTpl,
|
|
);
|
|
|
|
// Don't actually send the message.
|
|
const sendMessageSpy = vi.spyOn(insuranceController.mailSendService, "sendLocalisedNpcMessageToPlayer")
|
|
.mockImplementation(vi.fn());
|
|
|
|
// Execute the method.
|
|
insuranceController.sendMail(sessionID, insurance);
|
|
|
|
// Verify that the randomUtil.getArrayValue method was not called.
|
|
expect(mockGetArrayValue).not.toBeCalled();
|
|
|
|
// Verify that the insurance failed message was not sent.
|
|
expect(sendMessageSpy).toHaveBeenCalledWith(
|
|
sessionID,
|
|
insuranceController.traderHelper.getTraderById(insurance.traderId),
|
|
MessageType.INSURANCE_RETURN,
|
|
insurance.messageTemplateId,
|
|
insurance.items,
|
|
insurance.maxStorageTime,
|
|
insurance.systemData,
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("rollForDelete", () =>
|
|
{
|
|
it("should return true when random roll is equal to trader return chance", () =>
|
|
{
|
|
vi.spyOn(insuranceController.randomUtil, "getInt").mockReturnValue(8500); // Our "random" roll.
|
|
const traderId = "54cb57776803fa99248b456e"; // Therapist (85% return chance)
|
|
insuranceController.insuranceConfig = {
|
|
returnChancePercent: {
|
|
[traderId]: 85, // Force 85% return chance
|
|
},
|
|
};
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.rollForDelete(traderId);
|
|
|
|
// Verify that the result is true.
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it("should return true when random roll is greater than trader return chance", () =>
|
|
{
|
|
vi.spyOn(insuranceController.randomUtil, "getInt").mockReturnValue(8501); // Our "random" roll.
|
|
const traderId = "54cb57776803fa99248b456e"; // Therapist (85% return chance)
|
|
insuranceController.insuranceConfig = {
|
|
returnChancePercent: {
|
|
[traderId]: 85, // Force 85% return chance
|
|
},
|
|
};
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.rollForDelete(traderId);
|
|
|
|
// Verify that the result is true.
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it("should return false when random roll is less than trader return chance", () =>
|
|
{
|
|
vi.spyOn(insuranceController.randomUtil, "getInt").mockReturnValue(8499); // Our "random" roll.
|
|
const traderId = "54cb57776803fa99248b456e"; // Therapist (85% return chance)
|
|
insuranceController.insuranceConfig = {
|
|
returnChancePercent: {
|
|
[traderId]: 85, // Force 85% return chance
|
|
},
|
|
};
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.rollForDelete(traderId);
|
|
|
|
// Verify that the result is false.
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
it("should log error if trader can not be found", () =>
|
|
{
|
|
const traderId = "invalid-trader-id";
|
|
|
|
const loggerErrorSpy = vi.spyOn(insuranceController.logger, "error");
|
|
|
|
// Execute the method.
|
|
insuranceController.rollForDelete(traderId);
|
|
|
|
// Verify that the logger.error method was called.
|
|
expect(loggerErrorSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
it("should return null if trader can not be found", () =>
|
|
{
|
|
const traderId = "invalid-trader-id";
|
|
|
|
// Execute the method.
|
|
const result = insuranceController.rollForDelete(traderId);
|
|
|
|
// Verify that the result is null.
|
|
expect(result).toBe(undefined);
|
|
});
|
|
});
|
|
|
|
describe("insure", () =>
|
|
{
|
|
let pmcData: any;
|
|
let body: any;
|
|
let sessionId: string;
|
|
let insuranceController: any;
|
|
let mockGetRoublePriceToInsureItemWithTrader: any;
|
|
let mockPayMoney: any;
|
|
let mockGetOutput: any;
|
|
|
|
beforeEach(() =>
|
|
{
|
|
insuranceController = container.resolve<InsuranceController>("InsuranceController");
|
|
|
|
// Setup shared test data.
|
|
pmcData = {
|
|
Inventory: { items: [{ _id: "item1", otherProps: "value1" }, { _id: "item2", otherProps: "value2" }] },
|
|
InsuredItems: [],
|
|
};
|
|
body = { items: ["item1", "item2"], tid: "someTraderId" };
|
|
sessionId = "session-id";
|
|
|
|
// Setup shared mocks.
|
|
mockGetRoublePriceToInsureItemWithTrader = vi.spyOn(insuranceController.insuranceService, "getRoublePriceToInsureItemWithTrader").mockReturnValue(100);
|
|
mockPayMoney = vi.spyOn(insuranceController.paymentService, "payMoney").mockReturnValue({
|
|
warnings: [],
|
|
otherProperty: "property-value",
|
|
});
|
|
mockGetOutput = vi.spyOn(insuranceController.eventOutputHolder, "getOutput").mockReturnValue({
|
|
warnings: [],
|
|
otherProperty: "property-value",
|
|
});
|
|
});
|
|
|
|
it("should create a hash of inventory items by ID", () =>
|
|
{
|
|
// Execute the method.
|
|
insuranceController.insure(pmcData, body, sessionId);
|
|
|
|
// Since the inventoryItemsHash is internal to the function, we cannot check it directly. However, we can
|
|
// infer its correctness by ensuring the payMoney function is called with the right "scheme_items" property.
|
|
expect(mockPayMoney).toHaveBeenCalledWith(
|
|
pmcData,
|
|
{
|
|
scheme_items: [{ id: "5449016a4bdc2d6f028b456f", count: 100 }, {
|
|
id: "5449016a4bdc2d6f028b456f",
|
|
count: 100,
|
|
}],
|
|
tid: "someTraderId",
|
|
Action: "SptInsure",
|
|
type: "",
|
|
item_id: "",
|
|
count: 0,
|
|
scheme_id: 0,
|
|
},
|
|
sessionId,
|
|
{ warnings: [], otherProperty: "property-value" },
|
|
);
|
|
});
|
|
|
|
it("should calculate the insurance premium for each item to insure", () =>
|
|
{
|
|
// Execute the method.
|
|
insuranceController.insure(pmcData, body, sessionId);
|
|
|
|
// Verify that getRoublePriceToInsureItemWithTrader is called with each item from the pmcData.Inventory.items array.
|
|
for (const item of pmcData.Inventory.items)
|
|
{
|
|
expect(mockGetRoublePriceToInsureItemWithTrader).toHaveBeenCalledWith(pmcData, item, body.tid);
|
|
}
|
|
|
|
// Verify that getRoublePriceToInsureItemWithTrader was called the correct number of times.
|
|
expect(mockGetRoublePriceToInsureItemWithTrader).toHaveBeenCalledTimes(body.items.length);
|
|
});
|
|
|
|
it("should call the payment service with the correct parameters", () =>
|
|
{
|
|
// Execute the method.
|
|
insuranceController.insure(pmcData, body, sessionId);
|
|
|
|
// Define the expected payment options structure based on the setup data.
|
|
const expectedPaymentOptions = {
|
|
scheme_items: [{ id: "5449016a4bdc2d6f028b456f", count: 100 }, {
|
|
id: "5449016a4bdc2d6f028b456f",
|
|
count: 100,
|
|
}],
|
|
tid: body.tid,
|
|
Action: "SptInsure",
|
|
type: "",
|
|
item_id: "",
|
|
count: 0,
|
|
scheme_id: 0,
|
|
};
|
|
|
|
// Verify that the paymentService's payMoney method was called once with the expected parameters.
|
|
expect(mockPayMoney).toHaveBeenCalledWith(pmcData, expectedPaymentOptions, sessionId, expect.any(Object));
|
|
|
|
// Verify that the output passed to payMoney is the one obtained from getOutput.
|
|
expect(mockPayMoney).toHaveBeenCalledWith(
|
|
pmcData,
|
|
expectedPaymentOptions,
|
|
sessionId,
|
|
mockGetOutput.mock.results[0].value,
|
|
);
|
|
});
|
|
|
|
it("should add items to InsuredItems after successful payment", () =>
|
|
{
|
|
// Execute the method.
|
|
insuranceController.insure(pmcData, body, sessionId);
|
|
|
|
// Verify that the InsuredItems array has been populated with the correct items.
|
|
const insuredItemIds = pmcData.InsuredItems.map((insuredItem) => insuredItem.itemId);
|
|
expect(insuredItemIds).toContain("item1");
|
|
expect(insuredItemIds).toContain("item2");
|
|
|
|
// Verify that the number of InsuredItems matches the number of items intended to be insured.
|
|
expect(pmcData.InsuredItems.length).toBe(body.items.length);
|
|
});
|
|
|
|
it("should update output with warnings if payment fails", () =>
|
|
{
|
|
// Override the payMoney mock to simulate a payment failure with a warning.
|
|
const expectedPayMoneyReturn = {
|
|
warnings: [{ index: 0, errmsg: "You broke.", code: 500 }],
|
|
otherProperty: "property-value",
|
|
};
|
|
mockPayMoney.mockImplementation((pmcData, request, sessionID, output) =>
|
|
{
|
|
output.warnings = expectedPayMoneyReturn.warnings;
|
|
});
|
|
|
|
// Execute the method.
|
|
const response = insuranceController.insure(pmcData, body, sessionId);
|
|
|
|
// Verify that the response contains the warnings from the payment failure
|
|
expect(response.warnings).toStrictEqual(expectedPayMoneyReturn.warnings);
|
|
|
|
// Verify that other properties from the response are still present.
|
|
expect(response).toHaveProperty("otherProperty", "property-value");
|
|
});
|
|
|
|
it("should not add items to InsuredItems if payment fails", () =>
|
|
{
|
|
// Override the payMoney mock to simulate a payment failure with a warning.
|
|
const expectedPayMoneyReturn = {
|
|
warnings: [{ index: 0, errmsg: "You broke.", code: 500 }],
|
|
otherProperty: "property-value",
|
|
};
|
|
mockPayMoney.mockImplementation((pmcData, request, sessionID, output) =>
|
|
{
|
|
output.warnings = expectedPayMoneyReturn.warnings;
|
|
});
|
|
|
|
// Execute the method.
|
|
insuranceController.insure(pmcData, body, sessionId);
|
|
|
|
// Verify that the InsuredItems array has not been populated.
|
|
expect(pmcData.InsuredItems).toHaveLength(0);
|
|
});
|
|
});
|
|
|
|
describe("cost", () =>
|
|
{
|
|
let sessionId: string;
|
|
|
|
beforeEach(() =>
|
|
{
|
|
insuranceController = container.resolve<InsuranceController>("InsuranceController");
|
|
|
|
sessionId = "session-id";
|
|
|
|
vi.spyOn(insuranceController.profileHelper, "getPmcProfile").mockReturnValue({
|
|
Inventory: {
|
|
items: [{ _id: "itemId1", _tpl: "itemTpl1", otherProperty: "property-value1" }, {
|
|
_id: "itemId2",
|
|
_tpl: "itemTpl2",
|
|
otherProperty: "property-value2",
|
|
}, { _id: "itemId3", _tpl: "itemTpl3", otherProperty: "property-value3" }],
|
|
},
|
|
});
|
|
});
|
|
|
|
it("should return an empty object if no traders and items are specified", () =>
|
|
{
|
|
const request = { traders: [], items: [] };
|
|
const expected = {};
|
|
|
|
const result = insuranceController.cost(request, sessionId);
|
|
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it("should return an empty object if no items are specified", () =>
|
|
{
|
|
const request = { traders: ["prapor"], items: [] };
|
|
const expected = { prapor: {} };
|
|
|
|
const result = insuranceController.cost(request, sessionId);
|
|
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it("should return an empty object if no trader is specified but items are", () =>
|
|
{
|
|
const request = { traders: [], items: ["itemId1", "itemId2"] };
|
|
const expected = {};
|
|
|
|
const result = insuranceController.cost(request, sessionId);
|
|
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it("should return the expected cost for each item and trader", () =>
|
|
{
|
|
const request = { traders: ["prapor", "therapist"], items: ["itemId1", "itemId2", "itemId3"] };
|
|
const expected = {
|
|
prapor: { itemTpl1: 100, itemTpl2: 200, itemTpl3: 300 },
|
|
therapist: { itemTpl1: 150, itemTpl2: 250, itemTpl3: 350 },
|
|
};
|
|
|
|
// Mock the InsuranceService.getRoublePriceToInsureItemWithTrader method to return the expected values.
|
|
vi.spyOn(insuranceController.insuranceService, "getRoublePriceToInsureItemWithTrader").mockReturnValueOnce(100).mockReturnValueOnce(
|
|
200,
|
|
).mockReturnValueOnce(300).mockReturnValueOnce(150).mockReturnValueOnce(250).mockReturnValueOnce(350);
|
|
|
|
const result = insuranceController.cost(request, sessionId);
|
|
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it("should skip items that are not in the player's inventory", () =>
|
|
{
|
|
const request = {
|
|
traders: ["prapor"],
|
|
items: [
|
|
"itemId1",
|
|
"itemId2",
|
|
"itemId4", // Doesn't exist in the player's inventory.
|
|
],
|
|
};
|
|
const expected = { prapor: { itemTpl1: 100, itemTpl2: 200 } };
|
|
|
|
// Mock the InsuranceService.getRoublePriceToInsureItemWithTrader method to return the expected values.
|
|
vi.spyOn(insuranceController.insuranceService, "getRoublePriceToInsureItemWithTrader").mockReturnValueOnce(100).mockReturnValueOnce(
|
|
200,
|
|
);
|
|
|
|
const result = insuranceController.cost(request, sessionId);
|
|
|
|
expect(result).toEqual(expected);
|
|
});
|
|
});
|
|
});
|