|  | // META: title=IDBObjectStore.createIndex() | 
|  | // META: global=window,worker | 
|  | // META: script=resources/support.js | 
|  |  | 
|  | 'use strict'; | 
|  |  | 
|  | async_test(t => { | 
|  | let db; | 
|  |  | 
|  | let open_rq = createdb(t); | 
|  | open_rq.onupgradeneeded = function (e) { | 
|  | db = e.target.result; | 
|  | let objStore = db.createObjectStore("store"); | 
|  | let index = objStore.createIndex("index", "indexedProperty", { unique: true }); | 
|  |  | 
|  | assert_true(index instanceof IDBIndex, "IDBIndex"); | 
|  | assert_equals(index.name, "index", "name"); | 
|  | assert_equals(index.objectStore, objStore, "objectStore"); | 
|  | assert_equals(index.keyPath, "indexedProperty", "keyPath"); | 
|  | assert_true(index.unique, "unique"); | 
|  | assert_false(index.multiEntry, "multiEntry"); | 
|  |  | 
|  | t.done(); | 
|  | }; | 
|  | }, "Returns an IDBIndex and the properties are set correctly"); | 
|  |  | 
|  | async_test(t => { | 
|  | let db, aborted, | 
|  | record = { indexedProperty: "bar" }; | 
|  |  | 
|  | let open_rq = createdb(t); | 
|  | open_rq.onupgradeneeded = function (e) { | 
|  | db = e.target.result; | 
|  | let txn = e.target.transaction, | 
|  | objStore = db.createObjectStore("store"); | 
|  |  | 
|  | objStore.add(record, 1); | 
|  | objStore.add(record, 2); | 
|  | let index = objStore.createIndex("index", "indexedProperty", { unique: true }); | 
|  |  | 
|  | assert_true(index instanceof IDBIndex, "IDBIndex"); | 
|  |  | 
|  | e.target.transaction.onabort = t.step_func(function (e) { | 
|  | aborted = true; | 
|  | assert_equals(e.type, "abort", "event type"); | 
|  | }); | 
|  |  | 
|  | db.onabort = function (e) { | 
|  | assert_true(aborted, "transaction.abort event has fired"); | 
|  | t.done(); | 
|  | }; | 
|  |  | 
|  | e.target.transaction.oncomplete = fail(t, "got complete, expected abort"); | 
|  | }; | 
|  | }, "Attempt to create an index that requires unique values on an object store already contains duplicates"); | 
|  |  | 
|  | async_test(t => { | 
|  | let db, aborted; | 
|  |  | 
|  | let open_rq = createdb(t); | 
|  | open_rq.onupgradeneeded = function (e) { | 
|  | db = e.target.result; | 
|  | let txn = e.target.transaction, | 
|  | objStore = db.createObjectStore("store", { keyPath: 'key' }); | 
|  |  | 
|  | for (let i = 0; i < 100; i++) | 
|  | objStore.add({ key: "key_" + i, indexedProperty: "indexed_" + i }); | 
|  |  | 
|  | let idx = objStore.createIndex("index", "indexedProperty") | 
|  |  | 
|  | idx.get('indexed_99').onsuccess = t.step_func(function (e) { | 
|  | assert_equals(e.target.result.key, 'key_99', 'key'); | 
|  | }); | 
|  | idx.get('indexed_9').onsuccess = t.step_func(function (e) { | 
|  | assert_equals(e.target.result.key, 'key_9', 'key'); | 
|  | }); | 
|  | } | 
|  |  | 
|  | open_rq.onsuccess = function () { | 
|  | t.done(); | 
|  | } | 
|  | }, "The index is usable right after being made"); | 
|  |  | 
|  | async_test(t => { | 
|  | let db, | 
|  | events = []; | 
|  |  | 
|  | let open_rq = createdb(t); | 
|  | open_rq.onupgradeneeded = function (e) { | 
|  | db = e.target.result; | 
|  | e.target.transaction.oncomplete = log("transaction.complete"); | 
|  |  | 
|  | let txn = e.target.transaction, | 
|  | objStore = db.createObjectStore("store"); | 
|  |  | 
|  | let rq_add1 = objStore.add({ animal: "Unicorn" }, 1); | 
|  | rq_add1.onsuccess = log("rq_add1.success"); | 
|  | rq_add1.onerror = log("rq_add1.error"); | 
|  |  | 
|  | objStore.createIndex("index", "animal", { unique: true }); | 
|  |  | 
|  | let rq_add2 = objStore.add({ animal: "Unicorn" }, 2); | 
|  | rq_add2.onsuccess = log("rq_add2.success"); | 
|  | rq_add2.onerror = function (e) { | 
|  | log("rq_add2.error")(e); | 
|  | e.preventDefault(); | 
|  | e.stopPropagation(); | 
|  | } | 
|  |  | 
|  | objStore.deleteIndex("index"); | 
|  |  | 
|  | let rq_add3 = objStore.add({ animal: "Unicorn" }, 3); | 
|  | rq_add3.onsuccess = log("rq_add3.success"); | 
|  | rq_add3.onerror = log("rq_add3.error"); | 
|  | } | 
|  |  | 
|  | open_rq.onsuccess = function (e) { | 
|  | log("open_rq.success")(e); | 
|  | assert_array_equals(events, ["rq_add1.success", | 
|  | "rq_add2.error: ConstraintError", | 
|  | "rq_add3.success", | 
|  |  | 
|  | "transaction.complete", | 
|  |  | 
|  | "open_rq.success"], | 
|  | "events"); | 
|  | t.done(); | 
|  | } | 
|  |  | 
|  | function log(msg) { | 
|  | return function (e) { | 
|  | if (e && e.target && e.target.error) | 
|  | events.push(msg + ": " + e.target.error.name); | 
|  | else | 
|  | events.push(msg); | 
|  | }; | 
|  | } | 
|  | }, "Event ordering for a later deleted index"); | 
|  |  | 
|  | async_test(t => { | 
|  | let db, aborted; | 
|  |  | 
|  | let open_rq = createdb(t); | 
|  | open_rq.onupgradeneeded = function (e) { | 
|  | db = e.target.result; | 
|  | let txn = e.target.transaction, | 
|  | objStore = db.createObjectStore("store"); | 
|  |  | 
|  | for (let i = 0; i < 5; i++) | 
|  | objStore.add("object_" + i, i); | 
|  |  | 
|  | let rq = objStore.createIndex("index", "") | 
|  | rq.onerror = function () { assert_unreached("error: " + rq.error.name); } | 
|  | rq.onsuccess = function () { } | 
|  |  | 
|  | objStore.index("index") | 
|  | .get('object_4') | 
|  | .onsuccess = t.step_func(function (e) { | 
|  | assert_equals(e.target.result, 'object_4', 'result'); | 
|  | }); | 
|  | } | 
|  |  | 
|  | open_rq.onsuccess = function () { | 
|  | t.done(); | 
|  | } | 
|  | }, "Empty keyPath"); | 
|  |  | 
|  | async_test(t => { | 
|  | // Transaction may fire window.onerror in some implementations. | 
|  | setup({ allow_uncaught_exception: true }); | 
|  |  | 
|  | let db, | 
|  | events = []; | 
|  |  | 
|  | let open_rq = createdb(t); | 
|  | open_rq.onupgradeneeded = function (e) { | 
|  | db = e.target.result; | 
|  | db.onerror = log("db.error"); | 
|  | db.onabort = log("db.abort"); | 
|  | e.target.transaction.onabort = log("transaction.abort") | 
|  | e.target.transaction.onerror = log("transaction.error") | 
|  | e.target.transaction.oncomplete = log("transaction.complete") | 
|  |  | 
|  | let txn = e.target.transaction, | 
|  | objStore = db.createObjectStore("store"); | 
|  |  | 
|  | let rq_add1 = objStore.add({ animal: "Unicorn" }, 1); | 
|  | rq_add1.onsuccess = log("rq_add1.success"); | 
|  | rq_add1.onerror = log("rq_add1.error"); | 
|  |  | 
|  | let rq_add2 = objStore.add({ animal: "Unicorn" }, 2); | 
|  | rq_add2.onsuccess = log("rq_add2.success"); | 
|  | rq_add2.onerror = log("rq_add2.error"); | 
|  |  | 
|  | objStore.createIndex("index", "animal", { unique: true }) | 
|  |  | 
|  | let rq_add3 = objStore.add({ animal: "Unicorn" }, 3); | 
|  | rq_add3.onsuccess = log("rq_add3.success"); | 
|  | rq_add3.onerror = log("rq_add3.error"); | 
|  | } | 
|  |  | 
|  | open_rq.onerror = function (e) { | 
|  | log("open_rq.error")(e); | 
|  | assert_array_equals(events, ["rq_add1.success", | 
|  | "rq_add2.success", | 
|  |  | 
|  | "rq_add3.error: AbortError", | 
|  | "transaction.error: AbortError", | 
|  | "db.error: AbortError", | 
|  |  | 
|  | "transaction.abort: ConstraintError", | 
|  | "db.abort: ConstraintError", | 
|  |  | 
|  | "open_rq.error: AbortError"], | 
|  | "events"); | 
|  | t.done(); | 
|  | } | 
|  |  | 
|  | function log(msg) { | 
|  | return function (e) { | 
|  | if (e && e.target && e.target.error) | 
|  | events.push(msg + ": " + e.target.error.name); | 
|  | else | 
|  | events.push(msg); | 
|  | }; | 
|  | } | 
|  | }, "Event order when unique constraint is triggered"); | 
|  |  | 
|  | async_test(t => { | 
|  | setup({ allow_uncaught_exception: true }); | 
|  |  | 
|  | let db, | 
|  | events = []; | 
|  |  | 
|  | const open_rq = createdb(t); | 
|  | open_rq.onupgradeneeded = function (e) { | 
|  | db = e.target.result; | 
|  | let txn = e.target.transaction; | 
|  | db.onerror = log("db.error"); | 
|  | db.onabort = log("db.abort"); | 
|  | txn.onabort = log("transaction.abort") | 
|  | txn.onerror = log("transaction.error") | 
|  | txn.oncomplete = log("transaction.complete") | 
|  |  | 
|  | let objStore = db.createObjectStore("store"); | 
|  |  | 
|  | let rq_add1 = objStore.add({ animal: "Unicorn" }, 1); | 
|  | rq_add1.onsuccess = log("rq_add1.success"); | 
|  | rq_add1.onerror = log("rq_add1.error"); | 
|  |  | 
|  | objStore.createIndex("index", "animal", { unique: true }) | 
|  |  | 
|  | let rq_add2 = objStore.add({ animal: "Unicorn" }, 2); | 
|  | rq_add2.onsuccess = log("rq_add2.success"); | 
|  | rq_add2.onerror = log("rq_add2.error"); | 
|  |  | 
|  | let rq_add3 = objStore.add({ animal: "Horse" }, 3); | 
|  | rq_add3.onsuccess = log("rq_add3.success"); | 
|  | rq_add3.onerror = log("rq_add3.error"); | 
|  | } | 
|  |  | 
|  | open_rq.onerror = function (e) { | 
|  | log("open_rq.error")(e); | 
|  | assert_array_equals(events, ["rq_add1.success", | 
|  |  | 
|  | "rq_add2.error: ConstraintError", | 
|  | "transaction.error: ConstraintError", | 
|  | "db.error: ConstraintError", | 
|  |  | 
|  | "rq_add3.error: AbortError", | 
|  | "transaction.error: AbortError", | 
|  | "db.error: AbortError", | 
|  |  | 
|  | "transaction.abort: ConstraintError", | 
|  | "db.abort: ConstraintError", | 
|  |  | 
|  | "open_rq.error: AbortError"], | 
|  | "events"); | 
|  | t.done(); | 
|  | } | 
|  |  | 
|  | function log(msg) { | 
|  | return function (e) { | 
|  | if (e && e.target && e.target.error) | 
|  | events.push(msg + ": " + e.target.error.name); | 
|  | else | 
|  | events.push(msg); | 
|  | }; | 
|  | } | 
|  | }, "Event ordering for ConstraintError on request"); | 
|  |  | 
|  | async_test(t => { | 
|  | let db, | 
|  | now = new Date(), | 
|  | mar18 = new Date(1111111111111), | 
|  | ar = ["Yay", 2, -Infinity], | 
|  | num = 1337; | 
|  |  | 
|  | const open_rq = createdb(t); | 
|  | open_rq.onupgradeneeded = function (e) { | 
|  | db = e.target.result; | 
|  | let txn = e.target.transaction, | 
|  | objStore = db.createObjectStore("store", { keyPath: 'key' }); | 
|  |  | 
|  | objStore.add({ key: "now", i: now }); | 
|  | objStore.add({ key: "mar18", i: mar18 }); | 
|  | objStore.add({ key: "array", i: ar }); | 
|  | objStore.add({ key: "number", i: num }); | 
|  |  | 
|  | let idx = objStore.createIndex("index", "i") | 
|  |  | 
|  | idx.get(now).onsuccess = t.step_func(function (e) { | 
|  | assert_equals(e.target.result.key, 'now', 'key'); | 
|  | assert_equals(e.target.result.i.getTime(), now.getTime(), 'getTime'); | 
|  | }); | 
|  | idx.get(mar18).onsuccess = t.step_func(function (e) { | 
|  | assert_equals(e.target.result.key, 'mar18', 'key'); | 
|  | assert_equals(e.target.result.i.getTime(), mar18.getTime(), 'getTime'); | 
|  | }); | 
|  | idx.get(ar).onsuccess = t.step_func(function (e) { | 
|  | assert_equals(e.target.result.key, 'array', 'key'); | 
|  | assert_array_equals(e.target.result.i, ar, 'array is the same'); | 
|  | }); | 
|  | idx.get(num).onsuccess = t.step_func(function (e) { | 
|  | assert_equals(e.target.result.key, 'number', 'key'); | 
|  | assert_equals(e.target.result.i, num, 'number is the same'); | 
|  | }); | 
|  | } | 
|  |  | 
|  | open_rq.onsuccess = function () { | 
|  | t.done(); | 
|  | } | 
|  | }, "Index can be valid keys"); | 
|  |  | 
|  | async_test(t => { | 
|  | let db; | 
|  |  | 
|  | const open_rq = createdb(t); | 
|  | open_rq.onupgradeneeded = function (e) { | 
|  | db = e.target.result | 
|  | let store = db.createObjectStore("store") | 
|  |  | 
|  | for (let i = 0; i < 5; i++) | 
|  | store.add({ idx: "object_" + i }, i) | 
|  |  | 
|  | store.createIndex("", "idx") | 
|  |  | 
|  | store.index("") | 
|  | .get('object_4') | 
|  | .onsuccess = t.step_func(function (e) { | 
|  | assert_equals(e.target.result.idx, 'object_4', 'result') | 
|  | }) | 
|  | assert_equals(store.indexNames[0], "", "indexNames[0]") | 
|  | assert_equals(store.indexNames.length, 1, "indexNames.length") | 
|  | } | 
|  |  | 
|  | open_rq.onsuccess = function () { | 
|  | let store = db.transaction("store", "readonly").objectStore("store") | 
|  |  | 
|  | assert_equals(store.indexNames[0], "", "indexNames[0]") | 
|  | assert_equals(store.indexNames.length, 1, "indexNames.length") | 
|  |  | 
|  | t.done() | 
|  | } | 
|  | }, "IDBObjectStore.createIndex() - empty name"); | 
|  |  | 
|  | async_test(t => { | 
|  | const open_rq = createdb(t); | 
|  |  | 
|  | open_rq.onupgradeneeded = function (e) { | 
|  | let db = e.target.result; | 
|  | let ostore = db.createObjectStore("store"); | 
|  | ostore.createIndex("a", "a"); | 
|  | assert_throws_dom("ConstraintError", function () { | 
|  | ostore.createIndex("a", "a"); | 
|  | }); | 
|  | t.done(); | 
|  | } | 
|  | }, "If an index with the name name already exists in this object store, the implementation must throw a DOMException of type ConstraintError"); | 
|  |  | 
|  | async_test(t => { | 
|  | const open_rq = createdb(t); | 
|  |  | 
|  | open_rq.onupgradeneeded = function (e) { | 
|  | let db = e.target.result; | 
|  | let ostore = db.createObjectStore("store"); | 
|  | assert_throws_dom("SyntaxError", function () { | 
|  | ostore.createIndex("ab", "."); | 
|  | }); | 
|  | t.done(); | 
|  | } | 
|  | }, "If keyPath is not a valid key path, the implementation must throw a DOMException of type SyntaxError"); | 
|  |  | 
|  | async_test(t => { | 
|  | let db, ostore; | 
|  |  | 
|  | let open_rq = createdb(t); | 
|  | open_rq.onupgradeneeded = function (event) { | 
|  | db = event.target.result; | 
|  | ostore = db.createObjectStore("store"); | 
|  | db.deleteObjectStore("store"); | 
|  | } | 
|  |  | 
|  | open_rq.onsuccess = function (event) { | 
|  | t.step(function () { | 
|  | assert_throws_dom("InvalidStateError", function () { | 
|  | ostore.createIndex("index", "indexedProperty"); | 
|  | }); | 
|  | }); | 
|  | t.done(); | 
|  | } | 
|  | }, "If the object store has been deleted, the implementation must throw a DOMException of type InvalidStateError"); | 
|  |  | 
|  | async_test(t => { | 
|  | let db; | 
|  |  | 
|  | const open_rq = createdb(t); | 
|  | open_rq.onupgradeneeded = function (event) { | 
|  | db = event.target.result; | 
|  | db.createObjectStore("store"); | 
|  | } | 
|  |  | 
|  | open_rq.onsuccess = function (event) { | 
|  | let txn = db.transaction("store", "readwrite"); | 
|  | let ostore = txn.objectStore("store"); | 
|  | t.step(function () { | 
|  | assert_throws_dom("InvalidStateError", function () { | 
|  | ostore.createIndex("index", "indexedProperty"); | 
|  | }); | 
|  | }); | 
|  | t.done(); | 
|  | } | 
|  | }, "Operate out versionchange throw InvalidStateError"); | 
|  |  | 
|  | /* IndexedDB: Exception Order of IDBObjectStore.createIndex() */ | 
|  | indexeddb_test( | 
|  | function (t, db, txn) { | 
|  | let store = db.createObjectStore("s"); | 
|  | }, | 
|  | function (t, db) { | 
|  | let txn = db.transaction("s", "readonly"); | 
|  | let store = txn.objectStore("s"); | 
|  | txn.oncomplete = function () { | 
|  | assert_throws_dom("InvalidStateError", function () { | 
|  | store.createIndex("index", "foo"); | 
|  | }); | 
|  | t.done(); | 
|  | }; | 
|  | }, | 
|  | "InvalidStateError(Incorrect mode) vs. TransactionInactiveError. Mode check should precede state check of the transaction." | 
|  | ); | 
|  |  | 
|  | let gDeletedObjectStore; | 
|  | indexeddb_test( | 
|  | function (t, db, txn) { | 
|  | gDeletedObjectStore = db.createObjectStore("s"); | 
|  | db.deleteObjectStore("s"); | 
|  | txn.oncomplete = function () { | 
|  | assert_throws_dom("InvalidStateError", function () { | 
|  | gDeletedObjectStore.createIndex("index", "foo"); | 
|  | }); | 
|  | t.done(); | 
|  | }; | 
|  | }, | 
|  | null, | 
|  | "InvalidStateError(Deleted ObjectStore) vs. TransactionInactiveError. Deletion check should precede transaction-state check." | 
|  | ); | 
|  |  | 
|  | indexeddb_test( | 
|  | function (t, db, txn) { | 
|  | let store = db.createObjectStore("s"); | 
|  | store.createIndex("index", "foo"); | 
|  | txn.oncomplete = function () { | 
|  | assert_throws_dom("TransactionInactiveError", function () { | 
|  | store.createIndex("index", "foo"); | 
|  | }); | 
|  | t.done(); | 
|  | }; | 
|  | }, | 
|  | null, | 
|  | "TransactionInactiveError vs. ConstraintError. Transaction-state check should precede index name check." | 
|  | ); | 
|  |  | 
|  | indexeddb_test( | 
|  | function (t, db) { | 
|  | let store = db.createObjectStore("s"); | 
|  | store.createIndex("index", "foo"); | 
|  | assert_throws_dom("ConstraintError", function () { | 
|  | store.createIndex("index", "invalid key path"); | 
|  | }); | 
|  | assert_throws_dom("ConstraintError", function () { | 
|  | store.createIndex("index", | 
|  | ["invalid key path 1", "invalid key path 2"]); | 
|  | }); | 
|  | t.done(); | 
|  | }, | 
|  | null, | 
|  | "ConstraintError vs. SyntaxError. Index name check should precede syntax check of the key path" | 
|  | ); | 
|  |  | 
|  | indexeddb_test( | 
|  | function (t, db) { | 
|  | let store = db.createObjectStore("s"); | 
|  | assert_throws_dom("SyntaxError", function () { | 
|  | store.createIndex("index", | 
|  | ["invalid key path 1", "invalid key path 2"], | 
|  | { multiEntry: true }); | 
|  | }); | 
|  | t.done(); | 
|  | }, | 
|  | null, | 
|  | "SyntaxError vs. InvalidAccessError. Syntax check should precede multiEntry check of the key path." | 
|  | ); | 
|  |  | 
|  | /* AutoIncrement in Compound Index */ | 
|  | indexeddb_test( | 
|  | function (t, db, txn) { | 
|  | // No auto-increment | 
|  | let store = db.createObjectStore("Store1", { keyPath: "id" }); | 
|  | store.createIndex("CompoundKey", ["num", "id"]); | 
|  |  | 
|  | // Add data | 
|  | store.put({ id: 1, num: 100 }); | 
|  | }, | 
|  | function (t, db) { | 
|  | let store = db.transaction("Store1", "readwrite").objectStore("Store1"); | 
|  |  | 
|  | store.openCursor().onsuccess = t.step_func(function (e) { | 
|  | let item = e.target.result.value; | 
|  | store.index("CompoundKey").get([item.num, item.id]).onsuccess = t.step_func(function (e) { | 
|  | assert_equals(e.target.result ? e.target.result.num : null, 100, 'Expected 100.'); | 
|  | t.done(); | 
|  | }); | 
|  | }); | 
|  | }, | 
|  | "Explicit Primary Key" | 
|  | ); | 
|  |  | 
|  | indexeddb_test( | 
|  | function (t, db, txn) { | 
|  | // Auto-increment | 
|  | let store = db.createObjectStore("Store2", { keyPath: "id", autoIncrement: true }); | 
|  | store.createIndex("CompoundKey", ["num", "id"]); | 
|  |  | 
|  | // Add data | 
|  | store.put({ num: 100 }); | 
|  | }, | 
|  | function (t, db) { | 
|  | let store = db.transaction("Store2", "readwrite").objectStore("Store2"); | 
|  | store.openCursor().onsuccess = t.step_func(function (e) { | 
|  | let item = e.target.result.value; | 
|  | store.index("CompoundKey").get([item.num, item.id]).onsuccess = t.step_func(function (e) { | 
|  | assert_equals(e.target.result ? e.target.result.num : null, 100, 'Expected 100.'); | 
|  | t.done(); | 
|  | }); | 
|  | }); | 
|  | }, | 
|  | "Auto-Increment Primary Key" | 
|  | ); | 
|  |  | 
|  | indexeddb_test( | 
|  | function (t, db, txn) { | 
|  | // Auto-increment | 
|  | let store = db.createObjectStore("Store3", { keyPath: "id", autoIncrement: true }); | 
|  | store.createIndex("CompoundKey", ["num", "id", "other"]); | 
|  |  | 
|  | let num = 100; | 
|  |  | 
|  | // Add data to Store3 - valid keys | 
|  | // Objects will be stored in Store3 and keys will get added | 
|  | // to the CompoundKeys index. | 
|  | store.put({ num: num++, other: 0 }); | 
|  | store.put({ num: num++, other: [0] }); | 
|  |  | 
|  | // Add data - missing key | 
|  | // Objects will be stored in Store3 but keys won't get added to | 
|  | // the CompoundKeys index because the 'other' keypath doesn't | 
|  | // resolve to a value. | 
|  | store.put({ num: num++ }); | 
|  |  | 
|  | // Add data to Store3 - invalid keys | 
|  | // Objects will be stored in Store3 but keys won't get added to | 
|  | // the CompoundKeys index because the 'other' property values | 
|  | // aren't valid keys. | 
|  | store.put({ num: num++, other: null }); | 
|  | store.put({ num: num++, other: {} }); | 
|  | store.put({ num: num++, other: [null] }); | 
|  | store.put({ num: num++, other: [{}] }); | 
|  | }, | 
|  | function (t, db) { | 
|  | let store = db.transaction("Store3", "readwrite").objectStore("Store3"); | 
|  | const keys = []; | 
|  | let count; | 
|  | store.count().onsuccess = t.step_func(e => { count = e.target.result; }); | 
|  | store.index("CompoundKey").openCursor().onsuccess = t.step_func(function (e) { | 
|  | const cursor = e.target.result; | 
|  | if (cursor !== null) { | 
|  | keys.push(cursor.key); | 
|  | cursor.continue(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Done iteration, check results. | 
|  | assert_equals(count, 7, 'Expected all 7 records to be stored.'); | 
|  | assert_equals(keys.length, 2, 'Expected exactly two index entries.'); | 
|  | assert_array_equals(keys[0], [100, 1, 0]); | 
|  | assert_object_equals(keys[1], [101, 2, [0]]); | 
|  | t.done(); | 
|  | }); | 
|  | }, | 
|  | "Auto-Increment Primary Key - invalid key values elsewhere" | 
|  | ); |