1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-17 16:53:34 +00:00

Migrate provider service to state provider (#8173)

* Migrate existing provider data to StateProvider

Migrate existing provider data to StateProvider

* Rework the ProviderService to call StateProvider

* Unit test the ProviderService

* Update DI to reflect ProviderService's new args

* Add ProviderService to logout chains across products

* Remove provider related stateService methods

* Update libs/common/src/state-migrations/migrations/28-move-provider-state-to-state-provider.spec.ts

Co-authored-by: Justin Baur <19896123+justindbaur@users.noreply.github.com>

* Cover up a copy/paste job

* Compare equality over entire array in a test

---------

Co-authored-by: Justin Baur <19896123+justindbaur@users.noreply.github.com>
This commit is contained in:
Addison Beck
2024-03-05 13:35:12 -06:00
committed by GitHub
parent 5cd53c3a7d
commit 101e1a4f2b
13 changed files with 378 additions and 65 deletions

View File

@@ -1,7 +1,56 @@
import { FakeAccountService, FakeStateProvider, mockAccountServiceWith } from "../../../spec";
import { FakeActiveUserState } from "../../../spec/fake-state";
import { Utils } from "../../platform/misc/utils";
import { UserId } from "../../types/guid";
import { ProviderUserStatusType, ProviderUserType } from "../enums";
import { ProviderData } from "../models/data/provider.data";
import { Provider } from "../models/domain/provider";
import { PROVIDERS } from "./provider.service";
import { PROVIDERS, ProviderService } from "./provider.service";
/**
* It is easier to read arrays than records in code, but we store a record
* in state. This helper methods lets us build provider arrays in tests
* and easily map them to records before storing them in state.
*/
function arrayToRecord(input: ProviderData[]): Record<string, ProviderData> {
if (input == null) {
return undefined;
}
return Object.fromEntries(input?.map((i) => [i.id, i]));
}
/**
* Builds a simple mock `ProviderData[]` array that can be used in tests
* to populate state.
* @param count The number of organizations to populate the list with. The
* function returns undefined if this is less than 1. The default value is 1.
* @param suffix A string to append to data fields on each provider.
* This defaults to the index of the organization in the list.
* @returns a `ProviderData[]` array that can be used to populate
* stateProvider.
*/
function buildMockProviders(count = 1, suffix?: string): ProviderData[] {
if (count < 1) {
return undefined;
}
function buildMockProvider(id: string, name: string): ProviderData {
const data = new ProviderData({} as any);
data.id = id;
data.name = name;
return data;
}
const mockProviders = [];
for (let i = 0; i < count; i++) {
const s = suffix ? suffix + i.toString() : i.toString();
mockProviders.push(buildMockProvider("provider" + s, "provider" + s));
}
return mockProviders;
}
describe("PROVIDERS key definition", () => {
const sut = PROVIDERS;
@@ -21,3 +70,75 @@ describe("PROVIDERS key definition", () => {
expect(result).toEqual(expectedResult);
});
});
describe("ProviderService", () => {
let providerService: ProviderService;
const fakeUserId = Utils.newGuid() as UserId;
let fakeAccountService: FakeAccountService;
let fakeStateProvider: FakeStateProvider;
let fakeActiveUserState: FakeActiveUserState<Record<string, ProviderData>>;
beforeEach(async () => {
fakeAccountService = mockAccountServiceWith(fakeUserId);
fakeStateProvider = new FakeStateProvider(fakeAccountService);
fakeActiveUserState = fakeStateProvider.activeUser.getFake(PROVIDERS);
providerService = new ProviderService(fakeStateProvider);
});
describe("getAll()", () => {
it("Returns an array of all providers stored in state", async () => {
const mockData: ProviderData[] = buildMockProviders(5);
fakeActiveUserState.nextState(arrayToRecord(mockData));
const providers = await providerService.getAll();
expect(providers).toHaveLength(5);
expect(providers).toEqual(mockData.map((x) => new Provider(x)));
});
it("Returns an empty array if no providers are found in state", async () => {
const mockData: ProviderData[] = undefined;
fakeActiveUserState.nextState(arrayToRecord(mockData));
const result = await providerService.getAll();
expect(result).toEqual([]);
});
});
describe("get()", () => {
it("Returns a single provider from state that matches the specified id", async () => {
const mockData = buildMockProviders(5);
fakeActiveUserState.nextState(arrayToRecord(mockData));
const result = await providerService.get(mockData[3].id);
expect(result).toEqual(new Provider(mockData[3]));
});
it("Returns undefined if the specified provider id is not found", async () => {
const result = await providerService.get("this-provider-does-not-exist");
expect(result).toBe(undefined);
});
});
describe("save()", () => {
it("replaces the entire provider list in state for the active user", async () => {
const originalData = buildMockProviders(10);
fakeActiveUserState.nextState(arrayToRecord(originalData));
const newData = buildMockProviders(10, "newData");
await providerService.save(arrayToRecord(newData));
const result = await providerService.getAll();
expect(result).toEqual(newData);
expect(result).not.toEqual(originalData);
});
// This is more or less a test for logouts
it("can replace state with null", async () => {
const originalData = buildMockProviders(2);
fakeActiveUserState.nextState(arrayToRecord(originalData));
await providerService.save(null);
const result = await providerService.getAll();
expect(result).toEqual([]);
expect(result).not.toEqual(originalData);
});
});
});