summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/contacts
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/contacts
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/contacts')
-rw-r--r--testing/web-platform/tests/contacts/META.yml1
-rw-r--r--testing/web-platform/tests/contacts/contacts-select.https.window.js185
-rw-r--r--testing/web-platform/tests/contacts/resources/helpers.js41
-rw-r--r--testing/web-platform/tests/contacts/resources/non-main-frame-select.html9
4 files changed, 236 insertions, 0 deletions
diff --git a/testing/web-platform/tests/contacts/META.yml b/testing/web-platform/tests/contacts/META.yml
new file mode 100644
index 0000000000..aa55f896ee
--- /dev/null
+++ b/testing/web-platform/tests/contacts/META.yml
@@ -0,0 +1 @@
+spec: https://wicg.github.io/contact-api/spec/
diff --git a/testing/web-platform/tests/contacts/contacts-select.https.window.js b/testing/web-platform/tests/contacts/contacts-select.https.window.js
new file mode 100644
index 0000000000..850217aadf
--- /dev/null
+++ b/testing/web-platform/tests/contacts/contacts-select.https.window.js
@@ -0,0 +1,185 @@
+// META: script=/resources/test-only-api.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=resources/helpers.js
+'use strict';
+
+// Verifies that |func|, when invoked, throws a TypeError exception.
+async function expectTypeError(func) {
+ try {
+ await func();
+ } catch (e) {
+ assert_equals(e.name, 'TypeError');
+ return;
+ }
+
+ assert_unreached('expected a TypeError, but none was thrown');
+}
+
+promise_test(async () => {
+ try {
+ await navigator.contacts.select(['name']);
+ assert_unreached('expected a SecurityError, but none was thrown');
+ } catch (e) {
+ assert_equals(e.name, 'SecurityError');
+ }
+}, 'The Contact API requires a user gesture')
+
+contactsTestWithUserActivation(async (test, setSelectedContacts) => {
+ // At least one property must be provided.
+ await expectTypeError(() => navigator.contacts.select());
+ await expectTypeError(() => navigator.contacts.select([]));
+
+ // Per WebIDL parsing, no invalid values may be provided.
+ await expectTypeError(() =>
+ navigator.contacts.select(['']));
+ await expectTypeError(() =>
+ navigator.contacts.select(['foo']));
+ await expectTypeError(() =>
+ navigator.contacts.select(['name', 'photo']));
+
+}, 'The Contact API requires valid properties to be provided');
+
+contactsTestWithUserActivation(async (test, setSelectedContacts) => {
+ // Returns a NULL result, indicating that no results are available.
+ setSelectedContacts(null);
+
+ await expectTypeError(() => navigator.contacts.select(['name']));
+
+}, 'The Contact API can fail when the selector cannot be opened');
+
+contactsTestWithUserActivation(async (test, setSelectedContacts) => {
+ setSelectedContacts([]);
+
+ const properties = await navigator.contacts.getProperties();
+ assert_true(properties.length > 0);
+
+ // Requesting the available properties should not fail.
+ await navigator.contacts.select(properties);
+
+}, 'Supported contact properties are exposed.');
+
+contactsTestWithUserActivation(async (test, setSelectedContacts) => {
+ const dwightAddress = {
+ country: 'US',
+ city: 'Scranton',
+ addressLine: ['Schrute Farms'],
+ };
+ const michaelIcons = [new Blob('image binary data'.split(''), {type: 'image/test'})];
+
+ // Returns two contacts with all information available.
+ setSelectedContacts([
+ { name: ['Dwight Schrute'], email: ['dwight@schrutefarmsbnb.com'], tel: ['000-0000'], address: [dwightAddress] },
+ { name: ['Michael Scott', 'Prison Mike'], email: ['michael@dundermifflin.com'], icon: michaelIcons },
+ ]);
+
+ let results = await navigator.contacts.select(['name', 'email', 'icon', 'tel', 'address'], { multiple: true });
+ assert_equals(results.length, 2);
+ results = results.sort((c1, c2) => JSON.stringify(c1) < JSON.stringify(c2) ? -1 : 1);
+
+ {
+ const michael = results[0];
+
+ assert_own_property(michael, 'name');
+ assert_own_property(michael, 'email');
+ assert_own_property(michael, 'tel');
+ assert_own_property(michael, 'address');
+ assert_own_property(michael, 'icon');
+
+ assert_array_equals(michael.name, ['Michael Scott', 'Prison Mike']);
+ assert_array_equals(michael.email, ['michael@dundermifflin.com']);
+ assert_array_equals(michael.tel, []);
+ assert_array_equals(michael.address, []);
+
+ assert_equals(michael.icon.length, michaelIcons.length);
+ assert_equals(michael.icon[0].type, michaelIcons[0].type);
+ assert_equals(michael.icon[0].size, michaelIcons[0].size);
+ assert_equals(await michael.icon[0].text(), await michaelIcons[0].text());
+ }
+
+ {
+ const dwight = results[1];
+ assert_own_property(dwight, 'name');
+ assert_own_property(dwight, 'email');
+ assert_own_property(dwight, 'tel');
+ assert_own_property(dwight, 'address');
+ assert_own_property(dwight, 'icon');
+
+ assert_array_equals(dwight.name, ['Dwight Schrute']);
+ assert_array_equals(dwight.email, ['dwight@schrutefarmsbnb.com']);
+ assert_array_equals(dwight.tel, ['000-0000']);
+ assert_array_equals(dwight.icon, []);
+
+ assert_equals(dwight.address.length, 1);
+ const selectedAddress = dwight.address[0];
+ assert_object_equals({
+ country: selectedAddress.country,
+ city: selectedAddress.city,
+ addressLine: selectedAddress.addressLine,
+ }, dwightAddress);
+ }
+}, 'The Contact API correctly returns ContactInfo entries');
+
+contactsTestWithUserActivation(async (test, setSelectedContacts) => {
+ // Returns two contacts with all information available.
+ setSelectedContacts([
+ { name: ['Dwight Schrute'], email: ['dwight@schrutefarmsbnb.com'], tel: ['000-0000'] },
+ { name: ['Michael Scott', 'Prison Mike'], email: ['michael@dundermifflin.com'] },
+ ]);
+
+ const results = await navigator.contacts.select(['name', 'email', 'tel']);
+ assert_equals(results.length, 1);
+
+}, 'Only one contact is returned if `multiple` is not set.');
+
+contactsTestWithUserActivation(async (test, setSelectedContacts) => {
+ // Returns partial information since no e-mail addresses are requested.
+ setSelectedContacts([{ name: ['Creed'], email: ['creedthoughts@www.creedthoughts.gov.www'] }]);
+
+ const results = await navigator.contacts.select(['name']);
+
+ assert_equals(results.length, 1);
+
+ {
+ const creed = results[0];
+
+ assert_array_equals(creed.name, ['Creed']);
+ assert_equals(creed.email, undefined);
+ assert_equals(creed.tel, undefined);
+ }
+}, 'The Contact API does not include fields that were not requested');
+
+contactsTestWithUserActivation(async (test, setSelectedContacts) => {
+ // Returns partial information since no e-mail addresses are requested.
+ setSelectedContacts([{ name: ['Kelly'] }]);
+
+ // First request should work.
+ const promise1 = new Promise((resolve, reject) => {
+ navigator.contacts.select(['name']).then(resolve)
+ .catch(e => reject(e.message));
+ });
+
+ // Second request should fail (since the first one didn't complete yet).
+ const promise2 = new Promise((resolve, reject) => {
+ navigator.contacts.select(['name']).then(contacts => reject('This was supposed to fail'))
+ .catch(e => resolve(e.name));
+ });
+
+ const results = await Promise.all([promise1, promise2]);
+ const contacts = results[0];
+ assert_equals(contacts.length, 1);
+ const contact = contacts[0];
+ assert_equals(contact.name[0], 'Kelly');
+ assert_equals(results[1], 'InvalidStateError');
+
+}, 'The Contact API cannot be used again until the first operation is complete.');
+
+contactsTestWithUserActivation(async (test, setSelectedContacts) => {
+ const iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ iframe.src = 'resources/non-main-frame-select.html';
+ await new Promise(resolve => window.addEventListener('message', event => resolve(event.data)))
+ .then(data => assert_equals(data.errorMsg, 'InvalidStateError'))
+ .finally(() => iframe.remove())
+
+}, 'Test contacts.select() throws an InvalidStateError in a sub-frame');
diff --git a/testing/web-platform/tests/contacts/resources/helpers.js b/testing/web-platform/tests/contacts/resources/helpers.js
new file mode 100644
index 0000000000..8bac86b9b9
--- /dev/null
+++ b/testing/web-platform/tests/contacts/resources/helpers.js
@@ -0,0 +1,41 @@
+'use strict';
+
+// These tests rely on the User Agent providing an implementation of
+// platform contacts backends.
+//
+// In Chromium-based browsers this implementation is provided by a polyfill
+// in order to reduce the amount of test-only code shipped to users. To enable
+// these tests the browser must be run with these options:
+//
+// --enable-blink-features=MojoJS,MojoJSTest
+async function loadChromiumResources() {
+ await import('/resources/chromium/contacts_manager_mock.js');
+}
+
+// User Agents must provide their own implementation of `WebContacts`,
+// which must contain the following this interface:
+// class WebContactsTest {
+// /** @param {?Array<!ContactInfo>} contacts */
+// setSelectedContacts(contacts);
+// }
+async function createWebContactsTest() {
+ if (typeof WebContactsTest === 'undefined') {
+ if (isChromiumBased) {
+ await loadChromiumResources();
+ }
+ }
+ assert_implements(WebContactsTest, 'WebContactsTest is unavailable.');
+ return new WebContactsTest();
+}
+
+// Creates a Promise test for |func| given the |description|. The |func| will
+// be executed with `setSelectedContacts` which will allow tests to mock out
+// the result of calling navigator.contacts.select. `setSelectedContacts`
+// accepts a nullable Array of ContactInfos.
+function contactsTestWithUserActivation(func, description) {
+ promise_test(async test => {
+ const webContactsTest = await createWebContactsTest();
+ await window.test_driver.bless('request contacts');
+ return func(test, contacts => webContactsTest.setSelectedContacts(contacts));
+ }, description);
+}
diff --git a/testing/web-platform/tests/contacts/resources/non-main-frame-select.html b/testing/web-platform/tests/contacts/resources/non-main-frame-select.html
new file mode 100644
index 0000000000..c64ecd067c
--- /dev/null
+++ b/testing/web-platform/tests/contacts/resources/non-main-frame-select.html
@@ -0,0 +1,9 @@
+<script>
+ 'use strict';
+
+ window.onload = function() {
+ navigator.contacts.select(['name', 'email'], { multiple: true })
+ .then(results => parent.postMessage({ errorMsg: '' }, '*'))
+ .catch(exception => parent.postMessage({ errorMsg: exception.name }, '*'));
+ }
+</script>