michael@0: /** michael@0: * Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/publicdomain/zero/1.0/ michael@0: */ michael@0: michael@0: var testGenerator = testSteps(); michael@0: michael@0: var abortFired = false; michael@0: michael@0: function abortListener(evt) michael@0: { michael@0: abortFired = true; michael@0: is(evt.target.error, null, "Expect a null error for an aborted transaction"); michael@0: } michael@0: michael@0: function testSteps() michael@0: { michael@0: const Ci = Components.interfaces; michael@0: michael@0: const name = this.window ? window.location.pathname : "Splendid Test"; michael@0: michael@0: let request = indexedDB.open(name, 1); michael@0: request.onerror = errorHandler; michael@0: request.onupgradeneeded = grabEventAndContinueHandler; michael@0: request.onsuccess = grabEventAndContinueHandler; michael@0: let event = yield undefined; michael@0: michael@0: let db = event.target.result; michael@0: db.onabort = abortListener; michael@0: michael@0: let transaction; michael@0: let objectStore; michael@0: let index; michael@0: michael@0: transaction = event.target.transaction; michael@0: michael@0: try { michael@0: let error = transaction.error; michael@0: ok(false, "Expect an exception"); michael@0: } catch(e) { michael@0: ok(true, "Got an exception."); michael@0: is(e.name, "InvalidStateError", "Got the right exception"); michael@0: } michael@0: michael@0: objectStore = db.createObjectStore("foo", { autoIncrement: true }); michael@0: index = objectStore.createIndex("fooindex", "indexKey", { unique: true }); michael@0: michael@0: is(transaction.db, db, "Correct database"); michael@0: is(transaction.mode, "versionchange", "Correct mode"); michael@0: is(transaction.objectStoreNames.length, 1, "Correct names length"); michael@0: is(transaction.objectStoreNames.item(0), "foo", "Correct name"); michael@0: is(transaction.objectStore("foo"), objectStore, "Can get stores"); michael@0: is(transaction.oncomplete, null, "No complete listener"); michael@0: is(transaction.onabort, null, "No abort listener"); michael@0: michael@0: is(objectStore.name, "foo", "Correct name"); michael@0: is(objectStore.keyPath, null, "Correct keyPath"); michael@0: michael@0: is(objectStore.indexNames.length, 1, "Correct indexNames length"); michael@0: is(objectStore.indexNames[0], "fooindex", "Correct indexNames name"); michael@0: is(objectStore.index("fooindex"), index, "Can get index"); michael@0: michael@0: // Wait until it's complete! michael@0: transaction.oncomplete = grabEventAndContinueHandler; michael@0: event = yield undefined; michael@0: michael@0: is(transaction.db, db, "Correct database"); michael@0: is(transaction.mode, "versionchange", "Correct mode"); michael@0: is(transaction.objectStoreNames.length, 1, "Correct names length"); michael@0: is(transaction.objectStoreNames.item(0), "foo", "Correct name"); michael@0: is(transaction.onabort, null, "No abort listener"); michael@0: michael@0: try { michael@0: is(transaction.objectStore("foo").name, "foo", "Can't get stores"); michael@0: ok(false, "Should have thrown"); michael@0: } michael@0: catch (e) { michael@0: ok(true, "Out of scope transaction can't make stores"); michael@0: } michael@0: michael@0: is(objectStore.name, "foo", "Correct name"); michael@0: is(objectStore.keyPath, null, "Correct keyPath"); michael@0: michael@0: is(objectStore.indexNames.length, 1, "Correct indexNames length"); michael@0: is(objectStore.indexNames[0], "fooindex", "Correct indexNames name"); michael@0: michael@0: try { michael@0: objectStore.add({}); michael@0: ok(false, "Should have thrown"); michael@0: } michael@0: catch (e) { michael@0: ok(true, "Add threw"); michael@0: } michael@0: michael@0: try { michael@0: objectStore.put({}, 1); michael@0: ok(false, "Should have thrown"); michael@0: } michael@0: catch (e) { michael@0: ok(true, "Put threw"); michael@0: } michael@0: michael@0: try { michael@0: objectStore.put({}, 1); michael@0: ok(false, "Should have thrown"); michael@0: } michael@0: catch (e) { michael@0: ok(true, "Put threw"); michael@0: } michael@0: michael@0: try { michael@0: objectStore.delete(1); michael@0: ok(false, "Should have thrown"); michael@0: } michael@0: catch (e) { michael@0: ok(true, "Remove threw"); michael@0: } michael@0: michael@0: try { michael@0: objectStore.get(1); michael@0: ok(false, "Should have thrown"); michael@0: } michael@0: catch (e) { michael@0: ok(true, "Get threw"); michael@0: } michael@0: michael@0: try { michael@0: objectStore.getAll(null); michael@0: ok(false, "Should have thrown"); michael@0: } michael@0: catch (e) { michael@0: ok(true, "GetAll threw"); michael@0: } michael@0: michael@0: try { michael@0: objectStore.openCursor(); michael@0: ok(false, "Should have thrown"); michael@0: } michael@0: catch (e) { michael@0: ok(true, "OpenCursor threw"); michael@0: } michael@0: michael@0: try { michael@0: objectStore.createIndex("bar", "id"); michael@0: ok(false, "Should have thrown"); michael@0: } michael@0: catch (e) { michael@0: ok(true, "CreateIndex threw"); michael@0: } michael@0: michael@0: try { michael@0: objectStore.index("bar"); michael@0: ok(false, "Should have thrown"); michael@0: } michael@0: catch (e) { michael@0: ok(true, "Index threw"); michael@0: } michael@0: michael@0: try { michael@0: objectStore.deleteIndex("bar"); michael@0: ok(false, "Should have thrown"); michael@0: } michael@0: catch (e) { michael@0: ok(true, "RemoveIndex threw"); michael@0: } michael@0: michael@0: yield undefined; michael@0: michael@0: request = db.transaction("foo", "readwrite").objectStore("foo").add({}); michael@0: request.onerror = errorHandler; michael@0: request.onsuccess = grabEventAndContinueHandler; michael@0: event = yield undefined; michael@0: michael@0: event.target.transaction.onabort = function(event) { michael@0: ok(false, "Shouldn't see an abort event!"); michael@0: }; michael@0: event.target.transaction.oncomplete = grabEventAndContinueHandler; michael@0: event = yield undefined; michael@0: michael@0: is(event.type, "complete", "Right kind of event"); michael@0: michael@0: let key; michael@0: michael@0: request = db.transaction("foo", "readwrite").objectStore("foo").add({}); michael@0: request.onerror = errorHandler; michael@0: request.onsuccess = grabEventAndContinueHandler; michael@0: event = yield undefined; michael@0: michael@0: key = event.target.result; michael@0: michael@0: event.target.transaction.onabort = grabEventAndContinueHandler; michael@0: event.target.transaction.oncomplete = function(event) { michael@0: ok(false, "Shouldn't see a complete event here!"); michael@0: }; michael@0: michael@0: event.target.transaction.abort(); michael@0: michael@0: event = yield undefined; michael@0: michael@0: is(event.type, "abort", "Right kind of event"); michael@0: michael@0: request = db.transaction("foo").objectStore("foo").get(key); michael@0: request.onerror = errorHandler; michael@0: request.onsuccess = grabEventAndContinueHandler; michael@0: event = yield undefined; michael@0: michael@0: is(event.target.result, undefined, "Object was removed"); michael@0: michael@0: executeSoon(function() { testGenerator.next(); }); michael@0: yield undefined; michael@0: michael@0: let keys = []; michael@0: let abortEventCount = 0; michael@0: function abortErrorHandler(event) { michael@0: is(event.target.error.name, "AbortError", michael@0: "Good error"); michael@0: abortEventCount++; michael@0: event.preventDefault(); michael@0: }; michael@0: objectStore = db.transaction("foo", "readwrite").objectStore("foo"); michael@0: michael@0: for (let i = 0; i < 10; i++) { michael@0: request = objectStore.add({}); michael@0: request.onerror = abortErrorHandler; michael@0: request.onsuccess = function(event) { michael@0: keys.push(event.target.result); michael@0: if (keys.length == 5) { michael@0: event.target.transaction.onabort = grabEventAndContinueHandler; michael@0: event.target.transaction.abort(); michael@0: } michael@0: }; michael@0: } michael@0: event = yield undefined; michael@0: michael@0: is(event.type, "abort", "Got abort event"); michael@0: is(keys.length, 5, "Added 5 items in this transaction"); michael@0: is(abortEventCount, 5, "Got 5 abort error events"); michael@0: michael@0: for (let i in keys) { michael@0: request = db.transaction("foo").objectStore("foo").get(keys[i]); michael@0: request.onerror = errorHandler; michael@0: request.onsuccess = grabEventAndContinueHandler; michael@0: event = yield undefined; michael@0: michael@0: is(event.target.result, undefined, "Object was removed by abort"); michael@0: } michael@0: michael@0: // Set up some predictible data michael@0: transaction = db.transaction("foo", "readwrite"); michael@0: objectStore = transaction.objectStore("foo"); michael@0: objectStore.clear(); michael@0: objectStore.add({}, 1); michael@0: objectStore.add({}, 2); michael@0: request = objectStore.add({}, 1); michael@0: request.onsuccess = function() { michael@0: ok(false, "inserting duplicate key should fail"); michael@0: } michael@0: request.onerror = function(event) { michael@0: ok(true, "inserting duplicate key should fail"); michael@0: event.preventDefault(); michael@0: } michael@0: transaction.oncomplete = grabEventAndContinueHandler; michael@0: yield undefined; michael@0: michael@0: // Check when aborting is allowed michael@0: abortEventCount = 0; michael@0: let expectedAbortEventCount = 0; michael@0: michael@0: // During INITIAL michael@0: transaction = db.transaction("foo"); michael@0: transaction.abort(); michael@0: try { michael@0: transaction.abort(); michael@0: ok(false, "second abort should throw an error"); michael@0: } michael@0: catch (ex) { michael@0: ok(true, "second abort should throw an error"); michael@0: } michael@0: michael@0: // During LOADING michael@0: transaction = db.transaction("foo"); michael@0: transaction.objectStore("foo").get(1).onerror = abortErrorHandler; michael@0: expectedAbortEventCount++; michael@0: transaction.abort(); michael@0: try { michael@0: transaction.abort(); michael@0: ok(false, "second abort should throw an error"); michael@0: } michael@0: catch (ex) { michael@0: ok(true, "second abort should throw an error"); michael@0: } michael@0: michael@0: // During LOADING from callback michael@0: transaction = db.transaction("foo"); michael@0: transaction.objectStore("foo").get(1).onsuccess = grabEventAndContinueHandler; michael@0: event = yield undefined; michael@0: transaction.objectStore("foo").get(1).onerror = abortErrorHandler; michael@0: expectedAbortEventCount++ michael@0: transaction.abort(); michael@0: try { michael@0: transaction.abort(); michael@0: ok(false, "second abort should throw an error"); michael@0: } michael@0: catch (ex) { michael@0: ok(true, "second abort should throw an error"); michael@0: } michael@0: michael@0: // During LOADING from error callback michael@0: transaction = db.transaction("foo", "readwrite"); michael@0: transaction.objectStore("foo").add({}, 1).onerror = function(event) { michael@0: event.preventDefault(); michael@0: michael@0: transaction.objectStore("foo").get(1).onerror = abortErrorHandler; michael@0: expectedAbortEventCount++ michael@0: michael@0: transaction.abort(); michael@0: continueToNextStep(); michael@0: } michael@0: yield undefined; michael@0: michael@0: // In between callbacks michael@0: transaction = db.transaction("foo"); michael@0: function makeNewRequest() { michael@0: let r = transaction.objectStore("foo").get(1); michael@0: r.onsuccess = makeNewRequest; michael@0: r.onerror = abortErrorHandler; michael@0: } michael@0: makeNewRequest(); michael@0: transaction.objectStore("foo").get(1).onsuccess = function(event) { michael@0: executeSoon(function() { michael@0: transaction.abort(); michael@0: expectedAbortEventCount++; michael@0: continueToNextStep(); michael@0: }); michael@0: }; michael@0: yield undefined; michael@0: michael@0: // During COMMITTING michael@0: transaction = db.transaction("foo", "readwrite"); michael@0: transaction.objectStore("foo").put({hello: "world"}, 1).onsuccess = function(event) { michael@0: continueToNextStep(); michael@0: }; michael@0: yield undefined; michael@0: try { michael@0: transaction.abort(); michael@0: ok(false, "second abort should throw an error"); michael@0: } michael@0: catch (ex) { michael@0: ok(true, "second abort should throw an error"); michael@0: } michael@0: transaction.oncomplete = grabEventAndContinueHandler; michael@0: event = yield undefined; michael@0: michael@0: // Since the previous transaction shouldn't have caused any error events, michael@0: // we know that all events should have fired by now. michael@0: is(abortEventCount, expectedAbortEventCount, michael@0: "All abort errors fired"); michael@0: michael@0: // Abort both failing and succeeding requests michael@0: transaction = db.transaction("foo", "readwrite"); michael@0: transaction.onabort = transaction.oncomplete = grabEventAndContinueHandler; michael@0: transaction.objectStore("foo").add({indexKey: "key"}).onsuccess = function(event) { michael@0: transaction.abort(); michael@0: }; michael@0: let request1 = transaction.objectStore("foo").add({indexKey: "key"}); michael@0: request1.onsuccess = grabEventAndContinueHandler; michael@0: request1.onerror = grabEventAndContinueHandler; michael@0: let request2 = transaction.objectStore("foo").get(1); michael@0: request2.onsuccess = grabEventAndContinueHandler; michael@0: request2.onerror = grabEventAndContinueHandler; michael@0: michael@0: event = yield undefined; michael@0: is(event.type, "error", "abort() should make all requests fail"); michael@0: is(event.target, request1, "abort() should make all requests fail"); michael@0: is(event.target.error.name, "AbortError", "abort() should make all requests fail"); michael@0: event.preventDefault(); michael@0: michael@0: event = yield undefined; michael@0: is(event.type, "error", "abort() should make all requests fail"); michael@0: is(event.target, request2, "abort() should make all requests fail"); michael@0: is(event.target.error.name, "AbortError", "abort() should make all requests fail"); michael@0: event.preventDefault(); michael@0: michael@0: event = yield undefined; michael@0: is(event.type, "abort", "transaction should fail"); michael@0: is(event.target, transaction, "transaction should fail"); michael@0: michael@0: ok(abortFired, "Abort should have fired!"); michael@0: michael@0: finishTest(); michael@0: yield undefined; michael@0: }