1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-16 16:59:30 +00:00

[PM-30264] - fix exact match dialog show logic (#18216)

* fix exact match dialog show logic

* fix logic for uri matching

* simplify exact match dialog show logic
This commit is contained in:
Jordan Aasen
2026-01-09 10:31:08 -08:00
committed by GitHub
parent 392794b560
commit 1b76ce5b7c
2 changed files with 111 additions and 87 deletions

View File

@@ -158,14 +158,6 @@ describe("ItemMoreOptionsComponent", () => {
expect(autofillSvc.doAutofillAndSave).not.toHaveBeenCalled();
});
it("does not show the exact match dialog when the default match strategy is Exact and autofill confirmation is not to be shown", async () => {
uriMatchStrategy$.next(UriMatchStrategy.Exact);
autofillSvc.currentAutofillTab$.next({ url: "https://page.example.com/path" });
await component.doAutofill();
expect(dialogService.openSimpleDialog).not.toHaveBeenCalled();
});
describe("autofill confirmation dialog", () => {
beforeEach(() => {
uriMatchStrategy$.next(UriMatchStrategy.Domain);
@@ -236,22 +228,30 @@ describe("ItemMoreOptionsComponent", () => {
});
describe("URI match strategy handling", () => {
it("calls the passwordService to passwordRepromptCheck", async () => {
autofillSvc.currentAutofillTab$.next({ url: "https://page.example.com" });
mockConfirmDialogResult(AutofillConfirmationDialogResult.AutofilledOnly);
await component.doAutofill();
expect(passwordRepromptService.passwordRepromptCheck).toHaveBeenCalledWith(baseCipher);
});
describe("when the default URI match strategy is Exact", () => {
beforeEach(() => {
uriMatchStrategy$.next(UriMatchStrategy.Exact);
});
it("calls the passwordService to passwordRepromptCheck", async () => {
autofillSvc.currentAutofillTab$.next({ url: "https://page.example.com" });
mockConfirmDialogResult(AutofillConfirmationDialogResult.AutofilledOnly);
await component.doAutofill();
expect(passwordRepromptService.passwordRepromptCheck).toHaveBeenCalledWith(baseCipher);
});
it("shows the exact match dialog", async () => {
it("shows the exact match dialog when the cipher has no saved URIs", async () => {
autofillSvc.currentAutofillTab$.next({ url: "https://no-match.example.com" });
cipherService.getFullCipherView.mockImplementation(async (c) => ({
...baseCipher,
...c,
login: {
...baseCipher.login,
uris: [],
},
}));
await component.doAutofill();
@@ -266,6 +266,53 @@ describe("ItemMoreOptionsComponent", () => {
expect(autofillSvc.doAutofill).not.toHaveBeenCalled();
expect(autofillSvc.doAutofillAndSave).not.toHaveBeenCalled();
});
it("does not show the exact match dialog when the cipher has at least one non-exact match uri", async () => {
mockConfirmDialogResult(AutofillConfirmationDialogResult.AutofilledOnly);
cipherService.getFullCipherView.mockImplementation(async (c) => ({
...baseCipher,
...c,
login: {
...baseCipher.login,
uris: [
{ uri: "https://one.example.com", match: UriMatchStrategy.Exact },
{ uri: "https://two.example.com", match: UriMatchStrategy.Domain },
],
},
}));
autofillSvc.currentAutofillTab$.next({ url: "https://page.example.com/path" });
await component.doAutofill();
expect(dialogService.openSimpleDialog).not.toHaveBeenCalled();
});
it("shows the exact match dialog when the cipher uris all have a match strategy of Exact", async () => {
cipherService.getFullCipherView.mockImplementation(async (c) => ({
...baseCipher,
...c,
login: {
...baseCipher.login,
uris: [
{ uri: "https://one.example.com", match: UriMatchStrategy.Exact },
{ uri: "https://two.example.com/a", match: UriMatchStrategy.Exact },
],
},
}));
autofillSvc.currentAutofillTab$.next({ url: "https://page.example.com/path" });
await component.doAutofill();
expect(dialogService.openSimpleDialog).toHaveBeenCalledWith(
expect.objectContaining({
title: expect.objectContaining({ key: "cannotAutofill" }),
content: expect.objectContaining({ key: "cannotAutofillExactMatch" }),
type: "info",
}),
);
expect(autofillSvc.doAutofill).not.toHaveBeenCalled();
expect(autofillSvc.doAutofillAndSave).not.toHaveBeenCalled();
});
});
describe("when the default URI match strategy is not Exact", () => {
@@ -273,7 +320,45 @@ describe("ItemMoreOptionsComponent", () => {
mockConfirmDialogResult(AutofillConfirmationDialogResult.Canceled);
uriMatchStrategy$.next(UriMatchStrategy.Domain);
});
it("does not show the exact match dialog", async () => {
it("does not show the exact match dialog when the cipher has no saved URIs", async () => {
autofillSvc.currentAutofillTab$.next({ url: "https://page.example.com" });
await component.doAutofill();
expect(dialogService.openSimpleDialog).not.toHaveBeenCalled();
});
it("shows the exact match dialog when the cipher has only exact match saved URIs", async () => {
cipherService.getFullCipherView.mockImplementation(async (c) => ({
...baseCipher,
...c,
login: {
...baseCipher.login,
uris: [
{ uri: "https://one.example.com", match: UriMatchStrategy.Exact },
{ uri: "https://two.example.com/a", match: UriMatchStrategy.Exact },
],
},
}));
autofillSvc.currentAutofillTab$.next({ url: "https://no-match.example.com" });
await component.doAutofill();
expect(dialogService.openSimpleDialog).toHaveBeenCalledWith(
expect.objectContaining({
title: expect.objectContaining({ key: "cannotAutofill" }),
content: expect.objectContaining({ key: "cannotAutofillExactMatch" }),
type: "info",
}),
);
expect(autofillSvc.doAutofill).not.toHaveBeenCalled();
expect(autofillSvc.doAutofillAndSave).not.toHaveBeenCalled();
});
it("does not show the exact match dialog when the cipher has at least one uri without a match strategy of Exact", async () => {
mockConfirmDialogResult(AutofillConfirmationDialogResult.Canceled);
cipherService.getFullCipherView.mockImplementation(async (c) => ({
...baseCipher,
...c,
@@ -292,70 +377,6 @@ describe("ItemMoreOptionsComponent", () => {
expect(dialogService.openSimpleDialog).not.toHaveBeenCalled();
});
it("shows the exact match dialog when the cipher has a single uri with a match strategy of Exact", async () => {
cipherService.getFullCipherView.mockImplementation(async (c) => ({
...baseCipher,
...c,
login: {
...baseCipher.login,
uris: [{ uri: "https://one.example.com", match: UriMatchStrategy.Exact }],
},
}));
autofillSvc.currentAutofillTab$.next({ url: "https://no-match.example.com" });
await component.doAutofill();
expect(dialogService.openSimpleDialog).toHaveBeenCalledWith(
expect.objectContaining({
title: expect.objectContaining({ key: "cannotAutofill" }),
content: expect.objectContaining({ key: "cannotAutofillExactMatch" }),
type: "info",
}),
);
expect(autofillSvc.doAutofill).not.toHaveBeenCalled();
expect(autofillSvc.doAutofillAndSave).not.toHaveBeenCalled();
});
});
it("does not show the exact match dialog when the cipher has no uris", async () => {
mockConfirmDialogResult(AutofillConfirmationDialogResult.Canceled);
cipherService.getFullCipherView.mockImplementation(async (c) => ({
...baseCipher,
...c,
login: {
...baseCipher.login,
uris: [],
},
}));
autofillSvc.currentAutofillTab$.next({ url: "https://no-match.example.com" });
await component.doAutofill();
expect(dialogService.openSimpleDialog).not.toHaveBeenCalled();
});
it("does not show the exact match dialog when the cipher has a uri with a match strategy of Exact and a uri with a match strategy of Domain", async () => {
mockConfirmDialogResult(AutofillConfirmationDialogResult.Canceled);
cipherService.getFullCipherView.mockImplementation(async (c) => ({
...baseCipher,
...c,
login: {
...baseCipher.login,
uris: [
{ uri: "https://one.example.com", match: UriMatchStrategy.Exact },
{ uri: "https://page.example.com", match: UriMatchStrategy.Domain },
],
},
}));
autofillSvc.currentAutofillTab$.next({ url: "https://page.example.com" });
await component.doAutofill();
expect(dialogService.openSimpleDialog).not.toHaveBeenCalled();
});
});

View File

@@ -204,12 +204,15 @@ export class ItemMoreOptionsComponent {
}
const uris = cipher.login?.uris ?? [];
const cipherHasAllExactMatchLoginUris =
uris.length > 0 && uris.every((u) => u.uri && u.match === UriMatchStrategy.Exact);
const uriMatchStrategy = await firstValueFrom(this.uriMatchStrategy$);
if (cipherHasAllExactMatchLoginUris || uriMatchStrategy === UriMatchStrategy.Exact) {
const showExactMatchDialog =
uris.length === 0
? uriMatchStrategy === UriMatchStrategy.Exact
: // all saved URIs are exact match
uris.every((u) => (u.match ?? uriMatchStrategy) === UriMatchStrategy.Exact);
if (showExactMatchDialog) {
await this.dialogService.openSimpleDialog({
title: { key: "cannotAutofill" },
content: { key: "cannotAutofillExactMatch" },