1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-01-01 18:08:19 +01:00

[PM-15065] Vault Loading on empty tabs (#12059)

* catch errors from `tabSendMessage`

- Removes the need for a timeout when fetching page details

* Add parameter to reject on error

- allows each implementation to decide if they want to handle the error or not
This commit is contained in:
Nick Krantz 2024-11-25 08:37:01 -06:00 committed by GitHub
parent da6a0cb8e9
commit d52da5869b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 57 additions and 17 deletions

View File

@ -143,7 +143,7 @@ describe("AutofillService", () => {
});
describe("collectPageDetailsFromTab$", () => {
const tab = mock<chrome.tabs.Tab>({ id: 1 });
const tab = mock<chrome.tabs.Tab>({ id: 1, url: "https://www.example.com" });
const messages = new Subject<CollectPageDetailsResponseMessage>();
function mockCollectPageDetailsResponseMessage(
@ -165,11 +165,16 @@ describe("AutofillService", () => {
it("sends a `collectPageDetails` message to the passed tab", () => {
autofillService.collectPageDetailsFromTab$(tab);
expect(BrowserApi.tabSendMessage).toHaveBeenCalledWith(tab, {
command: AutofillMessageCommand.collectPageDetails,
sender: AutofillMessageSender.collectPageDetailsFromTabObservable,
expect(BrowserApi.tabSendMessage).toHaveBeenCalledWith(
tab,
});
{
command: AutofillMessageCommand.collectPageDetails,
sender: AutofillMessageSender.collectPageDetailsFromTabObservable,
tab,
},
null,
true,
);
});
it("builds an array of page details from received `collectPageDetailsResponse` messages", async () => {
@ -218,6 +223,24 @@ describe("AutofillService", () => {
expect(tracker.emissions[1]).toBeUndefined();
});
it("returns an empty array when the tab.url is empty", async () => {
const tracker = subscribeTo(autofillService.collectPageDetailsFromTab$({ ...tab, url: "" }));
await tracker.pauseUntilReceived(1);
expect(tracker.emissions[0]).toEqual([]);
});
it("returns an empty array when the `BrowserApi.tabSendMessage` throws an error", async () => {
(BrowserApi.tabSendMessage as jest.Mock).mockRejectedValueOnce(undefined);
const tracker = subscribeTo(autofillService.collectPageDetailsFromTab$(tab));
await tracker.pauseUntilReceived(1);
expect(tracker.emissions[0]).toEqual([]);
});
});
describe("loadAutofillScriptsOnInstall", () => {

View File

@ -1,4 +1,4 @@
import { filter, firstValueFrom, Observable, scan, startWith } from "rxjs";
import { filter, firstValueFrom, merge, Observable, ReplaySubject, scan, startWith } from "rxjs";
import { pairwise } from "rxjs/operators";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
@ -91,6 +91,9 @@ export default class AutofillService implements AutofillServiceInterface {
* @param tab The tab to collect page details from
*/
collectPageDetailsFromTab$(tab: chrome.tabs.Tab): Observable<PageDetail[]> {
/** Replay Subject that can be utilized when `messages$` may not emit the page details. */
const pageDetailsFallback$ = new ReplaySubject<[]>(1);
const pageDetailsFromTab$ = this.messageListener
.messages$(COLLECT_PAGE_DETAILS_RESPONSE_COMMAND)
.pipe(
@ -112,13 +115,28 @@ export default class AutofillService implements AutofillServiceInterface {
),
);
void BrowserApi.tabSendMessage(tab, {
tab: tab,
command: AutofillMessageCommand.collectPageDetails,
sender: AutofillMessageSender.collectPageDetailsFromTabObservable,
void BrowserApi.tabSendMessage(
tab,
{
tab: tab,
command: AutofillMessageCommand.collectPageDetails,
sender: AutofillMessageSender.collectPageDetailsFromTabObservable,
},
null,
true,
).catch(() => {
// When `tabSendMessage` throws an error the `pageDetailsFromTab$` will not emit,
// fallback to an empty array
pageDetailsFallback$.next([]);
});
return pageDetailsFromTab$;
// Empty/New tabs do not have a URL.
// In Safari, `tabSendMessage` doesn't throw an error for this case. Fallback to the empty array to handle.
if (!tab.url) {
pageDetailsFallback$.next([]);
}
return merge(pageDetailsFromTab$, pageDetailsFallback$);
}
/**

View File

@ -200,15 +200,17 @@ export class BrowserApi {
tab: chrome.tabs.Tab,
obj: T,
options: chrome.tabs.MessageSendOptions = null,
rejectOnError = false,
): Promise<TResponse> {
if (!tab || !tab.id) {
return;
}
return new Promise<TResponse>((resolve) => {
return new Promise<TResponse>((resolve, reject) => {
chrome.tabs.sendMessage(tab.id, obj, options, (response) => {
if (chrome.runtime.lastError) {
if (chrome.runtime.lastError && rejectOnError) {
// Some error happened
reject();
}
resolve(response);
});

View File

@ -10,7 +10,6 @@ import {
startWith,
Subject,
switchMap,
timeout,
} from "rxjs";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
@ -75,9 +74,7 @@ export class VaultPopupAutofillService {
if (!tab) {
return of([]);
}
return this.autofillService
.collectPageDetailsFromTab$(tab)
.pipe(timeout({ first: 1500, with: () => of([]) }));
return this.autofillService.collectPageDetailsFromTab$(tab);
}),
shareReplay({ refCount: false, bufferSize: 1 }),
);