contacts-select.https.window.js (6992B)
1 // META: script=/resources/test-only-api.js 2 // META: script=/resources/testdriver.js 3 // META: script=/resources/testdriver-vendor.js 4 // META: script=resources/helpers.js 5 'use strict'; 6 7 // Verifies that |func|, when invoked, throws a TypeError exception. 8 async function expectTypeError(func) { 9 try { 10 await func(); 11 } catch (e) { 12 assert_equals(e.name, 'TypeError'); 13 return; 14 } 15 16 assert_unreached('expected a TypeError, but none was thrown'); 17 } 18 19 promise_test(async () => { 20 try { 21 await navigator.contacts.select(['name']); 22 assert_unreached('expected a SecurityError, but none was thrown'); 23 } catch (e) { 24 assert_equals(e.name, 'SecurityError'); 25 } 26 }, 'The Contact API requires a user gesture') 27 28 contactsTestWithUserActivation(async (test, setSelectedContacts) => { 29 // At least one property must be provided. 30 await expectTypeError(() => navigator.contacts.select()); 31 await expectTypeError(() => navigator.contacts.select([])); 32 33 // Per WebIDL parsing, no invalid values may be provided. 34 await expectTypeError(() => 35 navigator.contacts.select([''])); 36 await expectTypeError(() => 37 navigator.contacts.select(['foo'])); 38 await expectTypeError(() => 39 navigator.contacts.select(['name', 'photo'])); 40 41 }, 'The Contact API requires valid properties to be provided'); 42 43 contactsTestWithUserActivation(async (test, setSelectedContacts) => { 44 // Returns a NULL result, indicating that no results are available. 45 setSelectedContacts(null); 46 47 await expectTypeError(() => navigator.contacts.select(['name'])); 48 49 }, 'The Contact API can fail when the selector cannot be opened'); 50 51 contactsTestWithUserActivation(async (test, setSelectedContacts) => { 52 setSelectedContacts([]); 53 54 const properties = await navigator.contacts.getProperties(); 55 assert_true(properties.length > 0); 56 57 // Requesting the available properties should not fail. 58 await navigator.contacts.select(properties); 59 60 }, 'Supported contact properties are exposed.'); 61 62 contactsTestWithUserActivation(async (test, setSelectedContacts) => { 63 const dwightAddress = { 64 country: 'US', 65 city: 'Scranton', 66 addressLine: ['Schrute Farms'], 67 }; 68 const michaelIcons = [new Blob('image binary data'.split(''), {type: 'image/test'})]; 69 70 // Returns two contacts with all information available. 71 setSelectedContacts([ 72 { name: ['Dwight Schrute'], email: ['dwight@schrutefarmsbnb.com'], tel: ['000-0000'], address: [dwightAddress] }, 73 { name: ['Michael Scott', 'Prison Mike'], email: ['michael@dundermifflin.com'], icon: michaelIcons }, 74 ]); 75 76 let results = await navigator.contacts.select(['name', 'email', 'icon', 'tel', 'address'], { multiple: true }); 77 assert_equals(results.length, 2); 78 results = results.sort((c1, c2) => JSON.stringify(c1) < JSON.stringify(c2) ? -1 : 1); 79 80 { 81 const michael = results[0]; 82 83 assert_own_property(michael, 'name'); 84 assert_own_property(michael, 'email'); 85 assert_own_property(michael, 'tel'); 86 assert_own_property(michael, 'address'); 87 assert_own_property(michael, 'icon'); 88 89 assert_array_equals(michael.name, ['Michael Scott', 'Prison Mike']); 90 assert_array_equals(michael.email, ['michael@dundermifflin.com']); 91 assert_array_equals(michael.tel, []); 92 assert_array_equals(michael.address, []); 93 94 assert_equals(michael.icon.length, michaelIcons.length); 95 assert_equals(michael.icon[0].type, michaelIcons[0].type); 96 assert_equals(michael.icon[0].size, michaelIcons[0].size); 97 assert_equals(await michael.icon[0].text(), await michaelIcons[0].text()); 98 } 99 100 { 101 const dwight = results[1]; 102 assert_own_property(dwight, 'name'); 103 assert_own_property(dwight, 'email'); 104 assert_own_property(dwight, 'tel'); 105 assert_own_property(dwight, 'address'); 106 assert_own_property(dwight, 'icon'); 107 108 assert_array_equals(dwight.name, ['Dwight Schrute']); 109 assert_array_equals(dwight.email, ['dwight@schrutefarmsbnb.com']); 110 assert_array_equals(dwight.tel, ['000-0000']); 111 assert_array_equals(dwight.icon, []); 112 113 assert_equals(dwight.address.length, 1); 114 const selectedAddress = dwight.address[0]; 115 assert_object_equals({ 116 country: selectedAddress.country, 117 city: selectedAddress.city, 118 addressLine: selectedAddress.addressLine, 119 }, dwightAddress); 120 } 121 }, 'The Contact API correctly returns ContactInfo entries'); 122 123 contactsTestWithUserActivation(async (test, setSelectedContacts) => { 124 // Returns two contacts with all information available. 125 setSelectedContacts([ 126 { name: ['Dwight Schrute'], email: ['dwight@schrutefarmsbnb.com'], tel: ['000-0000'] }, 127 { name: ['Michael Scott', 'Prison Mike'], email: ['michael@dundermifflin.com'] }, 128 ]); 129 130 const results = await navigator.contacts.select(['name', 'email', 'tel']); 131 assert_equals(results.length, 1); 132 133 }, 'Only one contact is returned if `multiple` is not set.'); 134 135 contactsTestWithUserActivation(async (test, setSelectedContacts) => { 136 // Returns partial information since no e-mail addresses are requested. 137 setSelectedContacts([{ name: ['Creed'], email: ['creedthoughts@www.creedthoughts.gov.www'] }]); 138 139 const results = await navigator.contacts.select(['name']); 140 141 assert_equals(results.length, 1); 142 143 { 144 const creed = results[0]; 145 146 assert_array_equals(creed.name, ['Creed']); 147 assert_equals(creed.email, undefined); 148 assert_equals(creed.tel, undefined); 149 } 150 }, 'The Contact API does not include fields that were not requested'); 151 152 contactsTestWithUserActivation(async (test, setSelectedContacts) => { 153 // Returns partial information since no e-mail addresses are requested. 154 setSelectedContacts([{ name: ['Kelly'] }]); 155 156 // First request should work. 157 const promise1 = new Promise((resolve, reject) => { 158 navigator.contacts.select(['name']).then(resolve) 159 .catch(e => reject(e.message)); 160 }); 161 162 // Second request should fail (since the first one didn't complete yet). 163 const promise2 = new Promise((resolve, reject) => { 164 navigator.contacts.select(['name']).then(contacts => reject('This was supposed to fail')) 165 .catch(e => resolve(e.name)); 166 }); 167 168 const results = await Promise.all([promise1, promise2]); 169 const contacts = results[0]; 170 assert_equals(contacts.length, 1); 171 const contact = contacts[0]; 172 assert_equals(contact.name[0], 'Kelly'); 173 assert_equals(results[1], 'InvalidStateError'); 174 175 }, 'The Contact API cannot be used again until the first operation is complete.'); 176 177 contactsTestWithUserActivation(async (test, setSelectedContacts) => { 178 const iframe = document.createElement('iframe'); 179 document.body.appendChild(iframe); 180 iframe.src = 'resources/non-main-frame-select.html'; 181 await new Promise(resolve => window.addEventListener('message', event => resolve(event.data))) 182 .then(data => assert_equals(data.errorMsg, 'InvalidStateError')) 183 .finally(() => iframe.remove()) 184 185 }, 'Test contacts.select() throws an InvalidStateError in a sub-frame');