From ad5e0815b6862a6e7eaf3f8bd49f67e59dc7304a Mon Sep 17 00:00:00 2001 From: Refringe Date: Fri, 27 Oct 2023 23:55:34 -0400 Subject: [PATCH] Migrated from Jest to Vitest Basically the same, except it plays nicer with Typescript and ESM. I have it mostly working, except for a type error: `TypeError: Int32Array is not a constructor` But I'm too damn tired it debug it at the moment. --- project/.vscode/settings.json | 11 +- project/jest.config.ts | 15 - project/package.json | 15 +- project/tests/CustomEnvironment.ts | 874 +++++++++--------- project/tests/helpers/ItemHelper.test.ts | 51 +- project/tests/services/PaymentService.test.ts | 8 +- project/tsconfig.json | 3 + project/tsconfig.test.json | 3 +- project/vitest.config.ts | 16 + 9 files changed, 498 insertions(+), 498 deletions(-) delete mode 100644 project/jest.config.ts create mode 100644 project/vitest.config.ts diff --git a/project/.vscode/settings.json b/project/.vscode/settings.json index bbd5e706..02965ef3 100644 --- a/project/.vscode/settings.json +++ b/project/.vscode/settings.json @@ -9,5 +9,12 @@ "editor.detectIndentation": false, "editor.tabSize": 4, "editor.insertSpaces": true - } -} \ No newline at end of file + }, + "cSpell.words": [ + "Baseclass", + "IIIA", + "medkit", + "Superfors", + "ULACH" + ] +} diff --git a/project/jest.config.ts b/project/jest.config.ts deleted file mode 100644 index 252cb7f8..00000000 --- a/project/jest.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -import type { Config } from "jest"; -import fs from "fs"; - -const config: Config = { - testEnvironment: "./tests/CustomEnvironment.ts", - roots: [ - "./tests/" - ], - transform: { - "^.+\\.ts$": [ "@swc/jest", JSON.parse(fs.readFileSync(`${__dirname}/.swcrc`, "utf-8")) ] - } -}; - -export default config; diff --git a/project/package.json b/project/package.json index d85f78dc..095fc273 100644 --- a/project/package.json +++ b/project/package.json @@ -14,8 +14,9 @@ "check:circular": "madge --circular --extensions ts ./src/", "lint": "rome ci src --formatter-enabled=false --max-diagnostics=200", "lint:fix": "eslint --fix --ext .ts src/**", - "test": "jest --colors --runInBand", - "test:coverage": "jest --coverage --maxWorkers=1 --no-cache", + "test": "vitest run", + "test:watch": "vitest", + "test:coverage": "vitest run --coverage", "build:release": "cross-env PKG_CACHE_PATH=\"./.pkg-cache\" gulp build:release", "build:debug": "cross-env PKG_CACHE_PATH=\"./.pkg-cache\" gulp build:debug", "build:bleeding": "cross-env PKG_CACHE_PATH=\"./.pkg-cache\" gulp build:bleeding", @@ -44,27 +45,22 @@ "devDependencies": { "@babel/preset-env": "7.23.2", "@babel/preset-typescript": "7.23.2", - "@jest/environment": "^29.7.0", - "@jest/globals": "29.7.0", "@pnpm/exe": "8.9.0", "@swc/cli": "0.1.62", "@swc/core": "1.3.92", - "@swc/jest": "0.2.29", "@types/i18n": "0.13.7", - "@types/jest": "29.5.5", "@types/node": "18.18.4", "@types/proper-lockfile": "4.1.2", "@types/semver": "7.5.3", "@types/ws": "8.5.7", "@typescript-eslint/eslint-plugin": "6.7.5", "@typescript-eslint/parser": "6.7.5", + "c8": "^8.0.1", "cross-env": "7.0.3", "eslint": "8.51.0", "gulp": "4.0.2", "gulp-execa": "5.0.1", "gulp-rename": "2.0.0", - "jest": "29.7.0", - "jest-environment-node": "^29.7.0", "madge": "6.1.0", "pkg": "5.8.1", "pkg-fetch": "3.5.2", @@ -73,7 +69,8 @@ "ts-node-dev": "2.0.0", "tsconfig-paths": "4.2.0", "typedoc": "0.25.2", - "typemoq": "2.1.0" + "typemoq": "2.1.0", + "vitest": "1.0.0-beta.3" }, "overrides": { "pkg": { diff --git a/project/tests/CustomEnvironment.ts b/project/tests/CustomEnvironment.ts index 424177d7..a0452761 100644 --- a/project/tests/CustomEnvironment.ts +++ b/project/tests/CustomEnvironment.ts @@ -248,460 +248,454 @@ import { Watermark, WatermarkLocale } from "@spt-aki/utils/Watermark"; import { WinstonMainLogger } from "@spt-aki/utils/logging/WinstonMainLogger"; import { WinstonRequestLogger } from "@spt-aki/utils/logging/WinstonRequestLogger"; -// For the Jest Custom Environment. -import NodeEnvironment from "jest-environment-node"; -import type { EnvironmentContext, JestEnvironmentConfig } from "@jest/environment"; +// For the Vitest Custom Environment. +import type { Environment } from "vitest"; +import { populateGlobal } from "vitest/environments"; // Used for importing the database. import path from "path"; import { IDatabaseTables } from "@spt-aki/models/spt/server/IDatabaseTables"; -export default class CustomEnvironment extends NodeEnvironment -{ - private container: DependencyContainer; - - // For importing the database. - private importerUtil: ImporterUtil; - private databaseServer: DatabaseServer; - - constructor(config: JestEnvironmentConfig, context: EnvironmentContext) +export default { + name: "spt-aki-server", + transformMode: "ssr", + async setup() { - super(config, context); - - this.container = this.register(container); - } - - async setup(): Promise - { - await super.setup(); + // Register all of the things! + register(container); // Import the database. - await this.importDatabase(); + await importDatabase(container); - // Make the container accessible to the tests. - this.global.container = this.container; + // Populate the global scope with all of the things! + populateGlobal(global, { container }, { bindFunctions: true }); // TODO: Create test account/profile + + return { + teardown() + { + // Not sure this is required, but it's here just in case. + delete global.container; + + // TODO: Delete test account/profile + } + }; } +}; - async teardown(): Promise - { - // TODO: Delete test account/profile +// Register all of the things! +function register(container: DependencyContainer): DependencyContainer +{ + container.register("ApplicationContext", ApplicationContext, { lifecycle: Lifecycle.Singleton }); - await super.teardown(); - } + registerUtils(container); + registerRouters(container); + registerGenerators(container); + registerHelpers(container); + registerLoaders(container); + registerCallbacks(container); + registerServers(container); + registerServices(container); + registerControllers(container); - // Register all of the things! - private register(container: DependencyContainer): DependencyContainer - { - container.register("ApplicationContext", ApplicationContext, { lifecycle: Lifecycle.Singleton }); + registerListTypes(container); - this.registerUtils(container); - this.registerRouters(container); - this.registerGenerators(container); - this.registerHelpers(container); - this.registerLoaders(container); - this.registerCallbacks(container); - this.registerServers(container); - this.registerServices(container); - this.registerControllers(container); - - this.registerListTypes(container); - - return container; - } - - private registerUtils(container: DependencyContainer): void - { - // Utils - container.register("App", App, { lifecycle: Lifecycle.Singleton }); - container.register("DatabaseImporter", DatabaseImporter, { lifecycle: Lifecycle.Singleton }); - container.register("HashUtil", HashUtil, { lifecycle: Lifecycle.Singleton }); - container.register("ImporterUtil", ImporterUtil, { lifecycle: Lifecycle.Singleton }); - container.register("HttpResponseUtil", HttpResponseUtil); - container.register("EncodingUtil", EncodingUtil, { lifecycle: Lifecycle.Singleton }); - container.register("JsonUtil", JsonUtil); - container.register("WinstonLogger", WinstonMainLogger, { lifecycle: Lifecycle.Singleton }); - container.register("RequestsLogger", WinstonRequestLogger, { lifecycle: Lifecycle.Singleton }); - container.register("MathUtil", MathUtil, { lifecycle: Lifecycle.Singleton }); - container.register("ObjectId", ObjectId); - container.register("RandomUtil", RandomUtil, { lifecycle: Lifecycle.Singleton }); - container.register("TimeUtil", TimeUtil, { lifecycle: Lifecycle.Singleton }); - container.register("VFS", VFS, { lifecycle: Lifecycle.Singleton }); - container.register("WatermarkLocale", WatermarkLocale, { lifecycle: Lifecycle.Singleton }); - container.register("Watermark", Watermark, { lifecycle: Lifecycle.Singleton }); - container.register("AsyncQueue", AsyncQueue, { lifecycle: Lifecycle.Singleton }); - container.register("UUidGenerator", UUidGenerator, { lifecycle: Lifecycle.Singleton }); - container.register("HttpFileUtil", HttpFileUtil, { lifecycle: Lifecycle.Singleton }); - container.register("ModLoadOrder", ModLoadOrder, { lifecycle: Lifecycle.Singleton }); - container.register("ModTypeCheck", ModTypeCheck, { lifecycle: Lifecycle.Singleton }); - } - - private registerRouters(container: DependencyContainer): void - { - // Routers - container.register("HttpRouter", HttpRouter, { lifecycle: Lifecycle.Singleton }); - container.register("ImageRouter", ImageRouter); - container.register("EventOutputHolder", EventOutputHolder, { lifecycle: Lifecycle.Singleton }); - container.register("ItemEventRouter", ItemEventRouter); - - // Dynamic Routes - container.register("BotDynamicRouter", { useClass: BotDynamicRouter }); - container.register("BundleDynamicRouter", { useClass: BundleDynamicRouter }); - container.register("CustomizationDynamicRouter", { useClass: CustomizationDynamicRouter }); - container.register("DataDynamicRouter", { useClass: DataDynamicRouter }); - container.register("HttpDynamicRouter", { useClass: HttpDynamicRouter }); - container.register("InraidDynamicRouter", { useClass: InraidDynamicRouter }); - container.register("LocationDynamicRouter", { useClass: LocationDynamicRouter }); - container.register("NotifierDynamicRouter", { useClass: NotifierDynamicRouter }); - container.register("TraderDynamicRouter", { useClass: TraderDynamicRouter }); - - // Item Event Routes - container.register("CustomizationItemEventRouter", { useClass: CustomizationItemEventRouter }); - container.register("HealthItemEventRouter", { useClass: HealthItemEventRouter }); - container.register("HideoutItemEventRouter", { useClass: HideoutItemEventRouter }); - container.register("InsuranceItemEventRouter", { useClass: InsuranceItemEventRouter }); - container.register("InventoryItemEventRouter", { useClass: InventoryItemEventRouter }); - container.register("NoteItemEventRouter", { useClass: NoteItemEventRouter }); - container.register("PresetBuildItemEventRouter", { useClass: PresetBuildItemEventRouter }); - container.register("QuestItemEventRouter", { useClass: QuestItemEventRouter }); - container.register("RagfairItemEventRouter", { useClass: RagfairItemEventRouter }); - container.register("RepairItemEventRouter", { useClass: RepairItemEventRouter }); - container.register("TradeItemEventRouter", { useClass: TradeItemEventRouter }); - container.register("WishlistItemEventRouter", { useClass: WishlistItemEventRouter }); - - // Save Load Routes - container.register("HealthSaveLoadRouter", { useClass: HealthSaveLoadRouter }); - container.register("InraidSaveLoadRouter", { useClass: InraidSaveLoadRouter }); - container.register("InsuranceSaveLoadRouter", { useClass: InsuranceSaveLoadRouter }); - container.register("ProfileSaveLoadRouter", { useClass: ProfileSaveLoadRouter }); - - // Route Serializers - container.register("BundleSerializer", { useClass: BundleSerializer }); - container.register("ImageSerializer", { useClass: ImageSerializer }); - container.register("NotifySerializer", { useClass: NotifySerializer }); - - // Static Routes - container.register("BotStaticRouter", { useClass: BotStaticRouter }); - container.register("BundleStaticRouter", { useClass: BundleStaticRouter }); - container.register("ClientLogStaticRouter", { useClass: ClientLogStaticRouter }); - container.register("CustomizationStaticRouter", { useClass: CustomizationStaticRouter }); - container.register("DataStaticRouter", { useClass: DataStaticRouter }); - container.register("DialogStaticRouter", { useClass: DialogStaticRouter }); - container.register("GameStaticRouter", { useClass: GameStaticRouter }); - container.register("HealthStaticRouter", { useClass: HealthStaticRouter }); - container.register("InraidStaticRouter", { useClass: InraidStaticRouter }); - container.register("InsuranceStaticRouter", { useClass: InsuranceStaticRouter }); - container.register("ItemEventStaticRouter", { useClass: ItemEventStaticRouter }); - container.register("LauncherStaticRouter", { useClass: LauncherStaticRouter }); - container.register("LocationStaticRouter", { useClass: LocationStaticRouter }); - container.register("MatchStaticRouter", { useClass: MatchStaticRouter }); - container.register("NotifierStaticRouter", { useClass: NotifierStaticRouter }); - container.register("PresetStaticRouter", { useClass: PresetStaticRouter }); - container.register("ProfileStaticRouter", { useClass: ProfileStaticRouter }); - container.register("QuestStaticRouter", { useClass: QuestStaticRouter }); - container.register("RagfairStaticRouter", { useClass: RagfairStaticRouter }); - container.register("TraderStaticRouter", { useClass: TraderStaticRouter }); - container.register("WeatherStaticRouter", { useClass: WeatherStaticRouter }); - } - - private registerGenerators(container: DependencyContainer): void - { - // Generators - container.register("BotGenerator", BotGenerator); - container.register("BotWeaponGenerator", BotWeaponGenerator); - container.register("BotLootGenerator", BotLootGenerator); - container.register("BotInventoryGenerator", BotInventoryGenerator); - container.register("LocationGenerator", { useClass: LocationGenerator }); - container.register("PMCLootGenerator", PMCLootGenerator, { lifecycle: Lifecycle.Singleton }); - container.register("ScavCaseRewardGenerator", ScavCaseRewardGenerator, { lifecycle: Lifecycle.Singleton }); - container.register("RagfairAssortGenerator", { useClass: RagfairAssortGenerator }); - container.register("RagfairOfferGenerator", { useClass: RagfairOfferGenerator }); - container.register("WeatherGenerator", { useClass: WeatherGenerator }); - container.register("PlayerScavGenerator", { useClass: PlayerScavGenerator }); - container.register("LootGenerator", { useClass: LootGenerator }); - container.register("FenceBaseAssortGenerator", { useClass: FenceBaseAssortGenerator }); - container.register("BotLevelGenerator", { useClass: BotLevelGenerator }); - container.register("BotEquipmentModGenerator", { useClass: BotEquipmentModGenerator }); - container.register("RepeatableQuestGenerator", { useClass: RepeatableQuestGenerator }); - container.register("BarrelInventoryMagGen", { useClass: BarrelInventoryMagGen }); - container.register("ExternalInventoryMagGen", { useClass: ExternalInventoryMagGen }); - container.register("InternalMagazineInventoryMagGen", { useClass: InternalMagazineInventoryMagGen }); - container.register("UbglExternalMagGen", { useClass: UbglExternalMagGen }); - - container.registerType("InventoryMagGen", "BarrelInventoryMagGen"); - container.registerType("InventoryMagGen", "ExternalInventoryMagGen"); - container.registerType("InventoryMagGen", "InternalMagazineInventoryMagGen"); - container.registerType("InventoryMagGen", "UbglExternalMagGen"); - } - - private registerHelpers(container: DependencyContainer): void - { - // Helpers - container.register("AssortHelper", { useClass: AssortHelper }); - container.register("BotHelper", { useClass: BotHelper }); - container.register("BotGeneratorHelper", { useClass: BotGeneratorHelper }); - container.register("ContainerHelper", ContainerHelper); - container.register("DialogueHelper", { useClass: DialogueHelper }); - container.register("DurabilityLimitsHelper", { useClass: DurabilityLimitsHelper }); - container.register("GameEventHelper", GameEventHelper); - container.register("HandbookHelper", HandbookHelper, { lifecycle: Lifecycle.Singleton }); - container.register("HealthHelper", { useClass: HealthHelper }); - container.register("HideoutHelper", { useClass: HideoutHelper }); - container.register("InRaidHelper", { useClass: InRaidHelper }); - container.register("InventoryHelper", { useClass: InventoryHelper }); - container.register("PaymentHelper", PaymentHelper); - container.register("ItemHelper", { useClass: ItemHelper }); - container.register("PresetHelper", PresetHelper, { lifecycle: Lifecycle.Singleton }); - container.register("ProfileHelper", { useClass: ProfileHelper }); - container.register("QuestHelper", { useClass: QuestHelper }); - container.register("QuestConditionHelper", QuestConditionHelper); - container.register("RagfairHelper", { useClass: RagfairHelper }); - container.register("RagfairSortHelper", { useClass: RagfairSortHelper }); - container.register("RagfairSellHelper", { useClass: RagfairSellHelper }); - container.register("RagfairOfferHelper", { useClass: RagfairOfferHelper }); - container.register("RagfairServerHelper", { useClass: RagfairServerHelper }); - container.register("RepairHelper", { useClass: RepairHelper }); - container.register("TraderHelper", TraderHelper); - container.register("TraderAssortHelper", TraderAssortHelper, { lifecycle: Lifecycle.Singleton }); - container.register("TradeHelper", { useClass: TradeHelper }); - container.register("NotifierHelper", { useClass: NotifierHelper }); - container.register("UtilityHelper", UtilityHelper); - container.register("WeightedRandomHelper", { useClass: WeightedRandomHelper }); - container.register("HttpServerHelper", { useClass: HttpServerHelper }); - container.register("NotificationSendHelper", { useClass: NotificationSendHelper }); - container.register("SecureContainerHelper", { useClass: SecureContainerHelper }); - container.register("ProbabilityHelper", { useClass: ProbabilityHelper }); - container.register("BotWeaponGeneratorHelper", { useClass: BotWeaponGeneratorHelper }); - container.register("BotDifficultyHelper", { useClass: BotDifficultyHelper }); - container.register("RepeatableQuestHelper", { useClass: RepeatableQuestHelper }); - } - - private registerLoaders(container: DependencyContainer): void - { - // Loaders - container.register("BundleLoader", BundleLoader, { lifecycle: Lifecycle.Singleton }); - container.register("PreAkiModLoader", PreAkiModLoader, { lifecycle: Lifecycle.Singleton }); - container.register("PostAkiModLoader", PostAkiModLoader, { lifecycle: Lifecycle.Singleton }); - } - - private registerCallbacks(container: DependencyContainer): void - { - // Callbacks - container.register("BotCallbacks", { useClass: BotCallbacks }); - container.register("BundleCallbacks", { useClass: BundleCallbacks }); - container.register("ClientLogCallbacks", { useClass: ClientLogCallbacks }); - container.register("CustomizationCallbacks", { useClass: CustomizationCallbacks }); - container.register("DataCallbacks", { useClass: DataCallbacks }); - container.register("DialogueCallbacks", { useClass: DialogueCallbacks }); - container.register("GameCallbacks", { useClass: GameCallbacks }); - container.register("HandbookCallbacks", { useClass: HandbookCallbacks }); - container.register("HealthCallbacks", { useClass: HealthCallbacks }); - container.register("HideoutCallbacks", { useClass: HideoutCallbacks }); - container.register("HttpCallbacks", { useClass: HttpCallbacks }); - container.register("InraidCallbacks", { useClass: InraidCallbacks }); - container.register("InsuranceCallbacks", { useClass: InsuranceCallbacks }); - container.register("InventoryCallbacks", { useClass: InventoryCallbacks }); - container.register("ItemEventCallbacks", { useClass: ItemEventCallbacks }); - container.register("LauncherCallbacks", { useClass: LauncherCallbacks }); - container.register("LocationCallbacks", { useClass: LocationCallbacks }); - container.register("MatchCallbacks", { useClass: MatchCallbacks }); - container.register("ModCallbacks", { useClass: ModCallbacks }); - container.register("PostDBModLoader", { useClass: PostDBModLoader }); - container.register("NoteCallbacks", { useClass: NoteCallbacks }); - container.register("NotifierCallbacks", { useClass: NotifierCallbacks }); - container.register("PresetBuildCallbacks", { useClass: PresetBuildCallbacks }); - container.register("PresetCallbacks", { useClass: PresetCallbacks }); - container.register("ProfileCallbacks", { useClass: ProfileCallbacks }); - container.register("QuestCallbacks", { useClass: QuestCallbacks }); - container.register("RagfairCallbacks", { useClass: RagfairCallbacks }); - container.register("RepairCallbacks", { useClass: RepairCallbacks }); - container.register("SaveCallbacks", { useClass: SaveCallbacks }); - container.register("TradeCallbacks", { useClass: TradeCallbacks }); - container.register("TraderCallbacks", { useClass: TraderCallbacks }); - container.register("WeatherCallbacks", { useClass: WeatherCallbacks }); - container.register("WishlistCallbacks", { useClass: WishlistCallbacks }); - } - - private registerServices(container: DependencyContainer): void - { - // Services - container.register("ImageRouteService", ImageRouteService, { lifecycle: Lifecycle.Singleton }); - container.register("FenceService", FenceService, { lifecycle: Lifecycle.Singleton }); - container.register("PlayerService", { useClass: PlayerService }); - container.register("PaymentService", { useClass: PaymentService }); - container.register("InsuranceService", InsuranceService, { lifecycle: Lifecycle.Singleton }); - container.register("TraderAssortService", TraderAssortService, { lifecycle: Lifecycle.Singleton }); - container.register("RagfairPriceService", RagfairPriceService, { lifecycle: Lifecycle.Singleton }); - container.register("RagfairCategoriesService", RagfairCategoriesService, { lifecycle: Lifecycle.Singleton }); - container.register("RagfairOfferService", RagfairOfferService, { lifecycle: Lifecycle.Singleton }); - container.register("RagfairLinkedItemService", RagfairLinkedItemService, { lifecycle: Lifecycle.Singleton }); - container.register("RagfairRequiredItemsService", RagfairRequiredItemsService, { lifecycle: Lifecycle.Singleton }); - container.register("NotificationService", NotificationService, { lifecycle: Lifecycle.Singleton }); - container.register("MatchLocationService", MatchLocationService, { lifecycle: Lifecycle.Singleton }); - container.register("ModCompilerService", ModCompilerService); - container.register("HashCacheService", HashCacheService, { lifecycle: Lifecycle.Singleton }); - container.register("LocaleService", LocaleService, { lifecycle: Lifecycle.Singleton }); - container.register("ProfileFixerService", ProfileFixerService); - container.register("RepairService", RepairService); - container.register("BotLootCacheService", BotLootCacheService, { lifecycle: Lifecycle.Singleton }); - container.register("CustomItemService", CustomItemService); - container.register("BotEquipmentFilterService", BotEquipmentFilterService); - container.register("ProfileSnapshotService", ProfileSnapshotService, { lifecycle: Lifecycle.Singleton }); - container.register("ItemFilterService", ItemFilterService, { lifecycle: Lifecycle.Singleton }); - container.register("BotGenerationCacheService", BotGenerationCacheService, { lifecycle: Lifecycle.Singleton }); - container.register("LocalisationService", LocalisationService, { lifecycle: Lifecycle.Singleton }); - container.register("CustomLocationWaveService", CustomLocationWaveService, { lifecycle: Lifecycle.Singleton }); - container.register("OpenZoneService", OpenZoneService, { lifecycle: Lifecycle.Singleton }); - container.register("ItemBaseClassService", ItemBaseClassService, { lifecycle: Lifecycle.Singleton }); - container.register("BotEquipmentModPoolService", BotEquipmentModPoolService, { lifecycle: Lifecycle.Singleton }); - container.register("BotWeaponModLimitService", BotWeaponModLimitService, { lifecycle: Lifecycle.Singleton }); - container.register("SeasonalEventService", SeasonalEventService, { lifecycle: Lifecycle.Singleton }); - container.register("MatchBotDetailsCacheService", MatchBotDetailsCacheService, { lifecycle: Lifecycle.Singleton }); - container.register("RagfairTaxService", RagfairTaxService, { lifecycle: Lifecycle.Singleton }); - container.register("TraderPurchasePersisterService", TraderPurchasePersisterService); - container.register("PmcChatResponseService", PmcChatResponseService); - container.register("GiftService", GiftService); - container.register("MailSendService", MailSendService); - } - - private registerServers(container: DependencyContainer): void - { - // Servers - container.register("DatabaseServer", DatabaseServer, { lifecycle: Lifecycle.Singleton }); - container.register("HttpServer", HttpServer, { lifecycle: Lifecycle.Singleton }); - container.register("WebSocketServer", WebSocketServer, { lifecycle: Lifecycle.Singleton }); - container.register("RagfairServer", RagfairServer); - container.register("SaveServer", SaveServer, { lifecycle: Lifecycle.Singleton }); - container.register("ConfigServer", ConfigServer, { lifecycle: Lifecycle.Singleton }); - container.register("HttpBufferHandler", HttpBufferHandler, {lifecycle: Lifecycle.Singleton}); - } - - private registerControllers(container: DependencyContainer): void - { - // Controllers - container.register("BotController", { useClass: BotController }); - container.register("ClientLogController", { useClass: ClientLogController }); - container.register("CustomizationController", { useClass: CustomizationController }); - container.register("DialogueController", { useClass: DialogueController }); - container.register("GameController", { useClass: GameController }); - container.register("HandbookController", { useClass: HandbookController }); - container.register("HealthController", { useClass: HealthController }); - container.register("HideoutController", { useClass: HideoutController }); - container.register("InraidController", { useClass: InraidController }); - container.register("InsuranceController", { useClass: InsuranceController }); - container.register("InventoryController", { useClass: InventoryController }); - container.register("LauncherController", { useClass: LauncherController }); - container.register("LocationController", { useClass: LocationController }); - container.register("MatchController", MatchController); - container.register("NoteController", { useClass: NoteController }); - container.register("NotifierController", { useClass: NotifierController }); - container.register("PresetBuildController", { useClass: PresetBuildController }); - container.register("PresetController", { useClass: PresetController }); - container.register("ProfileController", { useClass: ProfileController }); - container.register("QuestController", { useClass: QuestController }); - container.register("RagfairController", { useClass: RagfairController }); - container.register("RepairController", { useClass: RepairController }); - container.register("RepeatableQuestController", { useClass: RepeatableQuestController }); - container.register("TradeController", { useClass: TradeController }); - container.register("TraderController", { useClass: TraderController }); - container.register("WeatherController", { useClass: WeatherController }); - container.register("WishlistController", WishlistController); - } - - private registerListTypes(container: DependencyContainer): void - { - container.register("OnLoadModService", { useValue: new OnLoadModService(container) }); - container.register("HttpListenerModService", { useValue: new HttpListenerModService(container) }); - container.register("OnUpdateModService", { useValue: new OnUpdateModService(container) }); - container.register("DynamicRouterModService", { useValue: new DynamicRouterModService(container) }); - container.register("StaticRouterModService", { useValue: new StaticRouterModService(container) }); - - container.registerType("OnLoad", "DatabaseImporter"); - container.registerType("OnLoad", "PostDBModLoader"); - container.registerType("OnLoad", "HandbookCallbacks"); - container.registerType("OnLoad", "HttpCallbacks"); - container.registerType("OnLoad", "PresetCallbacks"); - container.registerType("OnLoad", "SaveCallbacks"); - container.registerType("OnLoad", "TraderCallbacks"); // must occur prior to RagfairCallbacks - container.registerType("OnLoad", "RagfairPriceService"); - container.registerType("OnLoad", "RagfairCallbacks"); - container.registerType("OnLoad", "ModCallbacks"); - container.registerType("OnLoad", "GameCallbacks"); - - container.registerType("OnUpdate", "DialogueCallbacks"); - container.registerType("OnUpdate", "HideoutCallbacks"); - container.registerType("OnUpdate", "TraderCallbacks"); - container.registerType("OnUpdate", "RagfairCallbacks"); - container.registerType("OnUpdate", "InsuranceCallbacks"); - container.registerType("OnUpdate", "SaveCallbacks"); - - container.registerType("StaticRoutes", "BotStaticRouter"); - container.registerType("StaticRoutes", "ClientLogStaticRouter"); - container.registerType("StaticRoutes", "CustomizationStaticRouter"); - container.registerType("StaticRoutes", "DataStaticRouter"); - container.registerType("StaticRoutes", "DialogStaticRouter"); - container.registerType("StaticRoutes", "GameStaticRouter"); - container.registerType("StaticRoutes", "HealthStaticRouter"); - container.registerType("StaticRoutes", "InraidStaticRouter"); - container.registerType("StaticRoutes", "InsuranceStaticRouter"); - container.registerType("StaticRoutes", "ItemEventStaticRouter"); - container.registerType("StaticRoutes", "LauncherStaticRouter"); - container.registerType("StaticRoutes", "LocationStaticRouter"); - container.registerType("StaticRoutes", "WeatherStaticRouter"); - container.registerType("StaticRoutes", "MatchStaticRouter"); - container.registerType("StaticRoutes", "QuestStaticRouter"); - container.registerType("StaticRoutes", "RagfairStaticRouter"); - container.registerType("StaticRoutes", "PresetStaticRouter"); - container.registerType("StaticRoutes", "BundleStaticRouter"); - container.registerType("StaticRoutes", "NotifierStaticRouter"); - container.registerType("StaticRoutes", "ProfileStaticRouter"); - container.registerType("StaticRoutes", "TraderStaticRouter"); - - container.registerType("DynamicRoutes", "BotDynamicRouter"); - container.registerType("DynamicRoutes", "BundleDynamicRouter"); - container.registerType("DynamicRoutes", "CustomizationDynamicRouter"); - container.registerType("DynamicRoutes", "DataDynamicRouter"); - container.registerType("DynamicRoutes", "HttpDynamicRouter"); - container.registerType("DynamicRoutes", "InraidDynamicRouter"); - container.registerType("DynamicRoutes", "LocationDynamicRouter"); - container.registerType("DynamicRoutes", "NotifierDynamicRouter"); - container.registerType("DynamicRoutes", "TraderDynamicRouter"); - - container.registerType("IERouters", "CustomizationItemEventRouter"); - container.registerType("IERouters", "HealthItemEventRouter"); - container.registerType("IERouters", "HideoutItemEventRouter"); - container.registerType("IERouters", "InsuranceItemEventRouter"); - container.registerType("IERouters", "InventoryItemEventRouter"); - container.registerType("IERouters", "NoteItemEventRouter"); - container.registerType("IERouters", "PresetBuildItemEventRouter"); - container.registerType("IERouters", "QuestItemEventRouter"); - container.registerType("IERouters", "RagfairItemEventRouter"); - container.registerType("IERouters", "RepairItemEventRouter"); - container.registerType("IERouters", "TradeItemEventRouter"); - container.registerType("IERouters", "WishlistItemEventRouter"); - - container.registerType("Serializer", "ImageSerializer"); - container.registerType("Serializer", "BundleSerializer"); - container.registerType("Serializer", "NotifySerializer"); - - // Registering these starts the server...? - container.registerType("SaveLoadRouter", "HealthSaveLoadRouter"); - container.registerType("SaveLoadRouter", "InraidSaveLoadRouter"); - container.registerType("SaveLoadRouter", "InsuranceSaveLoadRouter"); - container.registerType("SaveLoadRouter", "ProfileSaveLoadRouter"); - } - - private async importDatabase(): Promise - { - this.importerUtil = this.container.resolve("ImporterUtil"); - this.databaseServer = this.container.resolve("DatabaseServer"); - - // Read the data from the JSON files. - const databaseDir = path.resolve("./assets/database"); - const dataToImport = await this.importerUtil.loadAsync(`${databaseDir}/`); - - // Save the data to memory. - this.databaseServer.setTables(dataToImport); - } + return container; +} + +function registerUtils(container: DependencyContainer): void +{ + // Utils + container.register("App", App, { lifecycle: Lifecycle.Singleton }); + container.register("DatabaseImporter", DatabaseImporter, { lifecycle: Lifecycle.Singleton }); + container.register("HashUtil", HashUtil, { lifecycle: Lifecycle.Singleton }); + container.register("ImporterUtil", ImporterUtil, { lifecycle: Lifecycle.Singleton }); + container.register("HttpResponseUtil", HttpResponseUtil); + container.register("EncodingUtil", EncodingUtil, { lifecycle: Lifecycle.Singleton }); + container.register("JsonUtil", JsonUtil); + container.register("WinstonLogger", WinstonMainLogger, { lifecycle: Lifecycle.Singleton }); + container.register("RequestsLogger", WinstonRequestLogger, { lifecycle: Lifecycle.Singleton }); + container.register("MathUtil", MathUtil, { lifecycle: Lifecycle.Singleton }); + container.register("ObjectId", ObjectId); + container.register("RandomUtil", RandomUtil, { lifecycle: Lifecycle.Singleton }); + container.register("TimeUtil", TimeUtil, { lifecycle: Lifecycle.Singleton }); + container.register("VFS", VFS, { lifecycle: Lifecycle.Singleton }); + + // These two trouble-makers are manually mocked, as the original implementation hijacks our test console. + container.register("WatermarkLocale", WatermarkLocale, { lifecycle: Lifecycle.Singleton }); + container.register("Watermark", Watermark, { lifecycle: Lifecycle.Singleton }); + + container.register("AsyncQueue", AsyncQueue, { lifecycle: Lifecycle.Singleton }); + container.register("UUidGenerator", UUidGenerator, { lifecycle: Lifecycle.Singleton }); + container.register("HttpFileUtil", HttpFileUtil, { lifecycle: Lifecycle.Singleton }); + container.register("ModLoadOrder", ModLoadOrder, { lifecycle: Lifecycle.Singleton }); + container.register("ModTypeCheck", ModTypeCheck, { lifecycle: Lifecycle.Singleton }); +} + +function registerRouters(container: DependencyContainer): void +{ + // Routers + container.register("HttpRouter", HttpRouter, { lifecycle: Lifecycle.Singleton }); + container.register("ImageRouter", ImageRouter); + container.register("EventOutputHolder", EventOutputHolder, { lifecycle: Lifecycle.Singleton }); + container.register("ItemEventRouter", ItemEventRouter); + + // Dynamic Routes + container.register("BotDynamicRouter", { useClass: BotDynamicRouter }); + container.register("BundleDynamicRouter", { useClass: BundleDynamicRouter }); + container.register("CustomizationDynamicRouter", { useClass: CustomizationDynamicRouter }); + container.register("DataDynamicRouter", { useClass: DataDynamicRouter }); + container.register("HttpDynamicRouter", { useClass: HttpDynamicRouter }); + container.register("InraidDynamicRouter", { useClass: InraidDynamicRouter }); + container.register("LocationDynamicRouter", { useClass: LocationDynamicRouter }); + container.register("NotifierDynamicRouter", { useClass: NotifierDynamicRouter }); + container.register("TraderDynamicRouter", { useClass: TraderDynamicRouter }); + + // Item Event Routes + container.register("CustomizationItemEventRouter", { useClass: CustomizationItemEventRouter }); + container.register("HealthItemEventRouter", { useClass: HealthItemEventRouter }); + container.register("HideoutItemEventRouter", { useClass: HideoutItemEventRouter }); + container.register("InsuranceItemEventRouter", { useClass: InsuranceItemEventRouter }); + container.register("InventoryItemEventRouter", { useClass: InventoryItemEventRouter }); + container.register("NoteItemEventRouter", { useClass: NoteItemEventRouter }); + container.register("PresetBuildItemEventRouter", { useClass: PresetBuildItemEventRouter }); + container.register("QuestItemEventRouter", { useClass: QuestItemEventRouter }); + container.register("RagfairItemEventRouter", { useClass: RagfairItemEventRouter }); + container.register("RepairItemEventRouter", { useClass: RepairItemEventRouter }); + container.register("TradeItemEventRouter", { useClass: TradeItemEventRouter }); + container.register("WishlistItemEventRouter", { useClass: WishlistItemEventRouter }); + + // Save Load Routes + container.register("HealthSaveLoadRouter", { useClass: HealthSaveLoadRouter }); + container.register("InraidSaveLoadRouter", { useClass: InraidSaveLoadRouter }); + container.register("InsuranceSaveLoadRouter", { useClass: InsuranceSaveLoadRouter }); + container.register("ProfileSaveLoadRouter", { useClass: ProfileSaveLoadRouter }); + + // Route Serializers + container.register("BundleSerializer", { useClass: BundleSerializer }); + container.register("ImageSerializer", { useClass: ImageSerializer }); + container.register("NotifySerializer", { useClass: NotifySerializer }); + + // Static Routes + container.register("BotStaticRouter", { useClass: BotStaticRouter }); + container.register("BundleStaticRouter", { useClass: BundleStaticRouter }); + container.register("ClientLogStaticRouter", { useClass: ClientLogStaticRouter }); + container.register("CustomizationStaticRouter", { useClass: CustomizationStaticRouter }); + container.register("DataStaticRouter", { useClass: DataStaticRouter }); + container.register("DialogStaticRouter", { useClass: DialogStaticRouter }); + container.register("GameStaticRouter", { useClass: GameStaticRouter }); + container.register("HealthStaticRouter", { useClass: HealthStaticRouter }); + container.register("InraidStaticRouter", { useClass: InraidStaticRouter }); + container.register("InsuranceStaticRouter", { useClass: InsuranceStaticRouter }); + container.register("ItemEventStaticRouter", { useClass: ItemEventStaticRouter }); + container.register("LauncherStaticRouter", { useClass: LauncherStaticRouter }); + container.register("LocationStaticRouter", { useClass: LocationStaticRouter }); + container.register("MatchStaticRouter", { useClass: MatchStaticRouter }); + container.register("NotifierStaticRouter", { useClass: NotifierStaticRouter }); + container.register("PresetStaticRouter", { useClass: PresetStaticRouter }); + container.register("ProfileStaticRouter", { useClass: ProfileStaticRouter }); + container.register("QuestStaticRouter", { useClass: QuestStaticRouter }); + container.register("RagfairStaticRouter", { useClass: RagfairStaticRouter }); + container.register("TraderStaticRouter", { useClass: TraderStaticRouter }); + container.register("WeatherStaticRouter", { useClass: WeatherStaticRouter }); +} + +function registerGenerators(container: DependencyContainer): void +{ + // Generators + container.register("BotGenerator", BotGenerator); + container.register("BotWeaponGenerator", BotWeaponGenerator); + container.register("BotLootGenerator", BotLootGenerator); + container.register("BotInventoryGenerator", BotInventoryGenerator); + container.register("LocationGenerator", { useClass: LocationGenerator }); + container.register("PMCLootGenerator", PMCLootGenerator, { lifecycle: Lifecycle.Singleton }); + container.register("ScavCaseRewardGenerator", ScavCaseRewardGenerator, { lifecycle: Lifecycle.Singleton }); + container.register("RagfairAssortGenerator", { useClass: RagfairAssortGenerator }); + container.register("RagfairOfferGenerator", { useClass: RagfairOfferGenerator }); + container.register("WeatherGenerator", { useClass: WeatherGenerator }); + container.register("PlayerScavGenerator", { useClass: PlayerScavGenerator }); + container.register("LootGenerator", { useClass: LootGenerator }); + container.register("FenceBaseAssortGenerator", { useClass: FenceBaseAssortGenerator }); + container.register("BotLevelGenerator", { useClass: BotLevelGenerator }); + container.register("BotEquipmentModGenerator", { useClass: BotEquipmentModGenerator }); + container.register("RepeatableQuestGenerator", { useClass: RepeatableQuestGenerator }); + container.register("BarrelInventoryMagGen", { useClass: BarrelInventoryMagGen }); + container.register("ExternalInventoryMagGen", { useClass: ExternalInventoryMagGen }); + container.register("InternalMagazineInventoryMagGen", { useClass: InternalMagazineInventoryMagGen }); + container.register("UbglExternalMagGen", { useClass: UbglExternalMagGen }); + + container.registerType("InventoryMagGen", "BarrelInventoryMagGen"); + container.registerType("InventoryMagGen", "ExternalInventoryMagGen"); + container.registerType("InventoryMagGen", "InternalMagazineInventoryMagGen"); + container.registerType("InventoryMagGen", "UbglExternalMagGen"); +} + +function registerHelpers(container: DependencyContainer): void +{ + // Helpers + container.register("AssortHelper", { useClass: AssortHelper }); + container.register("BotHelper", { useClass: BotHelper }); + container.register("BotGeneratorHelper", { useClass: BotGeneratorHelper }); + container.register("ContainerHelper", ContainerHelper); + container.register("DialogueHelper", { useClass: DialogueHelper }); + container.register("DurabilityLimitsHelper", { useClass: DurabilityLimitsHelper }); + container.register("GameEventHelper", GameEventHelper); + container.register("HandbookHelper", HandbookHelper, { lifecycle: Lifecycle.Singleton }); + container.register("HealthHelper", { useClass: HealthHelper }); + container.register("HideoutHelper", { useClass: HideoutHelper }); + container.register("InRaidHelper", { useClass: InRaidHelper }); + container.register("InventoryHelper", { useClass: InventoryHelper }); + container.register("PaymentHelper", PaymentHelper); + container.register("ItemHelper", { useClass: ItemHelper }); + container.register("PresetHelper", PresetHelper, { lifecycle: Lifecycle.Singleton }); + container.register("ProfileHelper", { useClass: ProfileHelper }); + container.register("QuestHelper", { useClass: QuestHelper }); + container.register("QuestConditionHelper", QuestConditionHelper); + container.register("RagfairHelper", { useClass: RagfairHelper }); + container.register("RagfairSortHelper", { useClass: RagfairSortHelper }); + container.register("RagfairSellHelper", { useClass: RagfairSellHelper }); + container.register("RagfairOfferHelper", { useClass: RagfairOfferHelper }); + container.register("RagfairServerHelper", { useClass: RagfairServerHelper }); + container.register("RepairHelper", { useClass: RepairHelper }); + container.register("TraderHelper", TraderHelper); + container.register("TraderAssortHelper", TraderAssortHelper, { lifecycle: Lifecycle.Singleton }); + container.register("TradeHelper", { useClass: TradeHelper }); + container.register("NotifierHelper", { useClass: NotifierHelper }); + container.register("UtilityHelper", UtilityHelper); + container.register("WeightedRandomHelper", { useClass: WeightedRandomHelper }); + container.register("HttpServerHelper", { useClass: HttpServerHelper }); + container.register("NotificationSendHelper", { useClass: NotificationSendHelper }); + container.register("SecureContainerHelper", { useClass: SecureContainerHelper }); + container.register("ProbabilityHelper", { useClass: ProbabilityHelper }); + container.register("BotWeaponGeneratorHelper", { useClass: BotWeaponGeneratorHelper }); + container.register("BotDifficultyHelper", { useClass: BotDifficultyHelper }); + container.register("RepeatableQuestHelper", { useClass: RepeatableQuestHelper }); +} + +function registerLoaders(container: DependencyContainer): void +{ + // Loaders + container.register("BundleLoader", BundleLoader, { lifecycle: Lifecycle.Singleton }); + container.register("PreAkiModLoader", PreAkiModLoader, { lifecycle: Lifecycle.Singleton }); + container.register("PostAkiModLoader", PostAkiModLoader, { lifecycle: Lifecycle.Singleton }); +} + +function registerCallbacks(container: DependencyContainer): void +{ + // Callbacks + container.register("BotCallbacks", { useClass: BotCallbacks }); + container.register("BundleCallbacks", { useClass: BundleCallbacks }); + container.register("ClientLogCallbacks", { useClass: ClientLogCallbacks }); + container.register("CustomizationCallbacks", { useClass: CustomizationCallbacks }); + container.register("DataCallbacks", { useClass: DataCallbacks }); + container.register("DialogueCallbacks", { useClass: DialogueCallbacks }); + container.register("GameCallbacks", { useClass: GameCallbacks }); + container.register("HandbookCallbacks", { useClass: HandbookCallbacks }); + container.register("HealthCallbacks", { useClass: HealthCallbacks }); + container.register("HideoutCallbacks", { useClass: HideoutCallbacks }); + container.register("HttpCallbacks", { useClass: HttpCallbacks }); + container.register("InraidCallbacks", { useClass: InraidCallbacks }); + container.register("InsuranceCallbacks", { useClass: InsuranceCallbacks }); + container.register("InventoryCallbacks", { useClass: InventoryCallbacks }); + container.register("ItemEventCallbacks", { useClass: ItemEventCallbacks }); + container.register("LauncherCallbacks", { useClass: LauncherCallbacks }); + container.register("LocationCallbacks", { useClass: LocationCallbacks }); + container.register("MatchCallbacks", { useClass: MatchCallbacks }); + container.register("ModCallbacks", { useClass: ModCallbacks }); + container.register("PostDBModLoader", { useClass: PostDBModLoader }); + container.register("NoteCallbacks", { useClass: NoteCallbacks }); + container.register("NotifierCallbacks", { useClass: NotifierCallbacks }); + container.register("PresetBuildCallbacks", { useClass: PresetBuildCallbacks }); + container.register("PresetCallbacks", { useClass: PresetCallbacks }); + container.register("ProfileCallbacks", { useClass: ProfileCallbacks }); + container.register("QuestCallbacks", { useClass: QuestCallbacks }); + container.register("RagfairCallbacks", { useClass: RagfairCallbacks }); + container.register("RepairCallbacks", { useClass: RepairCallbacks }); + container.register("SaveCallbacks", { useClass: SaveCallbacks }); + container.register("TradeCallbacks", { useClass: TradeCallbacks }); + container.register("TraderCallbacks", { useClass: TraderCallbacks }); + container.register("WeatherCallbacks", { useClass: WeatherCallbacks }); + container.register("WishlistCallbacks", { useClass: WishlistCallbacks }); +} + +function registerServices(container: DependencyContainer): void +{ + // Services + container.register("ImageRouteService", ImageRouteService, { lifecycle: Lifecycle.Singleton }); + container.register("FenceService", FenceService, { lifecycle: Lifecycle.Singleton }); + container.register("PlayerService", { useClass: PlayerService }); + container.register("PaymentService", { useClass: PaymentService }); + container.register("InsuranceService", InsuranceService, { lifecycle: Lifecycle.Singleton }); + container.register("TraderAssortService", TraderAssortService, { lifecycle: Lifecycle.Singleton }); + container.register("RagfairPriceService", RagfairPriceService, { lifecycle: Lifecycle.Singleton }); + container.register("RagfairCategoriesService", RagfairCategoriesService, { lifecycle: Lifecycle.Singleton }); + container.register("RagfairOfferService", RagfairOfferService, { lifecycle: Lifecycle.Singleton }); + container.register("RagfairLinkedItemService", RagfairLinkedItemService, { lifecycle: Lifecycle.Singleton }); + container.register("RagfairRequiredItemsService", RagfairRequiredItemsService, { lifecycle: Lifecycle.Singleton }); + container.register("NotificationService", NotificationService, { lifecycle: Lifecycle.Singleton }); + container.register("MatchLocationService", MatchLocationService, { lifecycle: Lifecycle.Singleton }); + container.register("ModCompilerService", ModCompilerService); + container.register("HashCacheService", HashCacheService, { lifecycle: Lifecycle.Singleton }); + container.register("LocaleService", LocaleService, { lifecycle: Lifecycle.Singleton }); + container.register("ProfileFixerService", ProfileFixerService); + container.register("RepairService", RepairService); + container.register("BotLootCacheService", BotLootCacheService, { lifecycle: Lifecycle.Singleton }); + container.register("CustomItemService", CustomItemService); + container.register("BotEquipmentFilterService", BotEquipmentFilterService); + container.register("ProfileSnapshotService", ProfileSnapshotService, { lifecycle: Lifecycle.Singleton }); + container.register("ItemFilterService", ItemFilterService, { lifecycle: Lifecycle.Singleton }); + container.register("BotGenerationCacheService", BotGenerationCacheService, { lifecycle: Lifecycle.Singleton }); + container.register("LocalisationService", LocalisationService, { lifecycle: Lifecycle.Singleton }); + container.register("CustomLocationWaveService", CustomLocationWaveService, { lifecycle: Lifecycle.Singleton }); + container.register("OpenZoneService", OpenZoneService, { lifecycle: Lifecycle.Singleton }); + container.register("ItemBaseClassService", ItemBaseClassService, { lifecycle: Lifecycle.Singleton }); + container.register("BotEquipmentModPoolService", BotEquipmentModPoolService, { lifecycle: Lifecycle.Singleton }); + container.register("BotWeaponModLimitService", BotWeaponModLimitService, { lifecycle: Lifecycle.Singleton }); + container.register("SeasonalEventService", SeasonalEventService, { lifecycle: Lifecycle.Singleton }); + container.register("MatchBotDetailsCacheService", MatchBotDetailsCacheService, { lifecycle: Lifecycle.Singleton }); + container.register("RagfairTaxService", RagfairTaxService, { lifecycle: Lifecycle.Singleton }); + container.register("TraderPurchasePersisterService", TraderPurchasePersisterService); + container.register("PmcChatResponseService", PmcChatResponseService); + container.register("GiftService", GiftService); + container.register("MailSendService", MailSendService); +} + +function registerServers(container: DependencyContainer): void +{ + // Servers + container.register("DatabaseServer", DatabaseServer, { lifecycle: Lifecycle.Singleton }); + container.register("HttpServer", HttpServer, { lifecycle: Lifecycle.Singleton }); + container.register("WebSocketServer", WebSocketServer, { lifecycle: Lifecycle.Singleton }); + container.register("RagfairServer", RagfairServer); + container.register("SaveServer", SaveServer, { lifecycle: Lifecycle.Singleton }); + container.register("ConfigServer", ConfigServer, { lifecycle: Lifecycle.Singleton }); + container.register("HttpBufferHandler", HttpBufferHandler, {lifecycle: Lifecycle.Singleton}); +} + +function registerControllers(container: DependencyContainer): void +{ + // Controllers + container.register("BotController", { useClass: BotController }); + container.register("ClientLogController", { useClass: ClientLogController }); + container.register("CustomizationController", { useClass: CustomizationController }); + container.register("DialogueController", { useClass: DialogueController }); + container.register("GameController", { useClass: GameController }); + container.register("HandbookController", { useClass: HandbookController }); + container.register("HealthController", { useClass: HealthController }); + container.register("HideoutController", { useClass: HideoutController }); + container.register("InraidController", { useClass: InraidController }); + container.register("InsuranceController", { useClass: InsuranceController }); + container.register("InventoryController", { useClass: InventoryController }); + container.register("LauncherController", { useClass: LauncherController }); + container.register("LocationController", { useClass: LocationController }); + container.register("MatchController", MatchController); + container.register("NoteController", { useClass: NoteController }); + container.register("NotifierController", { useClass: NotifierController }); + container.register("PresetBuildController", { useClass: PresetBuildController }); + container.register("PresetController", { useClass: PresetController }); + container.register("ProfileController", { useClass: ProfileController }); + container.register("QuestController", { useClass: QuestController }); + container.register("RagfairController", { useClass: RagfairController }); + container.register("RepairController", { useClass: RepairController }); + container.register("RepeatableQuestController", { useClass: RepeatableQuestController }); + container.register("TradeController", { useClass: TradeController }); + container.register("TraderController", { useClass: TraderController }); + container.register("WeatherController", { useClass: WeatherController }); + container.register("WishlistController", WishlistController); +} + +function registerListTypes(container: DependencyContainer): void +{ + container.register("OnLoadModService", { useValue: new OnLoadModService(container) }); + container.register("HttpListenerModService", { useValue: new HttpListenerModService(container) }); + container.register("OnUpdateModService", { useValue: new OnUpdateModService(container) }); + container.register("DynamicRouterModService", { useValue: new DynamicRouterModService(container) }); + container.register("StaticRouterModService", { useValue: new StaticRouterModService(container) }); + + container.registerType("OnLoad", "DatabaseImporter"); + container.registerType("OnLoad", "PostDBModLoader"); + container.registerType("OnLoad", "HandbookCallbacks"); + container.registerType("OnLoad", "HttpCallbacks"); + container.registerType("OnLoad", "PresetCallbacks"); + container.registerType("OnLoad", "SaveCallbacks"); + container.registerType("OnLoad", "TraderCallbacks"); // must occur prior to RagfairCallbacks + container.registerType("OnLoad", "RagfairPriceService"); + container.registerType("OnLoad", "RagfairCallbacks"); + container.registerType("OnLoad", "ModCallbacks"); + container.registerType("OnLoad", "GameCallbacks"); + + container.registerType("OnUpdate", "DialogueCallbacks"); + container.registerType("OnUpdate", "HideoutCallbacks"); + container.registerType("OnUpdate", "TraderCallbacks"); + container.registerType("OnUpdate", "RagfairCallbacks"); + container.registerType("OnUpdate", "InsuranceCallbacks"); + container.registerType("OnUpdate", "SaveCallbacks"); + + container.registerType("StaticRoutes", "BotStaticRouter"); + container.registerType("StaticRoutes", "ClientLogStaticRouter"); + container.registerType("StaticRoutes", "CustomizationStaticRouter"); + container.registerType("StaticRoutes", "DataStaticRouter"); + container.registerType("StaticRoutes", "DialogStaticRouter"); + container.registerType("StaticRoutes", "GameStaticRouter"); + container.registerType("StaticRoutes", "HealthStaticRouter"); + container.registerType("StaticRoutes", "InraidStaticRouter"); + container.registerType("StaticRoutes", "InsuranceStaticRouter"); + container.registerType("StaticRoutes", "ItemEventStaticRouter"); + container.registerType("StaticRoutes", "LauncherStaticRouter"); + container.registerType("StaticRoutes", "LocationStaticRouter"); + container.registerType("StaticRoutes", "WeatherStaticRouter"); + container.registerType("StaticRoutes", "MatchStaticRouter"); + container.registerType("StaticRoutes", "QuestStaticRouter"); + container.registerType("StaticRoutes", "RagfairStaticRouter"); + container.registerType("StaticRoutes", "PresetStaticRouter"); + container.registerType("StaticRoutes", "BundleStaticRouter"); + container.registerType("StaticRoutes", "NotifierStaticRouter"); + container.registerType("StaticRoutes", "ProfileStaticRouter"); + container.registerType("StaticRoutes", "TraderStaticRouter"); + + container.registerType("DynamicRoutes", "BotDynamicRouter"); + container.registerType("DynamicRoutes", "BundleDynamicRouter"); + container.registerType("DynamicRoutes", "CustomizationDynamicRouter"); + container.registerType("DynamicRoutes", "DataDynamicRouter"); + container.registerType("DynamicRoutes", "HttpDynamicRouter"); + container.registerType("DynamicRoutes", "InraidDynamicRouter"); + container.registerType("DynamicRoutes", "LocationDynamicRouter"); + container.registerType("DynamicRoutes", "NotifierDynamicRouter"); + container.registerType("DynamicRoutes", "TraderDynamicRouter"); + + container.registerType("IERouters", "CustomizationItemEventRouter"); + container.registerType("IERouters", "HealthItemEventRouter"); + container.registerType("IERouters", "HideoutItemEventRouter"); + container.registerType("IERouters", "InsuranceItemEventRouter"); + container.registerType("IERouters", "InventoryItemEventRouter"); + container.registerType("IERouters", "NoteItemEventRouter"); + container.registerType("IERouters", "PresetBuildItemEventRouter"); + container.registerType("IERouters", "QuestItemEventRouter"); + container.registerType("IERouters", "RagfairItemEventRouter"); + container.registerType("IERouters", "RepairItemEventRouter"); + container.registerType("IERouters", "TradeItemEventRouter"); + container.registerType("IERouters", "WishlistItemEventRouter"); + + container.registerType("Serializer", "ImageSerializer"); + container.registerType("Serializer", "BundleSerializer"); + container.registerType("Serializer", "NotifySerializer"); + + container.registerType("SaveLoadRouter", "HealthSaveLoadRouter"); + container.registerType("SaveLoadRouter", "InraidSaveLoadRouter"); + container.registerType("SaveLoadRouter", "InsuranceSaveLoadRouter"); + container.registerType("SaveLoadRouter", "ProfileSaveLoadRouter"); +} + +async function importDatabase(container: DependencyContainer): Promise +{ + const importerUtil = container.resolve("ImporterUtil"); + const databaseServer = container.resolve("DatabaseServer"); + + // Read the data from the JSON files. + const databaseDir = path.resolve("./assets/database"); + const dataToImport = await importerUtil.loadAsync(`${databaseDir}/`); + + // Save the data to memory. + databaseServer.setTables(dataToImport); } diff --git a/project/tests/helpers/ItemHelper.test.ts b/project/tests/helpers/ItemHelper.test.ts index e74f4bc2..67821766 100644 --- a/project/tests/helpers/ItemHelper.test.ts +++ b/project/tests/helpers/ItemHelper.test.ts @@ -1,5 +1,7 @@ import "reflect-metadata"; +import { vi, beforeAll, afterEach, describe, expect, it } from "vitest"; + import { ItemHelper } from "@spt-aki/helpers/ItemHelper"; import { DependencyContainer } from "tsyringe"; import { Item, Repairable } from "@spt-aki/models/eft/common/tables/IItem"; @@ -11,22 +13,15 @@ describe("ItemHelper", () => let container: DependencyContainer; let itemHelper: ItemHelper; - // Spies - let handbookHelperGetTemplatePriceSpy: jest.SpyInstance; - let loggerWarningSpy: jest.SpyInstance; - let loggerErrorSpy: jest.SpyInstance; - let databaseServerGetTablesSpy: jest.SpyInstance; - let jsonUtilCloneSpy: jest.SpyInstance; - beforeAll(() => { - container = globalThis.container; + container = global.container; itemHelper = container.resolve("ItemHelper"); }); afterEach(() => { - jest.restoreAllMocks(); + vi.restoreAllMocks(); }); describe("isValidItem", () => @@ -52,7 +47,7 @@ describe("ItemHelper", () => it("should return false when item's price is zero", () => { // Unsure if any item has price of "0", so mock the getItemPrice method to return 0. - jest.spyOn(itemHelper, "getItemPrice").mockReturnValue(0); + vi.spyOn(itemHelper, "getItemPrice").mockReturnValue(0); const result = itemHelper.isValidItem("5fc64ea372b0dd78d51159dc"); expect(result).toBe(false); @@ -112,7 +107,7 @@ describe("ItemHelper", () => const staticPrice = 1; const tpl = "590c657e86f77412b013051d"; - jest.spyOn(itemHelper, "getStaticItemPrice").mockReturnValue(staticPrice); + vi.spyOn(itemHelper, "getStaticItemPrice").mockReturnValue(staticPrice); const result = itemHelper.getItemPrice(tpl); @@ -125,8 +120,8 @@ describe("ItemHelper", () => const dynamicPrice = 42069; const tpl = "590c657e86f77412b013051d"; - jest.spyOn(itemHelper, "getStaticItemPrice").mockReturnValue(staticPrice); - jest.spyOn(itemHelper, "getDynamicItemPrice").mockReturnValue(dynamicPrice); + vi.spyOn(itemHelper, "getStaticItemPrice").mockReturnValue(staticPrice); + vi.spyOn(itemHelper, "getDynamicItemPrice").mockReturnValue(dynamicPrice); const result = itemHelper.getItemPrice(tpl); @@ -138,8 +133,8 @@ describe("ItemHelper", () => { const tpl = "590c657e86f77412b013051d"; - jest.spyOn(itemHelper, "getStaticItemPrice").mockReturnValue(0); - jest.spyOn(itemHelper, "getDynamicItemPrice").mockReturnValue(0); + vi.spyOn(itemHelper, "getStaticItemPrice").mockReturnValue(0); + vi.spyOn(itemHelper, "getDynamicItemPrice").mockReturnValue(0); const result = itemHelper.getItemPrice(tpl); @@ -156,8 +151,8 @@ describe("ItemHelper", () => const dynamicPrice = 69; const tpl = "590c657e86f77412b013051d"; - jest.spyOn(itemHelper, "getStaticItemPrice").mockReturnValue(staticPrice); - jest.spyOn(itemHelper, "getDynamicItemPrice").mockReturnValue(dynamicPrice); + vi.spyOn(itemHelper, "getStaticItemPrice").mockReturnValue(staticPrice); + vi.spyOn(itemHelper, "getDynamicItemPrice").mockReturnValue(dynamicPrice); const result = itemHelper.getItemMaxPrice(tpl); @@ -170,8 +165,8 @@ describe("ItemHelper", () => const dynamicPrice = 420; const tpl = "590c657e86f77412b013051d"; - jest.spyOn(itemHelper, "getStaticItemPrice").mockReturnValue(staticPrice); - jest.spyOn(itemHelper, "getDynamicItemPrice").mockReturnValue(dynamicPrice); + vi.spyOn(itemHelper, "getStaticItemPrice").mockReturnValue(staticPrice); + vi.spyOn(itemHelper, "getDynamicItemPrice").mockReturnValue(dynamicPrice); const result = itemHelper.getItemMaxPrice(tpl); @@ -183,8 +178,8 @@ describe("ItemHelper", () => const price = 42069; const tpl = "590c657e86f77412b013051d"; - jest.spyOn(itemHelper, "getStaticItemPrice").mockReturnValue(price); - jest.spyOn(itemHelper, "getDynamicItemPrice").mockReturnValue(price); + vi.spyOn(itemHelper, "getStaticItemPrice").mockReturnValue(price); + vi.spyOn(itemHelper, "getDynamicItemPrice").mockReturnValue(price); const result = itemHelper.getItemMaxPrice(tpl); @@ -209,7 +204,7 @@ describe("ItemHelper", () => const price = 42069; const tpl = "590c657e86f77412b013051d"; - handbookHelperGetTemplatePriceSpy = jest.spyOn((itemHelper as any).handbookHelper, "getTemplatePrice"); + const handbookHelperGetTemplatePriceSpy = vi.spyOn((itemHelper as any).handbookHelper, "getTemplatePrice"); handbookHelperGetTemplatePriceSpy.mockReturnValue(price); const result = itemHelper.getStaticItemPrice(tpl); @@ -222,7 +217,7 @@ describe("ItemHelper", () => const price = 0; const tpl = "590c657e86f77412b013051d"; // "Grizzly medical kit" - handbookHelperGetTemplatePriceSpy = jest.spyOn((itemHelper as any).handbookHelper, "getTemplatePrice"); + const handbookHelperGetTemplatePriceSpy = vi.spyOn((itemHelper as any).handbookHelper, "getTemplatePrice"); handbookHelperGetTemplatePriceSpy.mockReturnValue(price); const result = itemHelper.getStaticItemPrice(tpl); @@ -320,7 +315,7 @@ describe("ItemHelper", () => const parentId = container.resolve("HashUtil").generate(); - loggerWarningSpy = jest.spyOn((itemHelper as any).logger, "warning"); + const loggerWarningSpy = vi.spyOn((itemHelper as any).logger, "warning"); itemHelper.generateItemsFromStackSlot(ammoBox[1], parentId); @@ -332,8 +327,8 @@ describe("ItemHelper", () => { it("should call databaseServer.getTables() and jsonUtil.clone() methods", () => { - databaseServerGetTablesSpy = jest.spyOn((itemHelper as any).databaseServer, "getTables"); - jsonUtilCloneSpy = jest.spyOn((itemHelper as any).jsonUtil, "clone"); + const databaseServerGetTablesSpy = vi.spyOn((itemHelper as any).databaseServer, "getTables"); + const jsonUtilCloneSpy = vi.spyOn((itemHelper as any).jsonUtil, "clone"); itemHelper.getItems(); @@ -404,7 +399,7 @@ describe("ItemHelper", () => it("should call getItem with the provided tpl", () => { - const itemHelperSpy = jest.spyOn(itemHelper, "getItem"); + const itemHelperSpy = vi.spyOn(itemHelper, "getItem"); const tpl = "590c657e86f77412b013051d"; // "Grizzly medical kit" @@ -717,7 +712,7 @@ describe("ItemHelper", () => _tpl: "" }; - loggerErrorSpy = jest.spyOn((itemHelper as any).logger, "error"); + const loggerErrorSpy = vi.spyOn((itemHelper as any).logger, "error"); // Cast the method to any to allow access to private/protected method. (itemHelper as any).getRepairableItemQualityValue(weapon, repairable, item); diff --git a/project/tests/services/PaymentService.test.ts b/project/tests/services/PaymentService.test.ts index 485ee80b..79a1456a 100644 --- a/project/tests/services/PaymentService.test.ts +++ b/project/tests/services/PaymentService.test.ts @@ -1,6 +1,8 @@ import "reflect-metadata"; -import { DependencyContainer } from "tsyringe"; +import { vi, beforeAll, afterEach, describe, expect, it } from "vitest"; + +import { DependencyContainer } from "tsyringe"; import { PaymentService } from "@spt-aki/services/PaymentService"; describe("PaymentService", () => @@ -10,13 +12,13 @@ describe("PaymentService", () => beforeAll(() => { - container = globalThis.container; + container = global.container; paymentService = container.resolve("PaymentService"); }); afterEach(() => { - jest.restoreAllMocks(); + vi.restoreAllMocks(); }); describe("should be registered", () => diff --git a/project/tsconfig.json b/project/tsconfig.json index de909065..229ba4e3 100644 --- a/project/tsconfig.json +++ b/project/tsconfig.json @@ -8,6 +8,9 @@ "paths": { "@spt-aki/*": [ "src/*" + ], + "@tests/*": [ + "tests/*" ] } }, diff --git a/project/tsconfig.test.json b/project/tsconfig.test.json index c7d718a9..bc28a536 100644 --- a/project/tsconfig.test.json +++ b/project/tsconfig.test.json @@ -4,7 +4,8 @@ "outDir": "obj", "declaration": true, "sourceMap": true, - "noImplicitAny": false + "noImplicitAny": false, + "types": ["vitest/globals"], }, "include": [ "./types/**/*", diff --git a/project/vitest.config.ts b/project/vitest.config.ts new file mode 100644 index 00000000..cc28a7ed --- /dev/null +++ b/project/vitest.config.ts @@ -0,0 +1,16 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import path from "path"; +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + name: "spt-server", + root: "./tests", + environment: "./CustomEnvironment.ts", + globals: true, + alias: { + "@spt-aki": path.resolve(__dirname, "src"), + "@tests": path.resolve(__dirname, "tests") + } + } +});