mirror of
https://github.com/bitwarden/browser
synced 2025-12-23 19:53:43 +00:00
[PM-22693] Firefox - After creating a new item, the View Item screen is blank (#15868)
* Updated get cipher data to retrieve data from observable * Fixed tests
This commit is contained in:
@@ -78,14 +78,14 @@ describe("ViewV2Component", () => {
|
|||||||
const accountService: FakeAccountService = mockAccountServiceWith(mockUserId);
|
const accountService: FakeAccountService = mockAccountServiceWith(mockUserId);
|
||||||
|
|
||||||
const mockCipherService = {
|
const mockCipherService = {
|
||||||
get: jest.fn().mockResolvedValue({ decrypt: jest.fn().mockResolvedValue(mockCipher) }),
|
cipherViews$: jest.fn().mockImplementation((userId) => of([mockCipher])),
|
||||||
getKeyForCipherKeyDecryption: jest.fn().mockResolvedValue({}),
|
getKeyForCipherKeyDecryption: jest.fn().mockResolvedValue({}),
|
||||||
deleteWithServer: jest.fn().mockResolvedValue(undefined),
|
deleteWithServer: jest.fn().mockResolvedValue(undefined),
|
||||||
softDeleteWithServer: jest.fn().mockResolvedValue(undefined),
|
softDeleteWithServer: jest.fn().mockResolvedValue(undefined),
|
||||||
decrypt: jest.fn().mockResolvedValue(mockCipher),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
mockCipherService.cipherViews$.mockClear();
|
||||||
mockCipherService.deleteWithServer.mockClear();
|
mockCipherService.deleteWithServer.mockClear();
|
||||||
mockCipherService.softDeleteWithServer.mockClear();
|
mockCipherService.softDeleteWithServer.mockClear();
|
||||||
mockNavigate.mockClear();
|
mockNavigate.mockClear();
|
||||||
@@ -162,7 +162,7 @@ describe("ViewV2Component", () => {
|
|||||||
|
|
||||||
flush(); // Resolve all promises
|
flush(); // Resolve all promises
|
||||||
|
|
||||||
expect(mockCipherService.get).toHaveBeenCalledWith("122-333-444", mockUserId);
|
expect(mockCipherService.cipherViews$).toHaveBeenCalledWith(mockUserId);
|
||||||
expect(component.cipher).toEqual(mockCipher);
|
expect(component.cipher).toEqual(mockCipher);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ describe("ViewV2Component", () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('invokes `doAutofill` when action="AUTOFILL_ID"', fakeAsync(() => {
|
it('invokes `doAutofill` when action="AUTOFILL_ID"', fakeAsync(() => {
|
||||||
params$.next({ action: AUTOFILL_ID });
|
params$.next({ action: AUTOFILL_ID, cipherId: mockCipher.id });
|
||||||
|
|
||||||
flush(); // Resolve all promises
|
flush(); // Resolve all promises
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ describe("ViewV2Component", () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('invokes `copy` when action="copy-username"', fakeAsync(() => {
|
it('invokes `copy` when action="copy-username"', fakeAsync(() => {
|
||||||
params$.next({ action: COPY_USERNAME_ID });
|
params$.next({ action: COPY_USERNAME_ID, cipherId: mockCipher.id });
|
||||||
|
|
||||||
flush(); // Resolve all promises
|
flush(); // Resolve all promises
|
||||||
|
|
||||||
@@ -226,7 +226,7 @@ describe("ViewV2Component", () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('invokes `copy` when action="copy-password"', fakeAsync(() => {
|
it('invokes `copy` when action="copy-password"', fakeAsync(() => {
|
||||||
params$.next({ action: COPY_PASSWORD_ID });
|
params$.next({ action: COPY_PASSWORD_ID, cipherId: mockCipher.id });
|
||||||
|
|
||||||
flush(); // Resolve all promises
|
flush(); // Resolve all promises
|
||||||
|
|
||||||
@@ -234,7 +234,7 @@ describe("ViewV2Component", () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('invokes `copy` when action="copy-totp"', fakeAsync(() => {
|
it('invokes `copy` when action="copy-totp"', fakeAsync(() => {
|
||||||
params$.next({ action: COPY_VERIFICATION_CODE_ID });
|
params$.next({ action: COPY_VERIFICATION_CODE_ID, cipherId: mockCipher.id });
|
||||||
|
|
||||||
flush(); // Resolve all promises
|
flush(); // Resolve all promises
|
||||||
|
|
||||||
@@ -243,11 +243,13 @@ describe("ViewV2Component", () => {
|
|||||||
|
|
||||||
it("does not set the cipher until reprompt is complete", fakeAsync(() => {
|
it("does not set the cipher until reprompt is complete", fakeAsync(() => {
|
||||||
let promptPromise: (val?: unknown) => void;
|
let promptPromise: (val?: unknown) => void;
|
||||||
mockCipherService.decrypt.mockImplementationOnce(() =>
|
mockCipherService.cipherViews$.mockImplementationOnce((userId) =>
|
||||||
Promise.resolve({
|
of([
|
||||||
|
{
|
||||||
...mockCipher,
|
...mockCipher,
|
||||||
reprompt: CipherRepromptType.Password,
|
reprompt: CipherRepromptType.Password,
|
||||||
}),
|
},
|
||||||
|
]),
|
||||||
);
|
);
|
||||||
doAutofill.mockImplementationOnce(() => {
|
doAutofill.mockImplementationOnce(() => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
@@ -256,7 +258,7 @@ describe("ViewV2Component", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
params$.next({ action: AUTOFILL_ID });
|
params$.next({ action: AUTOFILL_ID, cipherId: mockCipher.id });
|
||||||
|
|
||||||
flush(); // Flush all pending actions
|
flush(); // Flush all pending actions
|
||||||
|
|
||||||
@@ -271,11 +273,13 @@ describe("ViewV2Component", () => {
|
|||||||
|
|
||||||
it("does not set the cipher at all if doAutofill fails and reprompt is active", fakeAsync(() => {
|
it("does not set the cipher at all if doAutofill fails and reprompt is active", fakeAsync(() => {
|
||||||
let promptPromise: (val?: unknown) => void;
|
let promptPromise: (val?: unknown) => void;
|
||||||
mockCipherService.decrypt.mockImplementationOnce(() =>
|
mockCipherService.cipherViews$.mockImplementationOnce((userId) =>
|
||||||
Promise.resolve({
|
of([
|
||||||
|
{
|
||||||
...mockCipher,
|
...mockCipher,
|
||||||
reprompt: CipherRepromptType.Password,
|
reprompt: CipherRepromptType.Password,
|
||||||
}),
|
},
|
||||||
|
]),
|
||||||
);
|
);
|
||||||
doAutofill.mockImplementationOnce(() => {
|
doAutofill.mockImplementationOnce(() => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
@@ -284,7 +288,7 @@ describe("ViewV2Component", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
params$.next({ action: AUTOFILL_ID });
|
params$.next({ action: AUTOFILL_ID, cipherId: mockCipher.id });
|
||||||
|
|
||||||
flush(); // Flush all pending actions
|
flush(); // Flush all pending actions
|
||||||
|
|
||||||
@@ -301,11 +305,13 @@ describe("ViewV2Component", () => {
|
|||||||
"does not set cipher when copy fails for %s",
|
"does not set cipher when copy fails for %s",
|
||||||
fakeAsync((action: string) => {
|
fakeAsync((action: string) => {
|
||||||
let promptPromise: (val?: unknown) => void;
|
let promptPromise: (val?: unknown) => void;
|
||||||
mockCipherService.decrypt.mockImplementationOnce(() =>
|
mockCipherService.cipherViews$.mockImplementationOnce((userId) =>
|
||||||
Promise.resolve({
|
of([
|
||||||
|
{
|
||||||
...mockCipher,
|
...mockCipher,
|
||||||
reprompt: CipherRepromptType.Password,
|
reprompt: CipherRepromptType.Password,
|
||||||
}),
|
},
|
||||||
|
]),
|
||||||
);
|
);
|
||||||
copy.mockImplementationOnce(() => {
|
copy.mockImplementationOnce(() => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
@@ -314,7 +320,7 @@ describe("ViewV2Component", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
params$.next({ action });
|
params$.next({ action, cipherId: mockCipher.id });
|
||||||
|
|
||||||
flush(); // Flush all pending actions
|
flush(); // Flush all pending actions
|
||||||
|
|
||||||
@@ -336,7 +342,7 @@ describe("ViewV2Component", () => {
|
|||||||
.spyOn(BrowserApi, "focusTab")
|
.spyOn(BrowserApi, "focusTab")
|
||||||
.mockImplementation(() => Promise.resolve());
|
.mockImplementation(() => Promise.resolve());
|
||||||
|
|
||||||
params$.next({ action: AUTOFILL_ID, senderTabId: 99 });
|
params$.next({ action: AUTOFILL_ID, senderTabId: 99, cipherId: mockCipher.id });
|
||||||
|
|
||||||
flush(); // Resolve all promises
|
flush(); // Resolve all promises
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Component } from "@angular/core";
|
|||||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
import { FormsModule } from "@angular/forms";
|
import { FormsModule } from "@angular/forms";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
import { firstValueFrom, Observable, switchMap, of } from "rxjs";
|
import { firstValueFrom, Observable, switchMap, of, map } from "rxjs";
|
||||||
|
|
||||||
import { CollectionView } from "@bitwarden/admin-console/common";
|
import { CollectionView } from "@bitwarden/admin-console/common";
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
@@ -209,8 +209,12 @@ export class ViewV2Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getCipherData(id: string, userId: UserId) {
|
async getCipherData(id: string, userId: UserId) {
|
||||||
const cipher = await this.cipherService.get(id, userId);
|
return await firstValueFrom(
|
||||||
return await this.cipherService.decrypt(cipher, userId);
|
this.cipherService.cipherViews$(userId).pipe(
|
||||||
|
filterOutNullish(),
|
||||||
|
map((ciphers) => ciphers.find((c) => c.id === id)),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async editCipher() {
|
async editCipher() {
|
||||||
|
|||||||
Reference in New Issue
Block a user