1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-11 05:43:41 +00:00
Files
browser/apps/web/src/app/auth/settings/security/device-management.component.spec.ts
Ike 7c9e95271d [PM -20329] browser auth approval client api service (#15161)
* feat: Create methods for calling GET auth-request/pending endpoint.

* feat: update banner service on web, and desktop vault

* test: updated banner test to use auth request services

* fix: DI fixes

* feat: add RequestDeviceId to AuthRequestResponse

* fix: add Browser Approvals feature flags to desktop vault and web vault banner service

* test: fix tests for feature flag
2025-06-26 11:13:06 -04:00

194 lines
5.9 KiB
TypeScript

import { ComponentFixture, TestBed } from "@angular/core/testing";
import { RouterTestingModule } from "@angular/router/testing";
import { of, Subject } from "rxjs";
import { AuthRequestApiServiceAbstraction } from "@bitwarden/auth/common";
import { DevicesServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices/devices.service.abstraction";
import { DeviceView } from "@bitwarden/common/auth/abstractions/devices/views/device.view";
import { DeviceType } from "@bitwarden/common/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
import { MessageListener } from "@bitwarden/common/platform/messaging";
import {
DialogService,
ToastService,
TableModule,
PopoverModule,
LayoutComponent,
} from "@bitwarden/components";
import { SharedModule } from "../../../shared";
import { VaultBannersService } from "../../../vault/individual-vault/vault-banners/services/vault-banners.service";
import { DeviceManagementComponent } from "./device-management.component";
class MockResizeObserver {
observe = jest.fn();
unobserve = jest.fn();
disconnect = jest.fn();
}
global.ResizeObserver = MockResizeObserver;
interface Message {
command: string;
notificationId?: string;
}
describe("DeviceManagementComponent", () => {
let fixture: ComponentFixture<DeviceManagementComponent>;
let messageSubject: Subject<Message>;
let mockDevices: DeviceView[];
let vaultBannersService: VaultBannersService;
const mockDeviceResponse = {
id: "test-id",
requestDeviceType: "test-type",
requestDeviceTypeValue: DeviceType.Android,
requestDeviceIdentifier: "test-identifier",
requestIpAddress: "127.0.0.1",
creationDate: new Date().toISOString(),
responseDate: null,
key: "test-key",
masterPasswordHash: null,
publicKey: "test-public-key",
requestApproved: false,
origin: "test-origin",
};
beforeEach(async () => {
messageSubject = new Subject<Message>();
mockDevices = [];
await TestBed.configureTestingModule({
imports: [
RouterTestingModule,
SharedModule,
TableModule,
PopoverModule,
DeviceManagementComponent,
],
providers: [
{
provide: DevicesServiceAbstraction,
useValue: {
getDevices$: jest.fn().mockReturnValue(mockDevices),
getCurrentDevice$: jest.fn().mockReturnValue(of(null)),
getDeviceByIdentifier$: jest.fn().mockReturnValue(of(null)),
updateTrustedDeviceKeys: jest.fn(),
},
},
{
provide: AuthRequestApiServiceAbstraction,
useValue: {
getAuthRequest: jest.fn().mockResolvedValue(mockDeviceResponse),
},
},
{
provide: MessageListener,
useValue: {
allMessages$: messageSubject.asObservable(),
},
},
{
provide: DialogService,
useValue: {
openSimpleDialog: jest.fn(),
},
},
{
provide: ToastService,
useValue: {
success: jest.fn(),
error: jest.fn(),
},
},
{
provide: VaultBannersService,
useValue: {
shouldShowPendingAuthRequestBanner: jest.fn(),
},
},
{
provide: I18nService,
useValue: {
t: jest.fn((key: string) => key),
},
},
{
provide: ValidationService,
useValue: {
showError: jest.fn(),
},
},
{
provide: LayoutComponent,
useValue: {
mainContent: jest.fn(),
},
},
],
}).compileComponents();
fixture = TestBed.createComponent(DeviceManagementComponent);
vaultBannersService = TestBed.inject(VaultBannersService);
});
describe("message listener", () => {
beforeEach(() => {
jest.spyOn(vaultBannersService, "shouldShowPendingAuthRequestBanner").mockResolvedValue(true);
});
it("ignores other message types", async () => {
const initialDataLength = (fixture.componentInstance as any).dataSource.data.length;
const message: Message = { command: "other", notificationId: "test-id" };
messageSubject.next(message);
await fixture.whenStable();
expect((fixture.componentInstance as any).dataSource.data.length).toBe(initialDataLength);
});
it("adds device to table when auth request message received", async () => {
const initialDataLength = (fixture.componentInstance as any).dataSource.data.length;
const message: Message = {
command: "openLoginApproval",
notificationId: "test-id",
};
messageSubject.next(message);
fixture.detectChanges();
await fixture.whenStable();
const dataSource = (fixture.componentInstance as any).dataSource;
expect(dataSource.data.length).toBe(initialDataLength + 1);
const addedDevice = dataSource.data[0];
expect(addedDevice).toEqual({
id: "",
type: mockDeviceResponse.requestDeviceTypeValue,
displayName: expect.any(String),
loginStatus: "requestPending",
firstLogin: expect.any(Date),
trusted: false,
devicePendingAuthRequest: {
id: mockDeviceResponse.id,
creationDate: mockDeviceResponse.creationDate,
},
hasPendingAuthRequest: true,
identifier: mockDeviceResponse.requestDeviceIdentifier,
});
});
it("stops listening when component is destroyed", async () => {
fixture.destroy();
const message: Message = {
command: "openLoginApproval",
notificationId: "test-id",
};
messageSubject.next(message);
expect((fixture.componentInstance as any).dataSource.data.length).toBe(0);
});
});
});