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:
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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" },
|
||||
|
||||
Reference in New Issue
Block a user