summaryrefslogtreecommitdiffstats
path: root/toolkit/components/credentialmanagement/tests/browser
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/credentialmanagement/tests/browser')
-rw-r--r--toolkit/components/credentialmanagement/tests/browser/browser.toml18
-rw-r--r--toolkit/components/credentialmanagement/tests/browser/browser_account_dialog.js462
-rw-r--r--toolkit/components/credentialmanagement/tests/browser/browser_policy_dialog.js204
-rw-r--r--toolkit/components/credentialmanagement/tests/browser/browser_provider_dialog.js396
-rw-r--r--toolkit/components/credentialmanagement/tests/browser/custom.svg8
-rw-r--r--toolkit/components/credentialmanagement/tests/browser/head.js2
6 files changed, 1090 insertions, 0 deletions
diff --git a/toolkit/components/credentialmanagement/tests/browser/browser.toml b/toolkit/components/credentialmanagement/tests/browser/browser.toml
new file mode 100644
index 0000000000..a7202c9190
--- /dev/null
+++ b/toolkit/components/credentialmanagement/tests/browser/browser.toml
@@ -0,0 +1,18 @@
+[DEFAULT]
+head = "head.js"
+prefs = [
+ "dom.security.credentialmanagement.identity.enabled=true",
+ "dom.security.credentialmanagement.identity.ignore_well_known=true",
+ "privacy.antitracking.enableWebcompat=false",
+] # disables opener heuristic
+scheme = "https"
+
+support-files = ["custom.svg"]
+
+["browser_account_dialog.js"]
+fail-if = ["a11y_checks"] # Bug 1854509 clicked identity-credential-list-item may not be focusable
+
+["browser_policy_dialog.js"]
+
+["browser_provider_dialog.js"]
+fail-if = ["a11y_checks"] # Bug 1854509 clicked identity-credential-list-item may not be focusable
diff --git a/toolkit/components/credentialmanagement/tests/browser/browser_account_dialog.js b/toolkit/components/credentialmanagement/tests/browser/browser_account_dialog.js
new file mode 100644
index 0000000000..f6e74d2bad
--- /dev/null
+++ b/toolkit/components/credentialmanagement/tests/browser/browser_account_dialog.js
@@ -0,0 +1,462 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+XPCOMUtils.defineLazyServiceGetter(
+ this,
+ "IdentityCredentialPromptService",
+ "@mozilla.org/browser/identitycredentialpromptservice;1",
+ "nsIIdentityCredentialPromptService"
+);
+
+const TEST_URL = "https://example.com/";
+
+// Test that a single account shows up in a dialog and is chosen when "continue" is clicked
+add_task(async function test_single_acccount_dialog() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ let popupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ // Show the single account
+ let prompt = IdentityCredentialPromptService.showAccountListPrompt(
+ tab.linkedBrowser.browsingContext,
+ {
+ accounts: [
+ {
+ id: "00000000-0000-0000-0000-000000000000",
+ name: "Test Account",
+ email: "test@idp.example",
+ },
+ ],
+ },
+ {
+ configURL: "https://idp.example/",
+ clientId: "123",
+ },
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ }
+ );
+
+ // Wait for the popup to appear
+ await popupShown;
+
+ let popupHiding = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popuphiding"
+ );
+
+ let document = tab.linkedBrowser.browsingContext.topChromeWindow.document;
+
+ // Validate the popup contents
+ let inputs = document
+ .getElementById("identity-credential-account")
+ .getElementsByClassName("identity-credential-list-item");
+ is(inputs.length, 1, "One account expected");
+ let label = inputs[0].getElementsByClassName(
+ "identity-credential-list-item-label-stack"
+ )[0];
+ ok(
+ label.textContent.includes("Test Account"),
+ "Label includes the account name"
+ );
+ ok(
+ label.textContent.includes("test@idp.example"),
+ "Label includes the account email"
+ );
+
+ let title = document.getElementById("identity-credential-header-text");
+ ok(
+ title.textContent.includes("idp.example"),
+ "Popup title includes the IDP Site"
+ );
+
+ // Click Continue
+ document
+ .getElementsByClassName("popup-notification-primary-button")[0]
+ .click();
+
+ // Make sure that the prompt resolves with the index of the only argument element
+ let value = await prompt;
+ is(value, 0);
+
+ await popupHiding;
+
+ // Close tabs.
+ await BrowserTestUtils.removeTab(tab);
+});
+
+// Test that no account is chosen when "cancel" is clicked
+add_task(async function test_single_acccount_deny() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ let popupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ // Show a prompt with one account
+ let prompt = IdentityCredentialPromptService.showAccountListPrompt(
+ tab.linkedBrowser.browsingContext,
+ {
+ accounts: [
+ {
+ id: "00000000-0000-0000-0000-000000000000",
+ name: "Test Account",
+ email: "test@idp.example",
+ },
+ ],
+ },
+ {
+ configURL: "https://idp.example/",
+ clientId: "123",
+ },
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ }
+ );
+
+ // Wait for that popup
+ await popupShown;
+
+ let popupHiding = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popuphiding"
+ );
+
+ let document = tab.linkedBrowser.browsingContext.topChromeWindow.document;
+
+ // Validate the popup contents
+ let inputs = document
+ .getElementById("identity-credential-account")
+ .getElementsByClassName("identity-credential-list-item");
+ is(inputs.length, 1, "One account expected");
+ let label = inputs[0].getElementsByClassName(
+ "identity-credential-list-item-label-stack"
+ )[0];
+ ok(
+ label.textContent.includes("Test Account"),
+ "Label includes the account name"
+ );
+ ok(
+ label.textContent.includes("test@idp.example"),
+ "Label includes the account email"
+ );
+
+ // Click cancel
+ document
+ .getElementsByClassName("popup-notification-secondary-button")[0]
+ .click();
+
+ // Make sure we reject
+ try {
+ await prompt;
+ ok(false, "Prompt should not resolve when denied.");
+ } catch (e) {
+ ok(true, "Prompt should reject when denied.");
+ }
+
+ await popupHiding;
+
+ // Close tabs.
+ await BrowserTestUtils.removeTab(tab);
+});
+
+// Show multiple accounts and select the first one
+add_task(async function test_multiple_acccount_dialog() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ let popupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ // Show a prompt with multiple accounts
+ let prompt = IdentityCredentialPromptService.showAccountListPrompt(
+ tab.linkedBrowser.browsingContext,
+ {
+ accounts: [
+ {
+ id: "00000000-0000-0000-0000-000000000000",
+ name: "Test Account",
+ email: "test@idp.example",
+ },
+ {
+ id: "00000000-0000-0000-0000-000000000000",
+ name: "Test Account 2",
+ email: "test2@idp.example",
+ },
+ ],
+ },
+ {
+ configURL: "https://idp.example/",
+ clientId: "123",
+ },
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ }
+ );
+
+ // Wait for that popup to appear
+ await popupShown;
+
+ let popupHiding = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popuphiding"
+ );
+
+ let document = tab.linkedBrowser.browsingContext.topChromeWindow.document;
+
+ // Validate the account list contents and ordering
+ let inputs = document
+ .getElementById("identity-credential-account")
+ .getElementsByClassName("identity-credential-list-item");
+ is(inputs.length, 2, "Two accounts expected");
+ let label0 = inputs[0].getElementsByClassName(
+ "identity-credential-list-item-label-stack"
+ )[0];
+ ok(
+ label0.textContent.includes("Test Account"),
+ "The first account name should be in the label"
+ );
+ ok(
+ label0.textContent.includes("test@idp.example"),
+ "The first account email should be in the label"
+ );
+ let label1 = inputs[1].getElementsByClassName(
+ "identity-credential-list-item-label-stack"
+ )[0];
+ ok(
+ label1.textContent.includes("Test Account 2"),
+ "The second account name should be in the label"
+ );
+ ok(
+ label1.textContent.includes("test2@idp.example"),
+ "The second account email should be in the label"
+ );
+
+ // Click continue
+ document
+ .getElementsByClassName("popup-notification-primary-button")[0]
+ .click();
+
+ // Validate that the caller gets a resolving promise with index of the first element
+ let value = await prompt;
+ is(value, 0, "The first account is chosen by default");
+
+ await popupHiding;
+
+ // Close tabs.
+ await BrowserTestUtils.removeTab(tab);
+});
+
+// Show multiple accounts and select the second one
+add_task(async function test_multiple_acccount_choose_second() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ let popupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ // Show a prompt with multiple accounts
+ let prompt = IdentityCredentialPromptService.showAccountListPrompt(
+ tab.linkedBrowser.browsingContext,
+ {
+ accounts: [
+ {
+ id: "00000000-0000-0000-0000-000000000000",
+ name: "Test Account",
+ email: "test@idp.example",
+ },
+ {
+ id: "00000000-0000-0000-0000-000000000000",
+ name: "Test Account 2",
+ email: "test2@idp.example",
+ },
+ ],
+ },
+ {
+ configURL: "https://idp.example/",
+ clientId: "123",
+ },
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ }
+ );
+
+ // Wait for that popup
+ await popupShown;
+
+ let popupHiding = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popuphiding"
+ );
+
+ let document = tab.linkedBrowser.browsingContext.topChromeWindow.document;
+
+ // Validate the account list contents and ordering
+ let inputs = document
+ .getElementById("identity-credential-account")
+ .getElementsByClassName("identity-credential-list-item");
+ is(inputs.length, 2, "Two accounts expected");
+ let label0 = inputs[0].getElementsByClassName(
+ "identity-credential-list-item-label-stack"
+ )[0];
+ ok(
+ label0.textContent.includes("Test Account"),
+ "The first account name should be in the label"
+ );
+ ok(
+ label0.textContent.includes("test@idp.example"),
+ "The first account email should be in the label"
+ );
+ let label1 = inputs[1].getElementsByClassName(
+ "identity-credential-list-item-label-stack"
+ )[0];
+ ok(
+ label1.textContent.includes("Test Account 2"),
+ "The second account name should be in the label"
+ );
+ ok(
+ label1.textContent.includes("test2@idp.example"),
+ "The second account email should be in the label"
+ );
+
+ // Click the second account
+ inputs[1].click();
+
+ // Click continue
+ document
+ .getElementsByClassName("popup-notification-primary-button")[0]
+ .click();
+
+ // Make sure we selected the second account
+ let value = await prompt;
+ is(value, 1, "The prompt should resolve to 1, indicating the second account");
+
+ await popupHiding;
+
+ // Close tabs.
+ await BrowserTestUtils.removeTab(tab);
+});
+
+// Test that account pictures are rendered for the user
+add_task(async function test_multiple_acccount_show_picture() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ let popupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ // Show a prompt with two accounts, but only the first has a custom picture
+ let prompt = IdentityCredentialPromptService.showAccountListPrompt(
+ tab.linkedBrowser.browsingContext,
+ {
+ accounts: [
+ {
+ id: "00000000-0000-0000-0000-000000000000",
+ name: "Test Account",
+ email: "test@idp.example",
+ picture:
+ "https://example.net/browser/toolkit/components/credentialmanagement/tests/browser/custom.svg",
+ },
+ {
+ id: "00000000-0000-0000-0000-000000000000",
+ name: "Test Account 2",
+ email: "test2@idp.example",
+ },
+ ],
+ },
+ {
+ configURL: "https://idp.example/",
+ clientId: "123",
+ },
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ privacy_policy_url: "https://idp.example/privacy-policy.html",
+ terms_of_service_url: "https://idp.example/terms-of-service.html",
+ branding: {
+ background_color: "0x6200ee",
+ color: "0xffffff",
+ icons: [
+ {
+ size: 256,
+ url: "https://example.net/browser/toolkit/components/credentialmanagement/tests/browser/custom.svg",
+ },
+ ],
+ name: "demo ip",
+ },
+ }
+ );
+
+ // Wait for that popup
+ await popupShown;
+
+ let popupHiding = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popuphiding"
+ );
+
+ let document = tab.linkedBrowser.browsingContext.topChromeWindow.document;
+
+ let icons = document
+ .getElementById("identity-credential-account")
+ .getElementsByClassName("identity-credential-list-item-icon");
+ is(icons.length, 2, "Two accounts expected");
+ Assert.notEqual(icons[0].src, icons[1].src, "The icons are different");
+ ok(
+ icons[0].src.startsWith(
+ "data:image/svg+xml;base64,PCEtLSBUaGlzIFNvdXJjZSBDb2RlIEZvcm0gaXMgc3ViamVjdCB0byB0aGUgdGVybXMgb2YgdGhlIE1vemlsbGEgUHVibGljCiAgIC0gTGljZW5zZSwgdi4gMi4wLiBJZiBhIGNvcHkgb2YgdGhlIE1QTCB3YXMgbm90IGRpc3RyaWJ1dGVkIHdpdGggdGhpcwogICAtIGZpbGUsIFlvdSBjYW4gb2J0YWluIG9uZSBhdCBodHRwOi8vbW96aWxsYS5vcmcvTVBMLzIuMC8uIC0tPgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDE2IDE2IiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIGZpbGw9ImNvbnRleHQtZmlsbCIgZmlsbC1vcGFjaXR5PSJjb250ZXh0LWZpbGwtb3BhY2l0eSI+CiAgPHBhdGggZD0iTS42MjUgMTNhLjYyNS42MjUgMCAwIDEgMC0xLjI1bDMuMjUgMEE0Ljg4IDQuODggMCAwIDAgOC43NSA2Ljg3NWwwLS4yNWEuNjI1LjYyNSAwIDAgMSAxLjI1IDBsMCAuMjVBNi4xMzIgNi4xMzIgMCAwIDEgMy44NzUgMTNsLTMuMjUgMHoiLz"
+ ),
+ "The first icon matches the custom.svg"
+ );
+
+ const headerIcon = document.getElementsByClassName(
+ "identity-credential-header-icon"
+ )[0];
+
+ let title = document.getElementById("identity-credential-header-text");
+ ok(
+ title.textContent.includes("demo ip"),
+ "Popup title appears as business short name"
+ );
+
+ ok(BrowserTestUtils.isVisible(headerIcon), "Header Icon is showing");
+ ok(
+ headerIcon.src.startsWith(
+ "data:image/svg+xml;base64,PCEtLSBUaGlzIFNvdXJjZSBDb2RlIEZvcm0gaXMgc3ViamVjdCB0byB0aGUgdGVybXMgb2YgdGhlIE1vemlsbGEgUHVibGljCiAgIC0gTGljZW5zZSwgdi4gMi4wLiBJZiBhIGNvcHkgb2YgdGhlIE1QTCB3YXMgbm90IGRpc3RyaWJ1dGVkIHdpdGggdGhpcwogICAtIGZpbGUsIFlvdSBjYW4gb2J0YWluIG9uZSBhdCBodHRwOi8vbW96aWxsYS5vcmcvTVBMLzIuMC8uIC0tPgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDE2IDE2IiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIGZpbGw9ImNvbnRleHQtZmlsbCIgZmlsbC1vcGFjaXR5PSJjb250ZXh0LWZpbGwtb3BhY2l0eSI+CiAgPHBhdGggZD0iTS42MjUgMTNhLjYyNS42MjUgMCAwIDEgMC0xLjI1bDMuMjUgMEE0Ljg4IDQuODggMCAwIDAgOC43NSA2Ljg3NWwwLS4yNWEuNjI1LjYyNSAwIDAgMSAxLjI1IDBsMCAuMjVBNi4xMzIgNi4xMzIgMCAwIDEgMy44NzUgMTNsLTMuMjUgMHoiLz"
+ ),
+ "The header icon matches the icon resource from manifest"
+ );
+
+ // Click Continue
+ document
+ .getElementsByClassName("popup-notification-primary-button")[0]
+ .click();
+
+ // Make sure that the prompt resolves with the index of the only argument element
+ let value = await prompt;
+ is(value, 0);
+
+ await popupHiding;
+
+ // Close tabs.
+ await BrowserTestUtils.removeTab(tab);
+});
diff --git a/toolkit/components/credentialmanagement/tests/browser/browser_policy_dialog.js b/toolkit/components/credentialmanagement/tests/browser/browser_policy_dialog.js
new file mode 100644
index 0000000000..eb1026934c
--- /dev/null
+++ b/toolkit/components/credentialmanagement/tests/browser/browser_policy_dialog.js
@@ -0,0 +1,204 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+XPCOMUtils.defineLazyServiceGetter(
+ this,
+ "IdentityCredentialPromptService",
+ "@mozilla.org/browser/identitycredentialpromptservice;1",
+ "nsIIdentityCredentialPromptService"
+);
+
+const TEST_URL = "https://example.com/";
+
+// Test that a policy dialog does not appear when no policies are given
+add_task(async function test_policy_dialog_empty() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ let prompt = IdentityCredentialPromptService.showPolicyPrompt(
+ tab.linkedBrowser.browsingContext,
+ {
+ configURL: "https://idp.example/",
+ clientId: "123",
+ },
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ },
+ {} // No policies!
+ );
+
+ // Make sure we resolve with true without interaction
+ let value = await prompt;
+ is(value, true, "Automatically accept the missing policies");
+
+ // Close tab
+ await BrowserTestUtils.removeTab(tab);
+});
+
+// Make sure that a policy dialog shows up when we have policies to show.
+// Also test the accept path.
+add_task(async function test_policy_dialog() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ let popupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ // Show a prompt- the operative argument is the last one
+ let prompt = IdentityCredentialPromptService.showPolicyPrompt(
+ tab.linkedBrowser.browsingContext,
+ {
+ configURL: "https://idp.example/",
+ clientId: "123",
+ },
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ branding: {
+ background_color: "0x6200ee",
+ color: "0xffffff",
+ icons: [
+ {
+ size: 256,
+ url: "https://example.net/browser/toolkit/components/credentialmanagement/tests/browser/custom.svg",
+ },
+ ],
+ name: "demo ip",
+ },
+ },
+ {
+ privacy_policy_url: "https://idp.example/privacy-policy.html",
+ terms_of_service_url: "https://idp.example/terms-of-service.html",
+ }
+ );
+
+ // Make sure the popup shows up
+ await popupShown;
+
+ let popupHiding = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popuphiding"
+ );
+
+ // Validate the contents of the popup
+ let document = tab.linkedBrowser.browsingContext.topChromeWindow.document;
+
+ let description = document.getElementById(
+ "identity-credential-policy-explanation"
+ );
+
+ ok(
+ description.textContent.includes("idp.example"),
+ "IDP domain in the policy prompt text"
+ );
+ ok(
+ description.textContent.includes("example.com"),
+ "RP domain in the policy prompt text"
+ );
+ ok(
+ description.textContent.includes("Privacy Policy"),
+ "Link to the privacy policy in the policy prompt text"
+ );
+ ok(
+ description.textContent.includes("Terms of Service"),
+ "Link to the ToS in the policy prompt text"
+ );
+
+ let title = document.getElementById("identity-credential-header-text");
+ ok(
+ title.textContent.includes("demo ip"),
+ "IDP domain in the policy prompt header as business short name"
+ );
+
+ const headerIcon = document.getElementsByClassName(
+ "identity-credential-header-icon"
+ )[0];
+
+ ok(BrowserTestUtils.isVisible(headerIcon), "Header Icon is showing");
+ ok(
+ headerIcon.src.startsWith(
+ "data:image/svg+xml;base64,PCEtLSBUaGlzIFNvdXJjZSBDb2RlIEZvcm0gaXMgc3ViamVjdCB0byB0aGUgdGVybXMgb2YgdGhlIE1vemlsbGEgUHVibGljCiAgIC0gTGljZW5zZSwgdi4gMi4wLiBJZiBhIGNvcHkgb2YgdGhlIE1QTCB3YXMgbm90IGRpc3RyaWJ1dGVkIHdpdGggdGhpcwogICAtIGZpbGUsIFlvdSBjYW4gb2J0YWluIG9uZSBhdCBodHRwOi8vbW96aWxsYS5vcmcvTVBMLzIuMC8uIC0tPgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDE2IDE2IiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIGZpbGw9ImNvbnRleHQtZmlsbCIgZmlsbC1vcGFjaXR5PSJjb250ZXh0LWZpbGwtb3BhY2l0eSI+CiAgPHBhdGggZD0iTS42MjUgMTNhLjYyNS42MjUgMCAwIDEgMC0xLjI1bDMuMjUgMEE0Ljg4IDQuODggMCAwIDAgOC43NSA2Ljg3NWwwLS4yNWEuNjI1LjYyNSAwIDAgMSAxLjI1IDBsMCAuMjVBNi4xMzIgNi4xMzIgMCAwIDEgMy44NzUgMTNsLTMuMjUgMHoiLz"
+ ),
+ "The header icon matches the icon resource from manifest"
+ );
+
+ // Accept the policies
+ document
+ .getElementsByClassName("popup-notification-primary-button")[0]
+ .click();
+
+ // Make sure the call to the propmt resolves with true
+ let value = await prompt;
+ is(value, true, "User clicking accept resolves with true");
+
+ // Wait for the prompt to go away
+ await popupHiding;
+
+ // Close tab
+ await BrowserTestUtils.removeTab(tab);
+});
+
+// Test that rejecting the policies works
+add_task(async function test_policy_reject() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ let popupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ // Show the same prompt with policies
+ let prompt = IdentityCredentialPromptService.showPolicyPrompt(
+ tab.linkedBrowser.browsingContext,
+ {
+ configURL: "https://idp.example/",
+ clientId: "123",
+ },
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ },
+ {
+ privacy_policy_url: "https://idp.example/privacy-policy.html",
+ terms_of_service_url: "https://idp.example/terms-of-service.html",
+ }
+ );
+
+ // Wait for the prompt to show up
+ await popupShown;
+
+ let popupHiding = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popuphiding"
+ );
+
+ let document = tab.linkedBrowser.browsingContext.topChromeWindow.document;
+
+ let title = document.getElementById("identity-credential-header-text");
+ ok(
+ title.textContent.includes("idp.example"),
+ "IDP domain in the policy prompt header as domain"
+ );
+
+ // Click reject.
+ document
+ .getElementsByClassName("popup-notification-secondary-button")[0]
+ .click();
+
+ // Make sure the prompt call accepts with an indication of the user's reject choice.
+ let value = await prompt;
+ is(value, false, "User clicking reject causes the promise to resolve(false)");
+
+ // Wait for the popup to go away.
+ await popupHiding;
+
+ // Close tab.
+ await BrowserTestUtils.removeTab(tab);
+});
diff --git a/toolkit/components/credentialmanagement/tests/browser/browser_provider_dialog.js b/toolkit/components/credentialmanagement/tests/browser/browser_provider_dialog.js
new file mode 100644
index 0000000000..ca81675bb2
--- /dev/null
+++ b/toolkit/components/credentialmanagement/tests/browser/browser_provider_dialog.js
@@ -0,0 +1,396 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+XPCOMUtils.defineLazyServiceGetter(
+ this,
+ "IdentityCredentialPromptService",
+ "@mozilla.org/browser/identitycredentialpromptservice;1",
+ "nsIIdentityCredentialPromptService"
+);
+
+const TEST_URL = "https://example.com/";
+
+// Test that a single provider shows up in a dialog and is chosen when "continue" is clicked
+add_task(async function test_single_provider_dialog() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ let popupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ // Show one IDP
+ let prompt = IdentityCredentialPromptService.showProviderPrompt(
+ tab.linkedBrowser.browsingContext,
+ [
+ {
+ configURL: "https://idp.example/",
+ clientId: "123",
+ },
+ ],
+ [
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ },
+ ]
+ );
+
+ // Make sure a popup shows up.
+ await popupShown;
+
+ let popupHiding = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popuphiding"
+ );
+
+ let document = tab.linkedBrowser.browsingContext.topChromeWindow.document;
+
+ // Make sure there is only one option
+ let inputs = document
+ .getElementById("identity-credential-provider")
+ .getElementsByClassName("identity-credential-list-item");
+ is(inputs.length, 1, "One IDP");
+
+ // Make sure the IDP Site is in the label
+ let label = inputs[0].getElementsByClassName(
+ "identity-credential-list-item-label-primary"
+ )[0];
+ ok(label.textContent.includes("idp.example"), "IDP site in label");
+
+ // Validate the title of the popup
+ let title = document.querySelector(
+ 'description[popupid="identity-credential"]'
+ );
+ ok(
+ title.textContent.includes("Sign in with a login provider"),
+ "Popup title correct"
+ );
+
+ // Click "Continue"
+ document
+ .getElementsByClassName("popup-notification-primary-button")[0]
+ .click();
+
+ // Make sure the prompt promise resolves
+ let value = await prompt;
+ is(value, 0, "Selected the only IDP");
+
+ await popupHiding;
+
+ // Close tabs.
+ await BrowserTestUtils.removeTab(tab);
+});
+
+// Test that a single provider shows up in a dialog and is not chosen when "cancel" is clicked
+add_task(async function test_single_provider_deny() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ let popupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ // Show one IDP
+ let prompt = IdentityCredentialPromptService.showProviderPrompt(
+ tab.linkedBrowser.browsingContext,
+ [
+ {
+ configURL: "https://idp.example/",
+ clientId: "123",
+ },
+ ],
+ [
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ },
+ ]
+ );
+
+ // Make sure a popup shows up.
+ await popupShown;
+
+ let popupHiding = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popuphiding"
+ );
+
+ // Click cancel
+ let document = tab.linkedBrowser.browsingContext.topChromeWindow.document;
+ document
+ .getElementsByClassName("popup-notification-secondary-button")[0]
+ .click();
+
+ try {
+ await prompt;
+ ok(false, "Prompt should not resolve when denied.");
+ } catch (e) {
+ ok(true, "Prompt should reject when denied.");
+ }
+
+ await popupHiding;
+
+ // Close tabs.
+ await BrowserTestUtils.removeTab(tab);
+});
+
+// Show multiple IDPs and select the first one
+add_task(async function test_multiple_provider_dialog() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ let popupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ // Show two providers, in order. (we don't need the metadata because we aren't testing branding)
+ let prompt = IdentityCredentialPromptService.showProviderPrompt(
+ tab.linkedBrowser.browsingContext,
+ [
+ {
+ configURL: "https://idp1.example/",
+ clientId: "123",
+ },
+ {
+ configURL: "https://idp2.example/",
+ clientId: "123",
+ },
+ ],
+ [
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ },
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ },
+ ]
+ );
+
+ // Make sure the popup shows up
+ await popupShown;
+
+ let popupHiding = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popuphiding"
+ );
+
+ let document = tab.linkedBrowser.browsingContext.topChromeWindow.document;
+
+ let inputs = document
+ .getElementById("identity-credential-provider")
+ .getElementsByClassName("identity-credential-list-item");
+ is(inputs.length, 2, "Two IDPs visible");
+
+ let label1 = inputs[0].getElementsByClassName(
+ "identity-credential-list-item-label-primary"
+ )[0];
+ ok(
+ label1.textContent.includes("idp1.example"),
+ "First IDP label includes its site"
+ );
+ let label2 = inputs[1].getElementsByClassName(
+ "identity-credential-list-item-label-primary"
+ )[0];
+ ok(
+ label2.textContent.includes("idp2.example"),
+ "Second IDP label includes its site"
+ );
+
+ // Click continue
+ document
+ .getElementsByClassName("popup-notification-primary-button")[0]
+ .click();
+
+ let value = await prompt;
+ is(value, 0, "The default is the first option in the list");
+
+ await popupHiding;
+
+ // Close tabs.
+ await BrowserTestUtils.removeTab(tab);
+});
+
+// Show multiple IDPs and select the second one
+add_task(async function test_multiple_provider_choose_second() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ let popupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ // Show two providers, in order. (we don't need the metadata because we aren't testing branding)
+ let prompt = IdentityCredentialPromptService.showProviderPrompt(
+ tab.linkedBrowser.browsingContext,
+ [
+ {
+ configURL: "https://idp1.example/",
+ clientId: "123",
+ },
+ {
+ configURL: "https://idp2.example/",
+ clientId: "123",
+ },
+ ],
+ [
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ },
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ },
+ ]
+ );
+
+ // Wait for the popup
+ await popupShown;
+
+ let popupHiding = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popuphiding"
+ );
+
+ let document = tab.linkedBrowser.browsingContext.topChromeWindow.document;
+
+ let inputs = document
+ .getElementById("identity-credential-provider")
+ .getElementsByClassName("identity-credential-list-item");
+ is(inputs.length, 2, "Two IDPs visible");
+
+ let label1 = inputs[0].getElementsByClassName(
+ "identity-credential-list-item-label-primary"
+ )[0];
+ ok(
+ label1.textContent.includes("idp1.example"),
+ "First IDP label includes its site"
+ );
+ let label2 = inputs[1].getElementsByClassName(
+ "identity-credential-list-item-label-primary"
+ )[0];
+ ok(
+ label2.textContent.includes("idp2.example"),
+ "Second IDP label includes its site"
+ );
+
+ // Click the second list item
+ inputs[1].click();
+
+ // Click continue
+ document
+ .getElementsByClassName("popup-notification-primary-button")[0]
+ .click();
+
+ // Make sure the caller gets the second IDP
+ let value = await prompt;
+ is(value, 1, "Choosing a different option makes a change");
+
+ await popupHiding;
+
+ // Close tabs.
+ await BrowserTestUtils.removeTab(tab);
+});
+
+// Validate that the branding information is rendered correctly
+add_task(async function test_multiple_provider_show_branding() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ let popupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ // Show the prompt, but include an icon for the second IDP
+ let prompt = IdentityCredentialPromptService.showProviderPrompt(
+ tab.linkedBrowser.browsingContext,
+ [
+ {
+ configURL: "https://idp1.example/",
+ clientId: "123",
+ },
+ {
+ configURL: "https://idp2.example/",
+ clientId: "123",
+ },
+ ],
+ [
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ },
+ {
+ accounts_endpoint: "",
+ client_metadata_endpoint: "",
+ id_assertion_endpoint: "",
+ branding: {
+ icons: [
+ {
+ url: "https://example.net/browser/toolkit/components/credentialmanagement/tests/browser/custom.svg",
+ },
+ ],
+ name: "demo ip",
+ },
+ },
+ ]
+ );
+
+ // Wait for that popup
+ await popupShown;
+
+ let popupHiding = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popuphiding"
+ );
+
+ let document = tab.linkedBrowser.browsingContext.topChromeWindow.document;
+
+ // Validate the icons
+ let icons = document
+ .getElementById("identity-credential-provider")
+ .getElementsByClassName("identity-credential-list-item-icon");
+ is(icons.length, 2, "Two icons in the popup");
+ Assert.notEqual(icons[0].src, icons[1].src, "Icons are different");
+ ok(
+ icons[1].src.startsWith(
+ "data:image/svg+xml;base64,PCEtLSBUaGlzIFNvdXJjZSBDb2RlIEZvcm0gaXMgc3ViamVjdCB0byB0aGUgdGVybXMgb2YgdGhlIE1vemlsbGEgUHVibGljCiAgIC0gTGljZW5zZSwgdi4gMi4wLiBJZiBhIGNvcHkgb2YgdGhlIE1QTCB3YXMgbm90IGRpc3RyaWJ1dGVkIHdpdGggdGhpcwogICAtIGZpbGUsIFlvdSBjYW4gb2J0YWluIG9uZSBhdCBodHRwOi8vbW96aWxsYS5vcmcvTVBMLzIuMC8uIC0tPgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDE2IDE2IiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIGZpbGw9ImNvbnRleHQtZmlsbCIgZmlsbC1vcGFjaXR5PSJjb250ZXh0LWZpbGwtb3BhY2l0eSI+CiAgPHBhdGggZD0iTS42MjUgMTNhLjYyNS42MjUgMCAwIDEgMC0xLjI1bDMuMjUgMEE0Ljg4IDQuODggMCAwIDAgOC43NSA2Ljg3NWwwLS4yNWEuNjI1LjYyNSAwIDAgMSAxLjI1IDBsMCAuMjVBNi4xMzIgNi4xMzIgMCAwIDEgMy44NzUgMTNsLTMuMjUgMHoiLz"
+ ),
+ "The second icon matches the custom.svg"
+ );
+
+ let inputs = document
+ .getElementById("identity-credential-provider")
+ .getElementsByClassName("identity-credential-list-item");
+ is(inputs.length, 2, "One IDP");
+ let label = inputs[1].getElementsByClassName(
+ "identity-credential-list-item-label-primary"
+ )[0];
+ ok(label.textContent.includes("demo ip"), "should show business short time");
+
+ // Click continue
+ document
+ .getElementsByClassName("popup-notification-primary-button")[0]
+ .click();
+
+ // Make sure the caller gets the first provider still
+ let value = await prompt;
+ is(value, 0, "The default is the first option in the list");
+
+ await popupHiding;
+
+ // Close tabs.
+ await BrowserTestUtils.removeTab(tab);
+});
diff --git a/toolkit/components/credentialmanagement/tests/browser/custom.svg b/toolkit/components/credentialmanagement/tests/browser/custom.svg
new file mode 100644
index 0000000000..320d516b07
--- /dev/null
+++ b/toolkit/components/credentialmanagement/tests/browser/custom.svg
@@ -0,0 +1,8 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity">
+ <path d="M.625 13a.625.625 0 0 1 0-1.25l3.25 0A4.88 4.88 0 0 0 8.75 6.875l0-.25a.625.625 0 0 1 1.25 0l0 .25A6.132 6.132 0 0 1 3.875 13l-3.25 0z"/>
+ <path d="M12.096 15.248a.625.625 0 0 1-.491-1.012c4.281-5.446 3.261-8.813 2.271-10.337-1.346-2.07-4.169-3.106-6.71-2.464-2.428.615-3.951 2.583-4.178 5.397-.027.345-.364.585-.673.574a.626.626 0 0 1-.573-.673C2.011 3.4 3.924.967 6.859.224c3.044-.768 6.437.489 8.064 2.995 1.172 1.803 2.426 5.732-2.337 11.791a.622.622 0 0 1-.49.238z"/>
+ <path d="M5.734 16a.624.624 0 0 1-.165-1.228c5.912-1.62 6.147-7.768 6.148-7.829a2.113 2.113 0 0 0-.457-1.708 2.713 2.713 0 0 0-1.689-.947c-.683-.109-1.357.021-1.902.371-.521.334-.859.83-.95 1.396l-.217 1.209a3.621 3.621 0 0 1-3.567 2.986l-2.31 0a.625.625 0 0 1 0-1.25l2.31 0a2.373 2.373 0 0 0 2.337-1.957l.215-1.196c.146-.912.683-1.711 1.509-2.24a3.95 3.95 0 0 1 2.774-.553 3.964 3.964 0 0 1 2.461 1.394c.618.762.878 1.688.729 2.611.005 0-.27 7.059-7.061 8.919a.619.619 0 0 1-.165.022z"/>
+</svg>
diff --git a/toolkit/components/credentialmanagement/tests/browser/head.js b/toolkit/components/credentialmanagement/tests/browser/head.js
new file mode 100644
index 0000000000..d646d2b39d
--- /dev/null
+++ b/toolkit/components/credentialmanagement/tests/browser/head.js
@@ -0,0 +1,2 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */