mirror of
https://github.com/bitwarden/browser
synced 2025-12-13 23:03:32 +00:00
[PM-10700] Navigate to View after cipher creation (#10484)
* refactor params subscription variable names * refactor param subscription to return a tuple - this is going to be helpful when multiple params are involved * navigate the user back to the vault when a new cipher is created * add unit tests for view-v2 component * prefer replaceUrl to avoid having to pass a query param * Fix grammar of mocking comment
This commit is contained in:
@@ -228,7 +228,10 @@ export class AddEditV2Component implements OnInit {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.location.back();
|
await this.router.navigate(["/view-cipher"], {
|
||||||
|
replaceUrl: true,
|
||||||
|
queryParams: { cipherId: cipher.id },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribeToParams(): void {
|
subscribeToParams(): void {
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
import { ComponentFixture, fakeAsync, flush, TestBed } from "@angular/core/testing";
|
||||||
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
import { mock } from "jest-mock-extended";
|
||||||
|
import { Subject } from "rxjs";
|
||||||
|
|
||||||
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
|
|
||||||
|
import { ViewV2Component } from "./view-v2.component";
|
||||||
|
|
||||||
|
// 'qrcode-parser' is used by `BrowserTotpCaptureService` but is an es6 module that jest can't compile.
|
||||||
|
// Mock the entire module here to prevent jest from throwing an error. I wasn't able to find a way to mock the
|
||||||
|
// `BrowserTotpCaptureService` where jest would not load the file in the first place.
|
||||||
|
jest.mock("qrcode-parser", () => {});
|
||||||
|
|
||||||
|
describe("ViewV2Component", () => {
|
||||||
|
let component: ViewV2Component;
|
||||||
|
let fixture: ComponentFixture<ViewV2Component>;
|
||||||
|
const params$ = new Subject();
|
||||||
|
const mockNavigate = jest.fn();
|
||||||
|
|
||||||
|
const mockCipher = {
|
||||||
|
id: "122-333-444",
|
||||||
|
type: CipherType.Login,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockCipherService = {
|
||||||
|
get: jest.fn().mockResolvedValue({ decrypt: jest.fn().mockResolvedValue(mockCipher) }),
|
||||||
|
getKeyForCipherKeyDecryption: jest.fn().mockResolvedValue({}),
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
mockNavigate.mockClear();
|
||||||
|
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [ViewV2Component],
|
||||||
|
providers: [
|
||||||
|
{ provide: Router, useValue: { navigate: mockNavigate } },
|
||||||
|
{ provide: CipherService, useValue: mockCipherService },
|
||||||
|
{ provide: LogService, useValue: mock<LogService>() },
|
||||||
|
{ provide: PlatformUtilsService, useValue: mock<PlatformUtilsService>() },
|
||||||
|
{ provide: ConfigService, useValue: mock<ConfigService>() },
|
||||||
|
{ provide: ActivatedRoute, useValue: { queryParams: params$ } },
|
||||||
|
{
|
||||||
|
provide: I18nService,
|
||||||
|
useValue: {
|
||||||
|
t: (key: string, ...rest: string[]) => {
|
||||||
|
if (rest?.length) {
|
||||||
|
return `${key} ${rest.join(" ")}`;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ViewV2Component);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("queryParams", () => {
|
||||||
|
it("loads an existing cipher", fakeAsync(() => {
|
||||||
|
params$.next({ cipherId: "122-333-444" });
|
||||||
|
|
||||||
|
flush(); // Resolve all promises
|
||||||
|
|
||||||
|
expect(mockCipherService.get).toHaveBeenCalledWith("122-333-444");
|
||||||
|
expect(component.cipher).toEqual(mockCipher);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("sets the correct header text", fakeAsync(() => {
|
||||||
|
// Set header text for a login
|
||||||
|
mockCipher.type = CipherType.Login;
|
||||||
|
params$.next({ cipherId: mockCipher.id });
|
||||||
|
flush(); // Resolve all promises
|
||||||
|
|
||||||
|
expect(component.headerText).toEqual("viewItemHeader typelogin");
|
||||||
|
|
||||||
|
// Set header text for a card
|
||||||
|
mockCipher.type = CipherType.Card;
|
||||||
|
params$.next({ cipherId: mockCipher.id });
|
||||||
|
flush(); // Resolve all promises
|
||||||
|
|
||||||
|
expect(component.headerText).toEqual("viewItemHeader typecard");
|
||||||
|
|
||||||
|
// Set header text for an identity
|
||||||
|
mockCipher.type = CipherType.Identity;
|
||||||
|
params$.next({ cipherId: mockCipher.id });
|
||||||
|
flush(); // Resolve all promises
|
||||||
|
|
||||||
|
expect(component.headerText).toEqual("viewItemHeader typeidentity");
|
||||||
|
|
||||||
|
// Set header text for a secure note
|
||||||
|
mockCipher.type = CipherType.SecureNote;
|
||||||
|
params$.next({ cipherId: mockCipher.id });
|
||||||
|
flush(); // Resolve all promises
|
||||||
|
|
||||||
|
expect(component.headerText).toEqual("viewItemHeader note");
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -54,7 +54,6 @@ import { PopupPageComponent } from "./../../../../../platform/popup/layout/popup
|
|||||||
})
|
})
|
||||||
export class ViewV2Component {
|
export class ViewV2Component {
|
||||||
headerText: string;
|
headerText: string;
|
||||||
cipherId: string;
|
|
||||||
cipher: CipherView;
|
cipher: CipherView;
|
||||||
organization$: Observable<Organization>;
|
organization$: Observable<Organization>;
|
||||||
folder$: Observable<FolderView>;
|
folder$: Observable<FolderView>;
|
||||||
@@ -75,14 +74,14 @@ export class ViewV2Component {
|
|||||||
subscribeToParams(): void {
|
subscribeToParams(): void {
|
||||||
this.route.queryParams
|
this.route.queryParams
|
||||||
.pipe(
|
.pipe(
|
||||||
switchMap((param) => {
|
switchMap(async (params): Promise<CipherView> => {
|
||||||
return this.getCipherData(param.cipherId);
|
return await this.getCipherData(params.cipherId);
|
||||||
}),
|
}),
|
||||||
takeUntilDestroyed(),
|
takeUntilDestroyed(),
|
||||||
)
|
)
|
||||||
.subscribe((data) => {
|
.subscribe((cipher) => {
|
||||||
this.cipher = data;
|
this.cipher = cipher;
|
||||||
this.headerText = this.setHeader(data.type);
|
this.headerText = this.setHeader(cipher.type);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user