import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute"; import { StorageService } from "@bitwarden/common/abstractions/storage.service"; import { StateVersion } from "@bitwarden/common/enums/stateVersion"; import { StateFactory } from "@bitwarden/common/factories/stateFactory"; import { Account } from "@bitwarden/common/models/domain/account"; import { GlobalState } from "@bitwarden/common/models/domain/globalState"; import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service"; const userId = "USER_ID"; describe("State Migration Service", () => { let storageService: SubstituteOf; let secureStorageService: SubstituteOf; let stateFactory: SubstituteOf; let stateMigrationService: StateMigrationService; beforeEach(() => { storageService = Substitute.for(); secureStorageService = Substitute.for(); stateFactory = Substitute.for(); stateMigrationService = new StateMigrationService( storageService, secureStorageService, stateFactory ); }); describe("StateVersion 3 to 4 migration", async () => { beforeEach(() => { const globalVersion3: Partial = { stateVersion: StateVersion.Three, }; storageService.get("global", Arg.any()).resolves(globalVersion3); storageService.get("authenticatedAccounts", Arg.any()).resolves([userId]); }); it("clears everBeenUnlocked", async () => { const accountVersion3: Account = { profile: { apiKeyClientId: null, convertAccountToKeyConnector: null, email: "EMAIL", emailVerified: true, everBeenUnlocked: true, hasPremiumPersonally: false, kdfIterations: 100000, kdfType: 0, keyHash: "KEY_HASH", lastSync: "LAST_SYNC", userId: userId, usesKeyConnector: false, forcePasswordReset: false, }, }; const expectedAccountVersion4: Account = { profile: { ...accountVersion3.profile, }, }; delete expectedAccountVersion4.profile.everBeenUnlocked; storageService.get(userId, Arg.any()).resolves(accountVersion3); await stateMigrationService.migrate(); storageService.received(1).save(userId, expectedAccountVersion4, Arg.any()); }); it("updates StateVersion number", async () => { await stateMigrationService.migrate(); storageService.received(1).save( "global", Arg.is((globals: GlobalState) => globals.stateVersion === StateVersion.Four), Arg.any() ); }); }); });