mirror of
https://github.com/servo/servo.git
synced 2025-07-30 10:40:27 +01:00
175 lines
7.5 KiB
HTML
175 lines
7.5 KiB
HTML
<!DOCTYPE html>
|
|
<meta charset="utf-8">
|
|
<title>KV Storage: IDL interface tests</title>
|
|
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="/resources/WebIDLParser.js"></script>
|
|
<script src="/resources/idlharness.js"></script>
|
|
|
|
<script type="module">
|
|
import storage, { StorageArea } from "std:kv-storage";
|
|
|
|
// Web IDL/idlharness.js do not yet have support for the spec's IDL, which uses module {},
|
|
// async_iterator, and some new extended attributes. This IDL is a mutated version to work with the
|
|
// current idlharness.js to get some coverage.
|
|
//
|
|
// When the relevant Web IDL PRs land and idlharness.js gets updated, we can replace this file with
|
|
// a normal-style idlharness test, with the IDL scraped from the spec.
|
|
//
|
|
// Other tests in this file are similarly ones that should be generatable from the IDL, in theory.
|
|
|
|
const idl = `
|
|
[Constructor(DOMString name)]
|
|
interface StorageArea {
|
|
Promise<void> set(any key, any value);
|
|
Promise<any> get(any key);
|
|
Promise<void> delete(any key);
|
|
Promise<void> clear();
|
|
|
|
// async_iterable<any, any>;
|
|
|
|
[SameObject] readonly attribute object backingStore;
|
|
};
|
|
`;
|
|
|
|
// Define a global property because idlharness.js only understands
|
|
// global properties, not modules.
|
|
Object.defineProperty(window, "StorageArea", {
|
|
configurable: true,
|
|
enumerable: false,
|
|
writable: true,
|
|
value: StorageArea
|
|
});
|
|
|
|
test(t => {
|
|
window.testStorageArea = storage;
|
|
t.add_cleanup(() => {
|
|
delete window.testStorageArea;
|
|
});
|
|
|
|
const idlArray = new IdlArray();
|
|
idlArray.add_idls(idl);
|
|
idlArray.add_objects({ StorageArea: ["window.testStorageArea"] });
|
|
idlArray.test();
|
|
}, "idlharness basic interface tests");
|
|
|
|
test(() => {
|
|
assert_equals(storage instanceof StorageArea, true, "instanceof");
|
|
assert_equals(storage.constructor, StorageArea, ".constructor property");
|
|
assert_equals(Object.getPrototypeOf(storage), StorageArea.prototype, "[[Prototype]]");
|
|
}, "Built-in storage export is a StorageArea");
|
|
|
|
// These should be auto-tested by idlharness eventually, similar to
|
|
// https://github.com/web-platform-tests/wpt/blob/3725067ef0328c998be2ba93dbaeb0579586fccd/resources/idlharness.js#L2452
|
|
// for sync iterators (although this tests more than that does).
|
|
test(() => {
|
|
for (const methodName of ["keys", "values", "entries"]) {
|
|
const descriptor = Object.getOwnPropertyDescriptor(StorageArea.prototype, methodName);
|
|
|
|
assert_true(descriptor.writable, `${methodName} property should be writable`);
|
|
assert_true(descriptor.configurable, `${methodName} property should be configurable`);
|
|
|
|
// May need updating if https://github.com/heycam/webidl/issues/738 changes the spec
|
|
assert_true(descriptor.enumerable, `${methodName} property should be enumerable`);
|
|
|
|
assert_equals(typeof descriptor.value, "function",
|
|
`${methodName} property should be a function`);
|
|
assert_equals(descriptor.value.length, 0, `${methodName} function object length should be 0`);
|
|
assert_equals(descriptor.value.name, methodName,
|
|
`${methodName} function object should have the right name`);
|
|
|
|
assert_throws(new TypeError(), () => descriptor.value.call(StorageArea.prototype),
|
|
`${methodName} should throw when called on the prototype directly`);
|
|
assert_throws(new TypeError(), () => descriptor.value.call({}),
|
|
`${methodName} should throw when called on an empty object`);
|
|
}
|
|
|
|
const AsyncIteratorPrototype =
|
|
Object.getPrototypeOf(Object.getPrototypeOf(async function*() {}).prototype);
|
|
const asyncIteratorProto = Object.getPrototypeOf(storage.keys());
|
|
assert_equals(Object.getPrototypeOf(storage.values()), asyncIteratorProto,
|
|
"keys() and values() return values must have the same prototype");
|
|
assert_equals(Object.getPrototypeOf(storage.entries()), asyncIteratorProto,
|
|
"keys() and entries() return values must have the same prototype");
|
|
|
|
assert_equals(Object.getPrototypeOf(asyncIteratorProto), AsyncIteratorPrototype,
|
|
"[[Prototype]] must be the async iterator prototype");
|
|
|
|
assert_array_equals(Object.getOwnPropertyNames(asyncIteratorProto), ["next"],
|
|
`async iterator prototype object must have a next method`);
|
|
|
|
const nextMethodDescriptor = Object.getOwnPropertyDescriptor(asyncIteratorProto, "next");
|
|
assert_true(nextMethodDescriptor.writable, `async iterator next property should be writable`);
|
|
assert_true(nextMethodDescriptor.configurable,
|
|
`async iterator next property should be configurable`);
|
|
|
|
// May need updating if https://github.com/heycam/webidl/issues/739 changes the spec
|
|
assert_true(nextMethodDescriptor.enumerable,
|
|
`async iterator next property should be enumerable`);
|
|
|
|
assert_equals(typeof nextMethodDescriptor.value, "function",
|
|
`async iterator next property should be a function`);
|
|
assert_equals(nextMethodDescriptor.value.length, 0,
|
|
`async iterator next function object length should be 0`);
|
|
assert_equals(nextMethodDescriptor.value.name, "next",
|
|
`async iterator next function object should have the right name`);
|
|
|
|
assert_array_equals(Object.getOwnPropertySymbols(asyncIteratorProto), [Symbol.toStringTag]);
|
|
const toStringTagDescriptor = Object.getOwnPropertyDescriptor(
|
|
asyncIteratorProto,
|
|
Symbol.toStringTag
|
|
);
|
|
assert_false(toStringTagDescriptor.writable,
|
|
`async iterator @@toStringTag property should be non-writable`);
|
|
assert_true(toStringTagDescriptor.configurable,
|
|
`async iterator @@toStringTag property should be configurable`);
|
|
assert_false(toStringTagDescriptor.enumerable,
|
|
`async iterator @@toStringTag property should be non-enumerable`);
|
|
assert_equals(toStringTagDescriptor.value, "StorageArea AsyncIterator",
|
|
`async iterator @@toStringTag property should have the right value`);
|
|
|
|
assert_equals(StorageArea.prototype[Symbol.asyncIterator], StorageArea.prototype.entries,
|
|
"@@asyncIterator method should be the same as entries");
|
|
}, "@@asyncIterator tests");
|
|
|
|
promise_test(async t => {
|
|
const iframe = document.createElement("iframe");
|
|
iframe.src = "helpers/expose-as-global.html";
|
|
document.body.append(iframe);
|
|
|
|
await frameLoadPromise(iframe);
|
|
const OtherStorageArea = iframe.contentWindow.StorageArea;
|
|
|
|
await promise_rejects(t, new TypeError(),
|
|
OtherStorageArea.prototype.set.call(storage, "testkey", "testvalue"),
|
|
`set() must reject cross-realm`);
|
|
await promise_rejects(t, new TypeError(),
|
|
OtherStorageArea.prototype.get.call(storage, "testkey"),
|
|
`get() must reject cross-realm`);
|
|
await promise_rejects(t, new TypeError(),
|
|
OtherStorageArea.prototype.delete.call(storage, "testkey"),
|
|
`delete() must reject cross-realm`);
|
|
await promise_rejects(t, new TypeError(), OtherStorageArea.prototype.clear.call(storage),
|
|
`clear() must reject cross-realm`);
|
|
|
|
assert_throws(new TypeError(), () => OtherStorageArea.prototype.keys.call(storage),
|
|
`keys() must throw cross-realm`);
|
|
assert_throws(new TypeError(), () => OtherStorageArea.prototype.values.call(storage),
|
|
`values() must throw cross-realm`);
|
|
assert_throws(new TypeError(), () => OtherStorageArea.prototype.entries.call(storage),
|
|
`entries() must throw cross-realm`);
|
|
|
|
const otherBackingStoreGetter =
|
|
Object.getOwnPropertyDescriptor(OtherStorageArea.prototype, "backingStore").get;
|
|
assert_throws(new TypeError(), () => otherBackingStoreGetter.call(storage),
|
|
`backingStore must throw cross-realm`);
|
|
}, "Same-realm brand checks");
|
|
|
|
function frameLoadPromise(frame) {
|
|
return new Promise((resolve, reject) => {
|
|
frame.onload = resolve;
|
|
frame.onerror = () => reject(new Error(`${frame.src} failed to load`));
|
|
});
|
|
}
|
|
</script>
|