more WPTs

This commit is contained in:
Florian Dold 2021-02-16 17:18:40 +01:00
parent f9df95ded5
commit c363458374
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
2 changed files with 521 additions and 8 deletions

View File

@ -1,5 +1,5 @@
import test from "ava";
import { createdb, idbFactory } from "./wptsupport";
import { createdb, format_value, idbFactory } from "./wptsupport";
// IDBFactory.open() - request has no source
test("WPT idbfactory-open.htm", async (t) => {
@ -57,19 +57,411 @@ test("WPT idbfactory-open3.htm", async (t) => {
t.pass();
});
// IDBFactory.open() - new database has default version
test("WPT idbfactory-open4.htm", async (t) => {
const indexedDB = idbFactory;
await new Promise<void>((resolve, reject) => {
var open_rq = createdb(t, __filename + '-database_name');
var open_rq = createdb(t, __filename + "-database_name");
open_rq.onupgradeneeded = function(e: any) {
t.deepEqual(e.target.result.version, 1, "db.version");
open_rq.onupgradeneeded = function (e: any) {
t.deepEqual(e.target.result.version, 1, "db.version");
};
open_rq.onsuccess = function(e: any) {
t.deepEqual(e.target.result.version, 1, "db.version");
resolve();
open_rq.onsuccess = function (e: any) {
t.deepEqual(e.target.result.version, 1, "db.version");
resolve();
};
});
t.pass();
});
// IDBFactory.open() - new database is empty
test("WPT idbfactory-open5.htm", async (t) => {
const indexedDB = idbFactory;
await new Promise<void>((resolve, reject) => {
var open_rq = createdb(t, __filename + "-database_name");
open_rq.onupgradeneeded = function () {};
open_rq.onsuccess = function (e: any) {
t.deepEqual(
e.target.result.objectStoreNames.length,
0,
"objectStoreNames.length",
);
resolve();
};
});
t.pass();
});
// IDBFactory.open() - open database with a lower version than current
test("WPT idbfactory-open6.htm", async (t) => {
const indexedDB = idbFactory;
await new Promise<void>((resolve, reject) => {
var open_rq = createdb(t, undefined, 13);
var did_upgrade = false;
var open_rq2: any;
open_rq.onupgradeneeded = function () {};
open_rq.onsuccess = function (e: any) {
var db = e.target.result;
db.close();
open_rq2 = indexedDB.open(db.name, 14);
open_rq2.onupgradeneeded = function () {};
open_rq2.onsuccess = open_previous_db;
open_rq2.onerror = () => t.fail("Unexpected error");
};
function open_previous_db(e: any) {
var open_rq3 = indexedDB.open(e.target.result.name, 13);
open_rq3.onerror = function (e: any) {
t.deepEqual(e.target.error.name, "VersionError", "e.target.error.name");
open_rq2.result.close();
resolve();
};
open_rq3.onupgradeneeded = () => t.fail("Unexpected upgradeneeded");
open_rq3.onsuccess = () => t.fail("Unexpected success");
}
});
t.pass();
});
// IDBFactory.open() - open database with a higher version than current
test("WPT idbfactory-open7.htm", async (t) => {
const indexedDB = idbFactory;
await new Promise<void>((resolve, reject) => {
var open_rq = createdb(t, undefined, 13);
var did_upgrade = false;
var open_rq2: any;
open_rq.onupgradeneeded = function () {};
open_rq.onsuccess = function (e: any) {
var db = e.target.result;
db.close();
open_rq2 = indexedDB.open(db.name, 14);
open_rq2.onupgradeneeded = function () {
did_upgrade = true;
};
open_rq2.onsuccess = open_current_db;
open_rq2.onerror = () => t.fail("Unexpected error");
};
function open_current_db(e: any) {
var open_rq3 = indexedDB.open(e.target.result.name);
open_rq3.onsuccess = function (e: any) {
t.deepEqual(e.target.result.version, 14, "db.version");
open_rq2.result.close();
open_rq3.result.close();
resolve();
};
open_rq3.onupgradeneeded = () => t.fail("Unexpected upgradeneeded");
open_rq3.onerror = () => t.fail("Unexpected error");
t.true(did_upgrade, "did upgrade");
}
});
t.pass();
});
// IDBFactory.open() - error in version change transaction aborts open
test("WPT idbfactory-open8.htm", async (t) => {
const indexedDB = idbFactory;
await new Promise<void>((resolve, reject) => {
var open_rq = createdb(t, undefined, 13);
var did_upgrade = false;
var did_db_abort = false;
open_rq.onupgradeneeded = function (e: any) {
did_upgrade = true;
e.target.result.onabort = function () {
did_db_abort = true;
};
e.target.transaction.abort();
};
open_rq.onerror = function (e: any) {
t.true(did_upgrade);
t.deepEqual(e.target.error.name, "AbortError", "target.error");
resolve();
};
});
t.pass();
});
// IDBFactory.open() - errors in version argument
test("WPT idbfactory-open9.htm", async (t) => {
const indexedDB = idbFactory;
function should_throw(val: any, name?: string) {
if (!name) {
name = typeof val == "object" && val ? "object" : format_value(val);
}
t.throws(
() => {
indexedDB.open("test", val);
},
{ instanceOf: TypeError },
"Calling open() with version argument " +
name +
" should throw TypeError.",
);
}
should_throw(-1);
should_throw(-0.5);
should_throw(0);
should_throw(0.5);
should_throw(0.8);
should_throw(0x20000000000000); // Number.MAX_SAFE_INTEGER + 1
should_throw(NaN);
should_throw(Infinity);
should_throw(-Infinity);
should_throw("foo");
should_throw(null);
should_throw(false);
should_throw({
toString: function () {
t.fail("toString should not be called for ToPrimitive [Number]");
},
valueOf: function () {
return 0;
},
});
should_throw(
{
toString: function () {
return 0;
},
valueOf: function () {
return {};
},
},
"object (second)",
);
should_throw(
{
toString: function () {
return {};
},
valueOf: function () {
return {};
},
},
"object (third)",
);
/* Valid */
async function should_work(val: any, expected_version: number) {
var name = format_value(val);
var dbname = "test-db-does-not-exist";
await t.notThrowsAsync(async () => {
return new Promise<void>((resolve, reject) => {
indexedDB.deleteDatabase(dbname);
var rq = indexedDB.open(dbname, val);
rq.onupgradeneeded = function () {
var db = rq.result;
t.deepEqual(db.version, expected_version, "version");
rq!.transaction!.abort();
};
rq.onsuccess = () => t.fail("open should fail");
rq.onerror = () => resolve();
});
}, "Calling open() with version argument " + name + " should not throw.");
}
await should_work(1.5, 1);
await should_work(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER); // 0x20000000000000 - 1
await should_work(undefined, 1);
});
// IDBFactory.open() - error in version change transaction aborts open
test("WPT idbfactory-open10.htm", async (t) => {
const indexedDB = idbFactory;
await new Promise<void>((resolve, reject) => {
var db: any, db2: any;
var open_rq = createdb(t, undefined, 9);
open_rq.onupgradeneeded = function (e: any) {
db = e.target.result;
var st = db.createObjectStore("store");
st.createIndex("index", "i");
t.deepEqual(db.version, 9, "first db.version");
t.true(
db.objectStoreNames.contains("store"),
"objectStoreNames contains store",
);
t.true(st.indexNames.contains("index"), "indexNames contains index");
st.add({ i: "Joshua" }, 1);
st.add({ i: "Jonas" }, 2);
};
open_rq.onsuccess = function (e) {
db.close();
var open_rq2 = indexedDB.open(db.name, 10);
open_rq2.onupgradeneeded = function (e: any) {
db2 = e.target.result;
db2.createObjectStore("store2");
var store = open_rq2.transaction!.objectStore("store");
store.createIndex("index2", "i");
t.deepEqual(db2.version, 10, "db2.version");
t.true(
db2.objectStoreNames.contains("store"),
"second objectStoreNames contains store",
);
t.true(
db2.objectStoreNames.contains("store2"),
"second objectStoreNames contains store2",
);
t.true(
store.indexNames.contains("index"),
"second indexNames contains index",
);
t.true(
store.indexNames.contains("index2"),
"second indexNames contains index2",
);
store.add({ i: "Odin" }, 3);
store.put({ i: "Sicking" }, 2);
open_rq2.transaction!.abort();
};
open_rq2.onerror = function () {
t.deepEqual(db2.version, 9, "db2.version after error");
t.true(
db2.objectStoreNames.contains("store"),
"objectStoreNames contains store after error",
);
t.false(
db2.objectStoreNames.contains("store2"),
"objectStoreNames not contains store2 after error",
);
var open_rq3 = indexedDB.open(db.name);
open_rq3.onsuccess = function (e: any) {
var db3 = e.target.result;
t.true(
db3.objectStoreNames.contains("store"),
"third objectStoreNames contains store",
);
t.false(
db3.objectStoreNames.contains("store2"),
"third objectStoreNames contains store2",
);
var st = db3.transaction("store").objectStore("store");
t.deepEqual(db3.version, 9, "db3.version");
t.true(
st.indexNames.contains("index"),
"third indexNames contains index",
);
t.false(
st.indexNames.contains("index2"),
"third indexNames contains index2",
);
st.openCursor(null, "prev").onsuccess = function (e: any) {
t.deepEqual(e.target.result.key, 2, "opencursor(prev) key");
t.deepEqual(
e.target.result.value.i,
"Jonas",
"opencursor(prev) value",
);
};
st.get(3).onsuccess = function (e: any) {
t.deepEqual(e.target.result, undefined, "get(3)");
};
var idx = st.index("index");
idx.getKey("Jonas").onsuccess = function (e: any) {
t.deepEqual(e.target.result, 2, "getKey(Jonas)");
};
idx.getKey("Odin").onsuccess = function (e: any) {
t.deepEqual(e.target.result, undefined, "getKey(Odin)");
};
idx.getKey("Sicking").onsuccess = function (e: any) {
t.deepEqual(e.target.result, undefined, "getKey(Sicking)");
db3.close();
resolve();
};
};
};
};
});
t.pass();
});
// IDBFactory.open() - second open's transaction is available to get objectStores
test("WPT idbfactory-open11.htm", async (t) => {
const indexedDB = idbFactory;
await new Promise<void>((resolve, reject) => {
var db: any;
var count_done = 0;
var open_rq = createdb(t);
open_rq.onupgradeneeded = function (e: any) {
db = e.target.result;
db.createObjectStore("store");
assert_true(
db.objectStoreNames.contains("store"),
"objectStoreNames contains store",
);
var store = e.target.transaction.objectStore("store");
assert_equals(store.name, "store", "store.name");
store.add("data", 1);
store.count().onsuccess = this.step_func(function (e) {
assert_equals(e.target.result, 1, "count()");
count_done++;
});
store.add("data2", 2);
};
open_rq.onsuccess = function (e) {
var store = db.transaction("store").objectStore("store");
assert_equals(store.name, "store", "store.name");
store.count().onsuccess = this.step_func(function (e) {
assert_equals(e.target.result, 2, "count()");
count_done++;
});
db.close();
var open_rq2 = indexedDB.open(db.name, 10);
open_rq2.onupgradeneeded = function (e: any) {
var db2 = e.target.result;
t.true(
db2.objectStoreNames.contains("store"),
"objectStoreNames contains store",
);
var store = open_rq2.transaction!.objectStore("store");
t.deepEqual(store.name, "store", "store.name");
store.add("data3", 3);
store.count().onsuccess = function (e: any) {
t.deepEqual(e.target.result, 3, "count()");
count_done++;
t.deepEqual(count_done, 3, "count_done");
db2.close();
resolve();
};
};
};
});
t.pass();

View File

@ -301,3 +301,124 @@ export function createNotBooksStore(
store.createIndex("not_by_title", "title", { unique: true });
return store;
}
/*
* Return a string truncated to the given length, with ... added at the end
* if it was longer.
*/
function truncate(s: string, len: number): string {
if (s.length > len) {
return s.substring(0, len - 3) + "...";
}
return s;
}
var replacements = {
"0": "0",
"1": "x01",
"2": "x02",
"3": "x03",
"4": "x04",
"5": "x05",
"6": "x06",
"7": "x07",
"8": "b",
"9": "t",
"10": "n",
"11": "v",
"12": "f",
"13": "r",
"14": "x0e",
"15": "x0f",
"16": "x10",
"17": "x11",
"18": "x12",
"19": "x13",
"20": "x14",
"21": "x15",
"22": "x16",
"23": "x17",
"24": "x18",
"25": "x19",
"26": "x1a",
"27": "x1b",
"28": "x1c",
"29": "x1d",
"30": "x1e",
"31": "x1f",
"0xfffd": "ufffd",
"0xfffe": "ufffe",
"0xffff": "uffff",
};
/*
* Convert a value to a nice, human-readable string
*/
export function format_value(val: any, seen?: any): string {
if (!seen) {
seen = [];
}
if (typeof val === "object" && val !== null) {
if (seen.indexOf(val) >= 0) {
return "[...]";
}
seen.push(val);
}
if (Array.isArray(val)) {
let output = "[";
// @ts-ignore
if (val.beginEllipsis !== undefined) {
output += "…, ";
}
output += val
.map(function (x) {
return format_value(x, seen);
})
.join(", ");
// @ts-ignore
if (val.endEllipsis !== undefined) {
output += ", …";
}
return output + "]";
}
switch (typeof val) {
case "string":
val = val.replace(/\\/g, "\\\\");
for (var p in replacements) {
// @ts-ignore
var replace = "\\" + replacements[p];
// @ts-ignore
val = val.replace(RegExp(String.fromCharCode(p), "g"), replace);
}
return '"' + val.replace(/"/g, '\\"') + '"';
case "boolean":
case "undefined":
return String(val);
case "number":
// In JavaScript, -0 === 0 and String(-0) == "0", so we have to
// special-case.
if (val === -0 && 1 / val === -Infinity) {
return "-0";
}
return String(val);
case "object":
if (val === null) {
return "null";
}
/* falls through */
default:
try {
return typeof val + ' "' + truncate(String(val), 1000) + '"';
} catch (e) {
return (
"[stringifying object threw " +
String(e) +
" with type " +
String(typeof e) +
"]"
);
}
}
}