diff --git a/libs/vault/src/cipher-view/login-credentials/login-credentials-view.component.html b/libs/vault/src/cipher-view/login-credentials/login-credentials-view.component.html
index 5b6b995d095..8503604bf7c 100644
--- a/libs/vault/src/cipher-view/login-credentials/login-credentials-view.component.html
+++ b/libs/vault/src/cipher-view/login-credentials/login-credentials-view.component.html
@@ -28,17 +28,34 @@
{{ "loginCredentials" | i18n }}
>
- {{ "password" | i18n }}
+
+ {{ "password" | i18n }}
+
+
+
+
+
{
+ let component: LoginCredentialsViewComponent;
+ let fixture: ComponentFixture;
+
+ const hasPremiumFromAnySource$ = new BehaviorSubject(true);
+
+ const cipher = {
+ id: "cipher-id",
+ name: "Mock Cipher",
+ type: CipherType.Login,
+ login: new LoginView(),
+ } as CipherView;
+
+ cipher.login.password = "cipher-password";
+ cipher.login.username = "cipher-username";
+ const date = new Date("2024-02-02");
+ cipher.login.fido2Credentials = [{ creationDate: date } as Fido2CredentialView];
+
+ const collect = jest.fn();
+
+ beforeEach(async () => {
+ collect.mockClear();
+
+ await TestBed.configureTestingModule({
+ providers: [
+ {
+ provide: BillingAccountProfileStateService,
+ useValue: mock({ hasPremiumFromAnySource$ }),
+ },
+ { provide: PremiumUpgradePromptService, useValue: mock() },
+ { provide: EventCollectionService, useValue: mock({ collect }) },
+ { provide: PlatformUtilsService, useValue: mock() },
+ { provide: ToastService, useValue: mock() },
+ { provide: I18nService, useValue: { t: (...keys: string[]) => keys.join(" ") } },
+ ],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(LoginCredentialsViewComponent);
+ component = fixture.componentInstance;
+ component.cipher = cipher;
+ fixture.detectChanges();
+ });
+
+ describe("username", () => {
+ let usernameField: DebugElement;
+
+ beforeEach(() => {
+ usernameField = fixture.debugElement.queryAll(By.directive(BitFormFieldComponent))[0];
+ });
+
+ it("displays the username", () => {
+ const usernameInput = usernameField.query(By.css("input")).nativeElement;
+
+ expect(usernameInput.value).toBe(cipher.login.username);
+ });
+
+ it("configures CopyClickDirective for the username", () => {
+ const usernameCopyButton = usernameField.query(By.directive(CopyClickDirective));
+ const usernameCopyClickDirective = usernameCopyButton.injector.get(CopyClickDirective);
+
+ expect(usernameCopyClickDirective.valueToCopy).toBe(cipher.login.username);
+ });
+ });
+
+ describe("password", () => {
+ let passwordField: DebugElement;
+
+ beforeEach(() => {
+ passwordField = fixture.debugElement.queryAll(By.directive(BitFormFieldComponent))[1];
+ });
+
+ it("displays the password", () => {
+ const passwordInput = passwordField.query(By.css("input")).nativeElement;
+
+ expect(passwordInput.value).toBe(cipher.login.password);
+ });
+
+ describe("copy", () => {
+ it("does not allow copy when `viewPassword` is false", () => {
+ cipher.viewPassword = false;
+ fixture.detectChanges();
+
+ const passwordCopyButton = passwordField.query(By.directive(CopyClickDirective));
+
+ expect(passwordCopyButton).toBeNull();
+ });
+
+ it("configures CopyClickDirective for the password", () => {
+ cipher.viewPassword = true;
+ fixture.detectChanges();
+
+ const passwordCopyButton = passwordField.query(By.directive(CopyClickDirective));
+ const passwordCopyClickDirective = passwordCopyButton.injector.get(CopyClickDirective);
+
+ expect(passwordCopyClickDirective.valueToCopy).toBe(cipher.login.password);
+ });
+ });
+
+ describe("toggle password", () => {
+ it("does not allow password to be viewed when `viewPassword` is false", () => {
+ cipher.viewPassword = false;
+ fixture.detectChanges();
+
+ const viewPasswordButton = passwordField.query(
+ By.directive(BitPasswordInputToggleDirective),
+ );
+
+ expect(viewPasswordButton).toBeNull();
+ });
+
+ it("shows password color component", () => {
+ cipher.viewPassword = true;
+ fixture.detectChanges();
+
+ const viewPasswordButton = passwordField.query(
+ By.directive(BitPasswordInputToggleDirective),
+ );
+ const toggleInputDirective = viewPasswordButton.injector.get(
+ BitPasswordInputToggleDirective,
+ );
+
+ toggleInputDirective.onClick();
+ fixture.detectChanges();
+
+ const passwordColor = passwordField.query(By.directive(ColorPasswordComponent));
+
+ expect(passwordColor.componentInstance.password).toBe(cipher.login.password);
+ });
+
+ it("records event", () => {
+ cipher.viewPassword = true;
+ fixture.detectChanges();
+
+ const viewPasswordButton = passwordField.query(
+ By.directive(BitPasswordInputToggleDirective),
+ );
+ const toggleInputDirective = viewPasswordButton.injector.get(
+ BitPasswordInputToggleDirective,
+ );
+
+ toggleInputDirective.onClick();
+ fixture.detectChanges();
+
+ expect(collect).toHaveBeenCalledWith(
+ EventType.Cipher_ClientToggledPasswordVisible,
+ cipher.id,
+ false,
+ cipher.organizationId,
+ );
+ });
+ });
+ });
+
+ describe("fido2Credentials", () => {
+ let fido2Field: DebugElement;
+
+ beforeEach(() => {
+ fido2Field = fixture.debugElement.queryAll(By.directive(BitFormFieldComponent))[2];
+
+ // Mock datePipe to avoid timezone related issues within tests
+ jest.spyOn(component["datePipe"], "transform").mockReturnValue("2/2/24 6:00PM");
+ fixture.detectChanges();
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ it("displays the creation date", () => {
+ const fido2Input = fido2Field.query(By.css("input")).nativeElement;
+
+ expect(fido2Input.value).toBe("dateCreated 2/2/24 6:00PM");
+ });
+ });
+});