tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

NDEFReader_write.https.html (19356B)


      1 <!DOCTYPE html>
      2 <meta charset=utf-8>
      3 <title>Web NFC: NDEFReader.write Tests</title>
      4 <link rel="author" title="Intel" href="http://www.intel.com"/>
      5 <link rel="help" href="https://w3c.github.io/web-nfc/"/>
      6 <script src="/resources/testharness.js"></script>
      7 <script src="/resources/testharnessreport.js"></script>
      8 <script src="resources/nfc-helpers.js"></script>
      9 <script>
     10 
     11 "use strict";
     12 
     13 const invalid_type_messages =
     14    [
     15      // Invalid NDEFMessageSource type
     16      undefined,
     17 
     18      // NDEFMessage.records: should have at least 1 valid record.
     19      // https://w3c.github.io/web-nfc/#the-write-method - Step 8.
     20      createMessage([{}]),
     21 
     22      // NDEFMessageSource: not NDEF-formatable.
     23      // https://w3c.github.io/web-nfc/#the-write-method - Step 8.
     24      createMessage([]),
     25 
     26      // https://w3c.github.io/web-nfc/#dfn-map-text-to-ndef
     27      // NDEFRecord must have data.
     28      createMessage([createTextRecord()]),
     29 
     30      // NDEFRecord.data for 'text' record must be either a string,
     31      // an arrayBuffer, or an arrayBufferView.
     32      createMessage([createTextRecord(test_json_data)]),
     33 
     34      // NDEFRecord.encoding for 'text' record must be either "utf-8",
     35      // "utf-16", "utf-16le" or "utf-16be".
     36      createMessage([createTextRecord(test_buffer_data, "chinese")]),
     37 
     38      // https://w3c.github.io/web-nfc/#dfn-map-a-url-to-ndef
     39      // NDEFRecord must have data.
     40      createMessage([createUrlRecord()]),
     41 
     42      // https://w3c.github.io/web-nfc/#dfn-map-a-url-to-ndef
     43      // NDEFRecord must have data.
     44      createMessage([createUrlRecord(undefined, true)]),
     45 
     46      // NDEFRecord.data for 'url' record must be string.
     47      createMessage([createUrlRecord(test_buffer_data)]),
     48      createMessage([createUrlRecord(test_json_data)]),
     49 
     50      // NDEFRecord.data for 'absolute-url' record must be string.
     51      createMessage([createUrlRecord(test_buffer_data, true)]),
     52      createMessage([createUrlRecord(test_json_data, true)]),
     53 
     54      // https://w3c.github.io/web-nfc/#dfn-map-binary-data-to-ndef
     55      // NDEFRecord must have data.
     56      createMessage([createMimeRecord()]),
     57 
     58      // NDEFRecord.data for 'mime' record must be BufferSource.
     59      createMessage([createMimeRecord(test_text_data)]),
     60      createMessage([createMimeRecord(test_number_data)]),
     61      createMessage([createMimeRecord(test_json_data)]),
     62 
     63      // NDEFRecord must have data.
     64      createMessage([createUnknownRecord()]),
     65 
     66      // NDEFRecord.data for 'unknown' record must be BufferSource.
     67      createMessage([createUnknownRecord(test_text_data)]),
     68      createMessage([createUnknownRecord(test_number_data)]),
     69      createMessage([createUnknownRecord(test_json_data)]),
     70 
     71      // https://w3c.github.io/web-nfc/#dfn-map-external-data-to-ndef
     72      // NDEFRecord must have data.
     73      createMessage([createRecord('w3.org:xyz')]),
     74 
     75      // NDEFRecord.data for external record must be a BufferSource or NDEFMessageInit.
     76      createMessage([createRecord('w3.org:xyz', test_text_data)]),
     77      createMessage([createRecord('w3.org:xyz', test_number_data)]),
     78      createMessage([createRecord('w3.org:xyz', test_json_data)]),
     79 
     80      // https://w3c.github.io/web-nfc/#dfn-map-local-type-to-ndef
     81      // NDEFRecord must have data.
     82      createMessage([createRecord(':xyz')]),
     83 
     84      // NDEFRecord.data for local type record must be a BufferSource or NDEFMessageInit.
     85      createMessage([createRecord(':xyz', test_text_data)]),
     86      createMessage([createRecord(':xyz', test_number_data)]),
     87      createMessage([createRecord(':xyz', test_json_data)]),
     88 
     89      // https://w3c.github.io/web-nfc/#dfn-map-smart-poster-to-ndef
     90      // NDEFRecord must have data.
     91      createMessage([createRecord('smart-poster')]),
     92 
     93      // NDEFRecord.data for smart-poster record must be a NDEFMessageInit.
     94      createMessage([createRecord('smart-poster', test_text_data)]),
     95      createMessage([createRecord('smart-poster', test_number_data)]),
     96      createMessage([createRecord('smart-poster', test_json_data)]),
     97      createMessage([createRecord('smart-poster', test_buffer_data)]),
     98 
     99      // https://w3c.github.io/web-nfc/#ndef-record-types
    100      // The record type is neither a known type ('text', 'mime' etc.) nor a
    101      // valid external/local type.
    102      createMessage([createRecord('unmatched_type', test_buffer_data)])
    103    ];
    104 
    105 const invalid_syntax_messages =
    106    [
    107      // Data for 'url' or 'absolute-url' record, must be a valid URL.
    108      createMessage([createUrlRecord('Invalid URL:// Data')]),
    109      createMessage([createUrlRecord('Invalid URL:// Data', true)]),
    110 
    111      // NDEFRecord.lang length for 'text' record must be lower than 64.
    112      createMessage([createTextRecord(test_text_data, undefined /* encoding */,
    113                                      [...Array(64)].map(_ => 'a'))]),
    114    ];
    115 
    116 const invalid_signals = [
    117  "string",
    118  123,
    119  {},
    120  true,
    121  Symbol(),
    122  () => {},
    123  self
    124 ];
    125 
    126 nfc_test(async t => {
    127  const ndef = new NDEFReader();
    128  const promises = [];
    129  invalid_type_messages.forEach(message => {
    130    promises.push(
    131      promise_rejects_js(t, TypeError, ndef.write(message)));
    132  });
    133  await Promise.all(promises);
    134 }, "Test that promise is rejected with TypeError if NDEFMessageSource is invalid.");
    135 
    136 nfc_test(async t => {
    137  const ndef = new NDEFReader();
    138  const promises = [];
    139  invalid_syntax_messages.forEach(message => {
    140    promises.push(
    141      promise_rejects_dom(t, 'SyntaxError', ndef.write(message)));
    142  });
    143  await Promise.all(promises);
    144 }, "Test that promise is rejected with SyntaxError if NDEFMessageSource contains\
    145 invalid records.");
    146 
    147 nfc_test(async t => {
    148  await test_driver.set_permission({ name: 'nfc' }, 'denied');
    149  const ndef = new NDEFReader();
    150  await promise_rejects_dom(t, 'NotAllowedError', ndef.write(test_text_data));
    151 }, 'NDEFReader.write should fail if user permission is not granted.');
    152 
    153 // We do not provide NFC mock here to simulate that there has no available
    154 // implementation for NFC Mojo interface.
    155 nfc_test(async (t, mockNFC) => {
    156  mockNFC.simulateClosedPipe();
    157  const ndef = new NDEFReader();
    158  await promise_rejects_dom(t, 'NotSupportedError', ndef.write(test_text_data));
    159 }, 'NDEFReader.write should fail if no implementation for NFC Mojo interface is available.');
    160 
    161 nfc_test(async (t, mockNFC) => {
    162  const ndef = new NDEFReader();
    163  const controller = new AbortController();
    164 
    165  //Make sure push is pending
    166  mockNFC.setPendingPushCompleted(false);
    167  const p = ndef.write(test_text_data, { signal: controller.signal });
    168  const rejected = promise_rejects_dom(t, 'AbortError', p);
    169  let callback_called = false;
    170  await new Promise(resolve => {
    171    t.step_timeout(() => {
    172      callback_called = true;
    173      controller.abort();
    174      resolve();
    175    }, 10);
    176  });
    177  await rejected;
    178  assert_true(callback_called, 'timeout should have caused the abort');
    179 }, "NDEFReader.write should fail if abort write request before write happends.");
    180 
    181 nfc_test(async t => {
    182  const ndef = new NDEFReader();
    183  const controller = new AbortController();
    184  assert_false(controller.signal.aborted);
    185  controller.abort();
    186  assert_true(controller.signal.aborted);
    187  await promise_rejects_dom(t, 'AbortError',
    188      ndef.write(test_text_data, { signal: controller.signal }));
    189 }, "NDEFReader.write should fail if signal's aborted flag is set.");
    190 
    191 nfc_test(async t => {
    192  const ndef = new NDEFReader();
    193  const promises = [];
    194  invalid_signals.forEach(invalid_signal => {
    195    promises.push(promise_rejects_js(t, TypeError,
    196        ndef.write(test_text_data, { signal: invalid_signal })));
    197  });
    198  await Promise.all(promises);
    199 }, "NDEFReader.write should fail if signal is not an AbortSignal.");
    200 
    201 nfc_test(async (t, mockNFC) => {
    202  const ndef1 = new NDEFReader();
    203  const ndef2 = new NDEFReader();
    204  const controller = new AbortController();
    205  const p1 = ndef1.write(test_text_data, { signal: controller.signal });
    206 
    207  // Even though write request is grantable,
    208  // this abort should be processed synchronously.
    209  controller.abort();
    210  await promise_rejects_dom(t, 'AbortError', p1);
    211 
    212  await ndef2.write(test_text_data);
    213  assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
    214 }, "Synchronously signaled abort.");
    215 
    216 nfc_test(async (t, mockNFC) => {
    217  const ndef = new NDEFReader();
    218  mockNFC.setHWStatus(NFCHWStatus.DISABLED);
    219  await promise_rejects_dom(t, 'NotReadableError', ndef.write(test_text_data));
    220 }, "NDEFReader.write should fail when NFC HW is disabled.");
    221 
    222 nfc_test(async (t, mockNFC) => {
    223  const ndef = new NDEFReader();
    224  mockNFC.setHWStatus(NFCHWStatus.NOT_SUPPORTED);
    225  await promise_rejects_dom(t, 'NotSupportedError', ndef.write(test_text_data));
    226 }, "NDEFReader.write should fail when NFC HW is not supported.");
    227 
    228 nfc_test(async () => {
    229  await new Promise((resolve,reject) => {
    230    const iframe = document.createElement('iframe');
    231    iframe.srcdoc = `<script>
    232                      window.onmessage = async (message) => {
    233                        if (message.data === "Ready") {
    234                          try {
    235                            const ndef = new NDEFReader();
    236                            await ndef.write("Test");
    237                            parent.postMessage("Failure", "*");
    238                          } catch (error) {
    239                            if (error.name == "InvalidStateError") {
    240                              parent.postMessage("Success", "*");
    241                            } else {
    242                              parent.postMessage("Failure", "*");
    243                            }
    244                          }
    245                        }
    246                      };
    247                    <\/script>`;
    248    iframe.onload = () => iframe.contentWindow.postMessage('Ready', '*');
    249    document.body.appendChild(iframe);
    250    window.onmessage = message => {
    251      if (message.data == 'Success') {
    252        resolve();
    253      } else if (message.data == 'Failure') {
    254        reject();
    255      }
    256    }
    257  });
    258 }, 'Test that WebNFC API is not accessible from iframe context.');
    259 
    260 nfc_test(async () => {
    261  const ndef = new NDEFReader();
    262  await ndef.write(test_text_data);
    263 }, 'NDEFReader.write should succeed when NFC HW is enabled');
    264 
    265 nfc_test(async (t, mockNFC) => {
    266  const ndef = new NDEFReader();
    267  const message = createMessage([createTextRecord(test_text_data),
    268                               createMimeRecordFromJson(test_json_data),
    269                               createMimeRecord(test_buffer_data),
    270                               createUnknownRecord(test_buffer_data),
    271                               createUrlRecord(test_url_data),
    272                               createUrlRecord(test_url_data, true),
    273                               createRecord('w3.org:xyz', test_buffer_data)],
    274                               test_message_origin);
    275  await ndef.write(message);
    276  assertNDEFMessagesEqual(message, mockNFC.pushedMessage());
    277 }, "NDEFReader.write NDEFMessage containing text, mime, unknown, url, absolute-url \
    278 and external records with default NDEFWriteOptions.");
    279 
    280 nfc_test(async (t, mockNFC) => {
    281  const messageContainText = createMessage([createTextRecord(test_text_data)]);
    282 
    283  // Prepare a local type record that uses |messageContainText| as its payload.
    284  const messageContainLocal = createMessage([createRecord(':containsTextRecord', messageContainText)]);
    285 
    286  // Prepare an external type record that uses |messageContainLocal| as its payload.
    287  const message = createMessage([createRecord('example.com:containsLocalRecord', messageContainLocal)]);
    288 
    289  const ndef = new NDEFReader();
    290  await ndef.write(message);
    291  const pushed_message = mockNFC.pushedMessage();
    292 
    293  // The mojom message received by mock nfc contains only the external type record.
    294  assert_equals(pushed_message.data.length, 1);
    295  assert_equals(pushed_message.data[0].recordType, 'example.com:containsLocalRecord', 'recordType');
    296 
    297  // The external type record's payload is from the original |messageContainLocal|,
    298  // containing only the local type record.
    299  assert_array_equals(pushed_message.data[0].data, new Uint8Array(0),
    300      'payloadMessage is used instead');
    301  assert_equals(pushed_message.data[0].payloadMessage.data.length, 1);
    302  assert_equals(pushed_message.data[0].payloadMessage.data[0].recordType, ':containsTextRecord', 'recordType');
    303 
    304  // The local type record's payload is from the original |messageContainText|,
    305  // containing only the text record.
    306  assert_array_equals(pushed_message.data[0].payloadMessage.data[0].data, new Uint8Array(0),
    307      'payloadMessage is used instead');
    308  assertNDEFMessagesEqual(messageContainText, pushed_message.data[0].payloadMessage.data[0].payloadMessage);
    309 }, "NDEFReader.write NDEFMessage containing embedded records.");
    310 
    311 nfc_test(async (t, mockNFC) => {
    312  // A smart-poster record contains a uri record, text record.
    313  const uri_record = createUrlRecord(test_url_data);
    314  const text_record = createTextRecord(test_text_data);
    315  const payload_message = createMessage([uri_record, text_record]);
    316  const message = createMessage([createRecord(
    317      'smart-poster', payload_message, "dummy_record_id")]);
    318 
    319  const ndef = new NDEFReader();
    320  await ndef.write(message);
    321  const pushed_message = mockNFC.pushedMessage();
    322 
    323  // The mojom message received by mock nfc contains only the smart-poster record.
    324  assert_equals(pushed_message.data.length, 1);
    325  assert_equals(pushed_message.data[0].recordType, 'smart-poster', 'recordType');
    326  assert_equals(pushed_message.data[0].mediaType, null, 'mediaType');
    327  assert_equals(pushed_message.data[0].id, 'dummy_record_id', 'id');
    328 
    329  const embedded_records = pushed_message.data[0].payloadMessage.data;
    330  assert_equals(embedded_records.length, 2);
    331 
    332  let embedded_record_types = [];
    333  for(let record of embedded_records) {
    334    embedded_record_types.push(record.recordType);
    335    switch(record.recordType) {
    336      case 'url':
    337        compareNDEFRecords(uri_record, record);
    338        break;
    339      case 'text':
    340        compareNDEFRecords(text_record, record);
    341        break;
    342      default:
    343        assert_unreached("Unknown recordType");
    344    }
    345  }
    346  assert_array_equals(embedded_record_types.sort(), ['text', 'url'],
    347      'smart-poster record\'s contained record types');
    348 }, "NDEFReader.write NDEFMessage containing smart-poster record.");
    349 
    350 nfc_test(async (t, mockNFC) => {
    351  const ndef = new NDEFReader();
    352  await ndef.write(test_text_data);
    353  assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
    354 }, "Test that NDEFReader.write succeeds when message is DOMString.");
    355 
    356 nfc_test(async (t, mockNFC) => {
    357  const ndef = new NDEFReader();
    358  await ndef.write(test_buffer_data);
    359  assertNDEFMessagesEqual(test_buffer_data, mockNFC.pushedMessage());
    360 }, "Test that NDEFReader.write succeeds when message is ArrayBuffer.");
    361 
    362 nfc_test(async (t, mockNFC) => {
    363  let buffer_view = new Uint8Array(test_buffer_data, 2, 5);
    364  const ndef = new NDEFReader();
    365  await ndef.write(buffer_view);
    366  assertNDEFMessagesEqual(buffer_view, mockNFC.pushedMessage());
    367 }, "Test that NDEFReader.write succeeds when message is ArrayBufferView.");
    368 
    369 nfc_test(async (t, mockNFC) => {
    370  const ndef = new NDEFReader();
    371  await ndef.write(createMessage([createRecord('empty')]));
    372  const receivedMessage = mockNFC.pushedMessage();
    373  assert_equals(receivedMessage.data.length, 1);
    374  assert_equals(receivedMessage.data[0].recordType, 'empty', 'recordType');
    375 }, "NDEFReader.write with 'empty' record should succeed.");
    376 
    377 nfc_test(async (t, mockNFC) => {
    378  const ndef = new NDEFReader();
    379  await ndef.write(test_text_data);
    380  assertNDEFWriteOptionsEqual({overwrite: true}, mockNFC.writeOptions());
    381 }, "Check that default NDEFWriteOptions values are correctly set.");
    382 
    383 nfc_test(async (t, mockNFC) => {
    384  const ndef = new NDEFReader();
    385  await ndef.write(test_text_data, {overwrite: false});
    386  assertNDEFWriteOptionsEqual({overwrite: false}, mockNFC.writeOptions());
    387 }, "Check that provided NDEFWriteOptions values are correctly converted.");
    388 
    389 nfc_test(async (t, mockNFC) => {
    390  const ndef1 = new NDEFReader();
    391  const ndef2 = new NDEFReader();
    392 
    393  const p1 = ndef1.write(test_text_data, {overwrite: false});
    394  const p2 = ndef2.write(test_url_data, {overwrite: true});
    395 
    396  await new Promise((resolve, reject) => {
    397    // Make first push pending
    398    mockNFC.setPendingPushCompleted(false);
    399    let err = "";
    400    p1.then(() => {
    401      reject("pending push should not be fulfilled");
    402    }).catch(e => {
    403      err = e.name;
    404    });
    405    p2.then(() => {
    406      assertNDEFMessagesEqual(test_url_data, mockNFC.pushedMessage());
    407      assertNDEFWriteOptionsEqual( {overwrite: true}, mockNFC.writeOptions());
    408      assert_equals(err, "AbortError", "the pending push should be aborted");
    409      resolve();
    410    });
    411  });
    412 }, "NDEFReader.write should replace all previously configured write operations.");
    413 
    414 nfc_test(async () => {
    415  const ndef = new NDEFReader();
    416 
    417  const controller1 = new AbortController();
    418  await ndef.write(test_text_data, {signal: controller1.signal});
    419 
    420  const controller2 = new AbortController();
    421  const promise = ndef.write(test_text_data, {signal: controller2.signal});
    422  controller1.abort();
    423  await promise;
    424 }, 'NDEFReader.write signals are independent.');
    425 
    426 nfc_test(async (t, mockNFC) => {
    427  const ndef = new NDEFReader();
    428  await ndef.write({ records: [{ recordType: "mime", data: test_buffer_data }] });
    429  assertNDEFMessagesEqual(test_buffer_data, mockNFC.pushedMessage());
    430 }, "Test that mediaType should be set to 'application/octet-stream' if \
    431 NDEFRecordInit.record's recordType is 'mime' and NDEFRecordInit.record's \
    432 mediaType is undefined.");
    433 
    434 nfc_test(async (t, mockNFC) => {
    435  // Make sure the push will be pending in the mock.
    436  mockNFC.setPendingPushCompleted(false);
    437 
    438  const ndef1 = new NDEFReader();
    439  const promise = ndef1.write(test_text_data);
    440 
    441  // Just to make sure the write() request has already reached to the mock.
    442  const ndef2 = new NDEFReader();
    443  await ndef2.scan();
    444 
    445  mockNFC.simulateNonNDEFTagDiscovered();
    446  await promise_rejects_dom(t, 'NotSupportedError', promise);
    447 }, "NDEFReader.write should fail when the NFC device coming up does not expose \
    448 NDEF technology.");
    449 
    450 nfc_test(async (t, mockNFC) => {
    451  const ndef = new NDEFReader();
    452  await ndef.write(test_text_data, {overwrite: false});
    453  assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
    454 }, "NDEFReader.write should succeed to write data to an unformatted NFC device \
    455 when the NDEFWriteOptions.overwrite is false.");
    456 
    457 nfc_test(async (t, mockNFC) => {
    458  const ndef = new NDEFReader();
    459  await ndef.write(test_buffer_data);
    460  assertNDEFMessagesEqual(test_buffer_data, mockNFC.pushedMessage());
    461  await ndef.write(test_text_data, {overwrite: true});
    462  assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
    463 }, "NDEFReader.write should succeed to overwrite the existing data \
    464 when the NDEFWriteOptions.overwrite is true.");
    465 
    466 nfc_test(async (t, mockNFC) => {
    467  const ndef = new NDEFReader();
    468  const p = ndef.write(test_text_data, {overwrite: false});
    469  mockNFC.setIsFormattedTag(true);
    470  await promise_rejects_dom(t, 'NotAllowedError', p);
    471 }, "NDEFReader.write should fail when there are NDEF records on the NFC device \
    472 and NDEFWriteOptions.overwrite is false.");
    473 
    474 nfc_test(async (t, mockNFC) => {
    475  const ndef = new NDEFReader();
    476  mockNFC.simulateDataTransferFails();
    477  await promise_rejects_dom(t, 'NetworkError', ndef.write(test_text_data));
    478 }, "NDEFReader.write should fail with NetworkError when NFC data transfer fails.");
    479 
    480 </script>