mirror of
https://github.com/servo/servo.git
synced 2025-06-29 19:43:39 +01:00
449 lines
18 KiB
HTML
449 lines
18 KiB
HTML
<!DOCTYPE html>
|
|
<meta charset=utf-8>
|
|
<title>Web NFC: NDEFWriter.push Tests</title>
|
|
<link rel="author" title="Intel" href="http://www.intel.com"/>
|
|
<link rel="help" href="https://w3c.github.io/web-nfc/"/>
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="resources/nfc-helpers.js"></script>
|
|
<script>
|
|
|
|
"use strict";
|
|
|
|
const invalid_type_messages =
|
|
[
|
|
// Invalid NDEFMessageSource type
|
|
undefined,
|
|
|
|
// NDEFMessage.records: should have at least 1 valid record.
|
|
// https://w3c.github.io/web-nfc/#the-push-method - Step 8.
|
|
createMessage([{}]),
|
|
|
|
// NDEFMessageSource: not NDEF-formatable.
|
|
// https://w3c.github.io/web-nfc/#the-push-method - Step 8.
|
|
createMessage([]),
|
|
|
|
// https://w3c.github.io/web-nfc/#dfn-map-text-to-ndef
|
|
// NDEFRecord must have data.
|
|
createMessage([createTextRecord()]),
|
|
|
|
// NDEFRecord.data for 'text' record must be either a string,
|
|
// an arrayBuffer, or an arrayBufferView.
|
|
createMessage([createTextRecord(test_json_data)]),
|
|
|
|
// NDEFRecord.encoding for 'text' record must be either "utf-8",
|
|
// "utf-16", "utf-16le" or "utf-16be".
|
|
createMessage([createTextRecord(test_text_data, "chinese")]),
|
|
|
|
// NDEFRecord.lang length for 'text' record must be lower than 64.
|
|
createMessage([createTextRecord(test_text_data, undefined /* encoding */, [...Array(64)].map(_ => 'a'))]),
|
|
|
|
// https://w3c.github.io/web-nfc/#dfn-map-a-url-to-ndef
|
|
// NDEFRecord must have data.
|
|
createMessage([createUrlRecord()]),
|
|
|
|
// https://w3c.github.io/web-nfc/#dfn-map-a-url-to-ndef
|
|
// NDEFRecord must have data.
|
|
createMessage([createUrlRecord(undefined, true)]),
|
|
|
|
// NDEFRecord.data for 'url' record must be string.
|
|
createMessage([createUrlRecord(test_buffer_data)]),
|
|
createMessage([createUrlRecord(test_json_data)]),
|
|
|
|
// NDEFRecord.data for 'absolute-url' record must be string.
|
|
createMessage([createUrlRecord(test_buffer_data, true)]),
|
|
createMessage([createUrlRecord(test_json_data, true)]),
|
|
|
|
// https://w3c.github.io/web-nfc/#dfn-map-binary-data-to-ndef
|
|
// NDEFRecord must have data.
|
|
createMessage([createMimeRecord()]),
|
|
|
|
// NDEFRecord.data for 'mime' record must be BufferSource.
|
|
createMessage([createMimeRecord(test_text_data)]),
|
|
createMessage([createMimeRecord(test_number_data)]),
|
|
createMessage([createMimeRecord(test_json_data)]),
|
|
|
|
// NDEFRecord must have data.
|
|
createMessage([createUnknownRecord()]),
|
|
|
|
// NDEFRecord.data for 'unknown' record must be BufferSource.
|
|
createMessage([createUnknownRecord(test_text_data)]),
|
|
createMessage([createUnknownRecord(test_number_data)]),
|
|
createMessage([createUnknownRecord(test_json_data)]),
|
|
|
|
// https://w3c.github.io/web-nfc/#dfn-map-external-data-to-ndef
|
|
// NDEFRecord must have data.
|
|
createMessage([createRecord('w3.org:xyz')]),
|
|
|
|
// NDEFRecord.data for external record must be ArrayBuffer.
|
|
createMessage([createRecord('w3.org:xyz', test_text_data)]),
|
|
createMessage([createRecord('w3.org:xyz', test_number_data)]),
|
|
createMessage([createRecord('w3.org:xyz', test_json_data)]),
|
|
|
|
// https://w3c.github.io/web-nfc/#ndef-record-types
|
|
// The record type is neither a known type ('text', 'mime' etc.) nor a
|
|
// valid custom type for an external type record.
|
|
createMessage([createRecord('unmatched_type', test_buffer_data)])
|
|
];
|
|
|
|
const invalid_syntax_messages =
|
|
[
|
|
// Data for 'url' or 'absolute-url' record, must be a valid URL.
|
|
createMessage([createUrlRecord('Invalid URL:// Data')]),
|
|
createMessage([createUrlRecord('Invalid URL:// Data', true)]),
|
|
];
|
|
|
|
const invalid_signals = [
|
|
"string",
|
|
123,
|
|
{},
|
|
true,
|
|
Symbol(),
|
|
() => {},
|
|
self
|
|
];
|
|
|
|
promise_test(async t => {
|
|
const writer = new NDEFWriter();
|
|
const promises = [];
|
|
invalid_type_messages.forEach(message => {
|
|
promises.push(
|
|
promise_rejects(t, new TypeError(), writer.push(message)));
|
|
});
|
|
await Promise.all(promises);
|
|
}, "Test that promise is rejected with TypeError if NDEFMessageSource is invalid.");
|
|
|
|
promise_test(async t => {
|
|
const writer = new NDEFWriter();
|
|
const promises = [];
|
|
invalid_syntax_messages.forEach(message => {
|
|
promises.push(
|
|
promise_rejects(t, 'SyntaxError', writer.push(message)));
|
|
});
|
|
await Promise.all(promises);
|
|
}, "Test that promise is rejected with SyntaxError if NDEFMessageSource contains\
|
|
invalid records.");
|
|
|
|
promise_test(async t => {
|
|
if (window.testRunner) {
|
|
// Deny nfc permissions for Chromium testrunner.
|
|
window.testRunner.setPermission('nfc', 'denied',
|
|
location.origin, location.origin);
|
|
}
|
|
const writer = new NDEFWriter();
|
|
await promise_rejects(t, 'NotAllowedError', writer.push(test_text_data));
|
|
}, 'NDEFWriter.push should fail if user permission is not granted.');
|
|
|
|
// We do not provide NFC mock here to simulate that there has no available
|
|
// implementation for NFC Mojo interface.
|
|
promise_test(async t => {
|
|
if (window.testRunner) {
|
|
// Deny nfc permissions for Chromium testrunner.
|
|
window.testRunner.setPermission('nfc', 'granted',
|
|
location.origin, location.origin);
|
|
}
|
|
const writer = new NDEFWriter();
|
|
await promise_rejects(t, 'NotSupportedError', writer.push(test_text_data));
|
|
}, 'NDEFWriter.push should fail if no implementation for NFC Mojo interface is available.');
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer = new NDEFWriter();
|
|
const controller = new AbortController();
|
|
|
|
//Make sure push is pending
|
|
mockNFC.setPendingPushCompleted(false);
|
|
const p = writer.push(test_text_data, { signal: controller.signal });
|
|
const rejected = promise_rejects(t, 'AbortError', p);
|
|
let callback_called = false;
|
|
await new Promise(resolve => {
|
|
t.step_timeout(() => {
|
|
callback_called = true;
|
|
controller.abort();
|
|
resolve();
|
|
}, 10);
|
|
});
|
|
await rejected;
|
|
assert_true(callback_called, 'timeout should have caused the abort');
|
|
}, "NDEFWriter.push should fail if abort push request before push happends.");
|
|
|
|
promise_test(async t => {
|
|
const writer = new NDEFWriter();
|
|
const controller = new AbortController();
|
|
assert_false(controller.signal.aborted);
|
|
controller.abort();
|
|
assert_true(controller.signal.aborted);
|
|
await promise_rejects(t, 'AbortError',
|
|
writer.push(test_text_data, { signal: controller.signal }));
|
|
}, "NDEFWriter.push should fail if signal's aborted flag is set.");
|
|
|
|
promise_test(async t => {
|
|
const writer = new NDEFWriter();
|
|
const promises = [];
|
|
invalid_signals.forEach(invalid_signal => {
|
|
promises.push(promise_rejects(t, new TypeError(),
|
|
writer.push(test_text_data, { signal: invalid_signal })));
|
|
});
|
|
await Promise.all(promises);
|
|
}, "NDEFWriter.push should fail if signal is not an AbortSignal.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer1 = new NDEFWriter();
|
|
const writer2 = new NDEFWriter();
|
|
const controller = new AbortController();
|
|
const p1 = writer1.push(test_text_data, { signal: controller.signal });
|
|
|
|
// Even though push request is grantable,
|
|
// this abort should be processed synchronously.
|
|
controller.abort();
|
|
await promise_rejects(t, 'AbortError', p1);
|
|
|
|
await writer2.push(test_text_data);
|
|
assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
|
|
}, "Synchronously signaled abort.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer = new NDEFWriter();
|
|
mockNFC.setHWStatus(NFCHWStatus.DISABLED);
|
|
await promise_rejects(t, 'NotReadableError', writer.push(test_text_data));
|
|
}, "NDEFWriter.push should fail when NFC HW is disabled.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer = new NDEFWriter();
|
|
mockNFC.setHWStatus(NFCHWStatus.NOT_SUPPORTED);
|
|
await promise_rejects(t, 'NotSupportedError', writer.push(test_text_data));
|
|
}, "NDEFWriter.push should fail when NFC HW is not supported.");
|
|
|
|
promise_test(async t => {
|
|
const writer = new NDEFWriter();
|
|
await promise_rejects(
|
|
t, 'NotSupportedError', writer.push(new ArrayBuffer(32 * 1024 + 1)));
|
|
}, "Reject promise with NotSupportedError if NFC message size exceeds 32KB.");
|
|
|
|
promise_test(async t => {
|
|
const writer = new NDEFWriter();
|
|
await promise_rejects(
|
|
t, new TypeError(), writer.push(test_text_data, {target: "invalid"}));
|
|
}, "NDEFWriter.push should fail with TypeError when invalid target value is \
|
|
provided.");
|
|
|
|
promise_test(async () => {
|
|
await new Promise((resolve,reject) => {
|
|
const iframe = document.createElement('iframe');
|
|
iframe.srcdoc = `<script>
|
|
if (window.testRunner) {
|
|
// Grant nfc permissions for Chromium testrunner.
|
|
window.testRunner.setPermission('nfc', 'granted',
|
|
location.origin, location.origin);
|
|
}
|
|
window.onmessage = message => {
|
|
if (message.data === "Ready") {
|
|
const onSuccess = () => {
|
|
parent.postMessage("Failure", "*");
|
|
};
|
|
const onError = error => {
|
|
if (error.name == "NotAllowedError") {
|
|
parent.postMessage("Success", "*");
|
|
} else {
|
|
parent.postMessage("Failure", "*");
|
|
}
|
|
};
|
|
try {
|
|
const writer = new NDEFWriter();
|
|
writer.push("Test").then(onSuccess, onError);
|
|
} catch(e) {
|
|
parent.postMessage("Failure", "*");
|
|
}
|
|
}
|
|
};
|
|
<\/script>`;
|
|
iframe.onload = () => iframe.contentWindow.postMessage('Ready', '*');
|
|
document.body.appendChild(iframe);
|
|
window.onmessage = message => {
|
|
if (message.data == 'Success') {
|
|
resolve();
|
|
} else if (message.data == 'Failure') {
|
|
reject();
|
|
}
|
|
}
|
|
});
|
|
}, 'Test that WebNFC API is not accessible from iframe context.');
|
|
|
|
nfc_test(async () => {
|
|
const writer = new NDEFWriter();
|
|
await writer.push(test_text_data);
|
|
}, 'NDEFWriter.push should succeed when NFC HW is enabled');
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer = new NDEFWriter();
|
|
let message = createMessage([createTextRecord(test_text_data),
|
|
createMimeRecordFromJson(test_json_data),
|
|
createMimeRecord(test_buffer_data),
|
|
createUnknownRecord(test_buffer_data),
|
|
createUrlRecord(test_url_data),
|
|
createUrlRecord(test_url_data, true),
|
|
createRecord('w3.org:xyz', test_buffer_data)],
|
|
test_message_origin);
|
|
await writer.push(message);
|
|
assertNDEFMessagesEqual(message, mockNFC.pushedMessage());
|
|
}, "NDEFWriter.push NDEFMessage containing text, mime, unknown, url, absolute-url \
|
|
and external records with default NDEFPushOptions.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer = new NDEFWriter();
|
|
await writer.push(test_text_data);
|
|
assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
|
|
}, "Test that NDEFWriter.push succeeds when message is DOMString.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer = new NDEFWriter();
|
|
await writer.push(test_buffer_data);
|
|
assertNDEFMessagesEqual(test_buffer_data, mockNFC.pushedMessage());
|
|
}, "Test that NDEFWriter.push succeeds when message is ArrayBuffer.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
let buffer_view = new Uint8Array(test_buffer_data, 2, 5);
|
|
const writer = new NDEFWriter();
|
|
await writer.push(buffer_view);
|
|
assertNDEFMessagesEqual(buffer_view, mockNFC.pushedMessage());
|
|
}, "Test that NDEFWriter.push succeeds when message is ArrayBufferView.");
|
|
|
|
nfc_test(async () => {
|
|
const writer = new NDEFWriter();
|
|
await writer.push(createMessage([createRecord('empty')]));
|
|
}, "NDEFWriter.push with 'empty' record should succeed.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer = new NDEFWriter();
|
|
await writer.push(test_text_data);
|
|
assertNDEFPushOptionsEqual(createNDEFPushOptions('any', true),
|
|
mockNFC.pushOptions());
|
|
}, "Check that default NDEFPushOptions values are correctly set.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer = new NDEFWriter();
|
|
let ndefPushOptions = createNDEFPushOptions('tag', false);
|
|
await writer.push(test_text_data, ndefPushOptions);
|
|
assertNDEFPushOptionsEqual(ndefPushOptions, mockNFC.pushOptions());
|
|
}, "Check that provided NDEFPushOptions values are correctly converted.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const reader = new NDEFReader();
|
|
const message = createMessage([createTextRecord(test_text_data)]);
|
|
const controller = new AbortController();
|
|
const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]);
|
|
await reader.scan({ signal: controller.signal });
|
|
|
|
const writer = new NDEFWriter();
|
|
await writer.push(test_text_data, { ignoreRead: false });
|
|
assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
|
|
|
|
mockNFC.setReadingMessage(message);
|
|
await readerWatcher.wait_for("reading").then(event => {
|
|
controller.abort();
|
|
assertWebNDEFMessagesEqual(event.message, new NDEFMessage(message));
|
|
});
|
|
|
|
}, "NDEFWriter.push should read data when ignoreRead is false.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const reader = new NDEFReader();
|
|
const message = createMessage([createTextRecord(test_text_data)]);
|
|
// Ignore reading if NDEFPushOptions.ignoreRead is true
|
|
reader.onreading = t.unreached_func("reading event should not be fired.");
|
|
await reader.scan();
|
|
|
|
const writer = new NDEFWriter();
|
|
await writer.push(test_text_data, { ignoreRead: true });
|
|
mockNFC.setReadingMessage(message);
|
|
assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
|
|
}, "NDEFWriter.push should ignore reading data when ignoreRead is true.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer1 = new NDEFWriter();
|
|
const writer2 = new NDEFWriter();
|
|
|
|
const ndefPushOptions1 = createNDEFPushOptions('tag', false);
|
|
const ndefPushOptions2 = createNDEFPushOptions('tag', true);
|
|
const p1 = writer1.push(test_text_data, ndefPushOptions1);
|
|
const p2 = writer2.push(test_url_data, ndefPushOptions2);
|
|
|
|
await new Promise((resolve, reject) => {
|
|
// Make first push pending
|
|
mockNFC.setPendingPushCompleted(false);
|
|
let err = "";
|
|
p1.then(() => {
|
|
reject("pending push should not be fulfilled");
|
|
}).catch(e => {
|
|
err = e.name;
|
|
});
|
|
p2.then(() => {
|
|
assertNDEFMessagesEqual(test_url_data, mockNFC.pushedMessage());
|
|
assertNDEFPushOptionsEqual(ndefPushOptions2, mockNFC.pushOptions());
|
|
assert_equals(err, "AbortError", "the pending push should be aborted");
|
|
resolve();
|
|
});
|
|
});
|
|
}, "NDEFWriter.push should replace all previously configured push operations.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer = new NDEFWriter();
|
|
await writer.push({ records: [{ data: test_text_data}] });
|
|
assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
|
|
}, "Test that recordType should be set to 'text' if NDEFRecordInit.record's \
|
|
recordType is undefined and NDEFRecordInit.record's data is DOMString.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer = new NDEFWriter();
|
|
await writer.push({ records: [{ data: test_buffer_data}] });
|
|
assertNDEFMessagesEqual(test_buffer_data, mockNFC.pushedMessage());
|
|
}, "Test that recordType should be set to 'mime' if NDEFRecordInit.record's \
|
|
recordType is undefined and NDEFRecordInit.record's data is not DOMString.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer = new NDEFWriter();
|
|
await writer.push({ records: [{ recordType: "mime", data: test_buffer_data }] });
|
|
assertNDEFMessagesEqual(test_buffer_data, mockNFC.pushedMessage());
|
|
}, "Test that mediaType should be set to 'application/octet-stream' if \
|
|
NDEFRecordInit.record's recordType is 'mime' and NDEFRecordInit.record's \
|
|
mediaType is undefined.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
// Make sure the push will be pending in the mock.
|
|
mockNFC.setPendingPushCompleted(false);
|
|
|
|
const writer = new NDEFWriter();
|
|
const promise = writer.push(test_text_data);
|
|
|
|
// Just to make sure the push() request has already reached to the mock.
|
|
const reader = new NDEFReader();
|
|
await reader.scan();
|
|
|
|
mockNFC.simulateNonNDEFTagDiscovered();
|
|
await promise_rejects(t, 'NotSupportedError', promise);
|
|
}, "NDEFWriter.push should fail when the NFC device coming up does not expose \
|
|
NDEF technology.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer = new NDEFWriter();
|
|
await writer.push(test_text_data, { overwrite: false });
|
|
assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
|
|
}, "NDEFWriter.push should succeed to push data to an unformatted NFC device \
|
|
when the NDEFPushOptions.overwrite is false.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer = new NDEFWriter();
|
|
await writer.push(test_buffer_data);
|
|
assertNDEFMessagesEqual(test_buffer_data, mockNFC.pushedMessage());
|
|
await writer.push(test_text_data, { overwrite: true });
|
|
assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
|
|
}, "NDEFWriter.push should succeed to overwrite the existing data \
|
|
when the NDEFPushOptions.overwrite is true.");
|
|
|
|
nfc_test(async (t, mockNFC) => {
|
|
const writer = new NDEFWriter();
|
|
const p = writer.push(test_text_data, { overwrite: false });
|
|
mockNFC.setIsFormattedTag(true);
|
|
await promise_rejects(t, 'NotAllowedError', p);
|
|
}, "NDEFWriter.push should fail when there are NDEF records on the NFC device \
|
|
and NDEFPushOptions.overwrite is false.");
|
|
</script>
|