1 if (this.importScripts) {
2 importScripts('../../../resources/js-test.js');
3 importScripts('shared.js');
6 description("Test that expected exceptions are thrown per IndexedDB spec.");
8 indexedDBTest(prepareDatabase, testDatabase);
9 function prepareDatabase()
11 db = event.target.result;
13 evalAndLog("store = db.createObjectStore('store')");
14 evalAndLog("index = store.createIndex('index', 'id')");
15 evalAndLog("store.put({id: 'a'}, 1)");
16 evalAndLog("store.put({id: 'b'}, 2)");
17 evalAndLog("store.put({id: 'c'}, 3)");
18 evalAndLog("store.put({id: 'd'}, 4)");
19 evalAndLog("store.put({id: 'e'}, 5)");
20 evalAndLog("store.put({id: 'f'}, 6)");
21 evalAndLog("store.put({id: 'g'}, 7)");
22 evalAndLog("store.put({id: 'h'}, 8)");
23 evalAndLog("store.put({id: 'i'}, 9)");
24 evalAndLog("store.put({id: 'j'}, 10)");
25 evalAndLog("otherStore = db.createObjectStore('otherStore')");
26 evalAndLog("inlineKeyStore = db.createObjectStore('inlineKeyStore', {keyPath: 'id'})");
28 evalAndLog("request = inlineKeyStore.put({id: 0})");
29 shouldBeEqualToString("request.readyState", "pending");
32 debug("3.2.1 The IDBRequest Interface");
35 debug("IDBRequest.error");
36 debug("When the done flag is false, getting this property must throw a DOMException of type InvalidStateError.");
37 evalAndExpectException("request.error", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
40 debug("IDBRequest.result");
41 debug("When the done flag is false, getting this property must throw a DOMException of type InvalidStateError.");
42 evalAndExpectException("request.result", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
45 debug("3.2.3 Opening a database");
48 debug("IDBFactory.cmp()");
49 debug("One of the supplied keys was not a valid key.");
50 evalAndExpectException("indexedDB.cmp(null, 0)", "0", "'DataError'");
53 function testDatabase()
55 evalAndLog("db.close()");
58 debug("3.2.4 Database");
60 request = evalAndLog("indexedDB.open(dbname, 2)");
61 request.onerror = unexpectedErrorCallback;
62 request.onblocked = unexpectedBlockedCallback;
63 request.onsuccess = checkTransactionAndObjectStoreExceptions;
64 request.onupgradeneeded = function() {
66 var trans = request.transaction;
67 trans.onabort = unexpectedAbortCallback;
70 debug("IDBDatabase.createObjectStore()");
71 debug("If an objectStore with the same name already exists, the implementation must throw a DOMException of type ConstraintError.");
72 evalAndExpectException("db.createObjectStore('store')", "0", "'ConstraintError'");
73 debug("If keyPath is not a valid key path then a DOMException of type SyntaxError must be thrown.");
74 evalAndExpectException("db.createObjectStore('fail', {keyPath: '-invalid-'})", "DOMException.SYNTAX_ERR", "'SyntaxError'");
75 debug("If the optionalParameters parameter is specified, and autoIncrement is set to true, and the keyPath parameter is specified to the empty string, or specified to an Array, this function must throw a InvalidAccessError exception.");
76 evalAndExpectException("db.createObjectStore('fail', {autoIncrement: true, keyPath: ''})", "DOMException.INVALID_ACCESS_ERR", "'InvalidAccessError'");
77 evalAndExpectException("db.createObjectStore('fail', {autoIncrement: true, keyPath: ['a']})", "DOMException.INVALID_ACCESS_ERR", "'InvalidAccessError'");
80 debug("IDBDatabase.deleteObjectStore()");
81 debug("There is no object store with the given name, compared in a case-sensitive manner, in the connected database.");
82 evalAndExpectException("db.deleteObjectStore('no-such-store')", "DOMException.NOT_FOUND_ERR", "'NotFoundError'");
85 debug("IDBDatabase.transaction()");
86 debug('If this method is called on IDBDatabase object for which a "versionchange" transaction is still running, a InvalidStateError exception must be thrown.');
87 evalAndExpectException("db.transaction('store')", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
91 function checkTransactionAndObjectStoreExceptions()
93 debug("One of the names provided in the storeNames argument doesn't exist in this database.");
94 evalAndExpectException("db.transaction('no-such-store')", "DOMException.NOT_FOUND_ERR", "'NotFoundError'");
95 debug("The value for the mode parameter is invalid.");
96 evalAndExpectExceptionClass("db.transaction('store', 'invalid-mode')", "TypeError");
97 debug("The 'versionchange' value for the mode parameter can only be set internally during upgradeneeded.");
98 evalAndExpectExceptionClass("db.transaction('store', 'versionchange')", "TypeError");
99 debug("The function was called with an empty list of store names");
100 evalAndExpectException("db.transaction([])", "DOMException.INVALID_ACCESS_ERR", "'InvalidAccessError'");
103 debug("One more IDBDatabase.createObjectStore() test:");
104 debug('If this function is called from outside a "versionchange" transaction callback ... the implementation must throw a DOMException of type InvalidStateError.');
105 evalAndExpectException("db.createObjectStore('fail')", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
108 debug("One more IDBDatabase.deleteObjectStore() test:");
109 debug('If this function is called from outside a "versionchange" transaction callback ... the implementation must throw a DOMException of type InvalidStateError.');
110 evalAndExpectException("db.deleteObjectStore('fail')", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
112 prepareStoreAndIndex();
115 function prepareStoreAndIndex()
118 debug("Prepare an object store and index from an inactive transaction for later use.");
119 evalAndLog("finishedTransaction = inactiveTransaction = db.transaction('store')");
120 inactiveTransaction.onabort = unexpectedAbortCallback;
121 evalAndLog("storeFromInactiveTransaction = inactiveTransaction.objectStore('store')");
122 evalAndLog("indexFromInactiveTransaction = storeFromInactiveTransaction.index('index')");
123 evalAndLog("request = storeFromInactiveTransaction.openCursor()");
124 request.onerror = unexpectedErrorCallback;
125 request.onsuccess = function() {
126 evalAndLog("cursorFromInactiveTransaction = request.result");
128 inactiveTransaction.oncomplete = testObjectStore;
131 function testObjectStore()
134 debug("3.2.5 Object Store");
135 evalAndLog("ro_transaction = db.transaction('store', 'readonly')");
136 evalAndLog("storeFromReadOnlyTransaction = ro_transaction.objectStore('store')");
137 evalAndLog("rw_transaction = db.transaction('store', 'readwrite')");
138 evalAndLog("store = rw_transaction.objectStore('store')");
141 debug("IDBObjectStore.add()");
142 debug('This method throws a DOMException of type ReadOnlyError if the transaction which this IDBObjectStore belongs to is has its mode set to "readonly".');
143 evalAndExpectException("storeFromReadOnlyTransaction.add(0, 0)", "0", "'ReadOnlyError'");
144 // "If any of the following conditions are true, this method throws a DOMException of type DataError:" - covered in objectstore-basics.html
145 debug("The transaction this IDBObjectStore belongs to is not active.");
146 evalAndExpectException("storeFromInactiveTransaction.add(0, 0)", "0", "'TransactionInactiveError'");
147 // "Occurs if a request is made on a source object that has been deleted or removed." - covered in deleted-objects.html
148 debug("The data being stored could not be cloned by the internal structured cloning algorithm.");
149 evalAndExpectException("store.add(self, 0)", "DOMException.DATA_CLONE_ERR"); // FIXME: Test 'DataCloneError' name when DOM4 exceptions are used in binding.
152 debug("IDBObjectStore.clear()");
153 debug('This method throws a DOMException of type ReadOnlyError if the transaction which this IDBObjectStore belongs to is has its mode set to "readonly".');
154 evalAndExpectException("storeFromReadOnlyTransaction.clear()", "0", "'ReadOnlyError'");
155 debug("The transaction this IDBObjectStore belongs to is not active.");
156 evalAndExpectException("storeFromInactiveTransaction.clear()", "0", "'TransactionInactiveError'");
157 // "Occurs if a request is made on a source object that has been deleted or removed." - covered in deleted-objects.html
160 debug("IDBObjectStore.count()");
161 debug("If the optional key parameter is not a valid key or a key range, this method throws a DOMException of type DataError.");
162 evalAndExpectException("store.count({})", "0", "'DataError'");
163 debug("The transaction this IDBObjectStore belongs to is not active.");
164 evalAndExpectException("storeFromInactiveTransaction.count()", "0", "'TransactionInactiveError'");
165 // "Occurs if a request is made on a source object that has been deleted or removed." - covered in deleted-objects.html
168 debug("IDBObjectStore.delete()");
169 debug('This method throws a DOMException of type ReadOnlyError if the transaction which this IDBObjectStore belongs to is has its mode set to "readonly".');
170 evalAndExpectException("storeFromReadOnlyTransaction.delete(0)", "0", "'ReadOnlyError'");
171 debug("If the key parameter is not a valid key or a key range this method throws a DOMException of type DataError.");
172 evalAndExpectException("store.delete({})", "0", "'DataError'");
173 debug("The transaction this IDBObjectStore belongs to is not active.");
174 evalAndExpectException("storeFromInactiveTransaction.add(0, 0)", "0", "'TransactionInactiveError'");
175 // "Occurs if a request is made on a source object that has been deleted or removed." - covered in deleted-objects.html
178 debug("IDBObjectStore.get()");
179 debug("If the key parameter is not a valid key or a key range, this method throws a DOMException of type DataError.");
180 evalAndExpectException("store.get({})", "0", "'DataError'");
181 debug("The transaction this IDBObjectStore belongs to is not active.");
182 evalAndExpectException("storeFromInactiveTransaction.get(0)", "0", "'TransactionInactiveError'");
183 // "Occurs if a request is made on a source object that has been deleted or removed." - covered in deleted-objects.html
186 debug("IDBObjectStore.index()");
187 debug("There is no index with the given name, compared in a case-sensitive manner, in the connected database.");
188 evalAndExpectException("store.index('no-such-index')", "DOMException.NOT_FOUND_ERR", "'NotFoundError'");
189 debug("Occurs if a request is made on a source object that has been deleted or removed, or if the transaction the object store belongs to has finished.");
190 evalAndExpectException("storeFromInactiveTransaction.index('index')", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
191 // "Occurs if a request is made on a source object that has been deleted or removed." - covered in deleted-objects.html
194 debug("IDBObjectStore.openCursor()");
195 debug("If the range parameter is specified but is not a valid key or a key range, this method throws a DOMException of type DataError.");
196 evalAndExpectException("store.openCursor({})", "0", "'DataError'");
197 debug("The transaction this IDBObjectStore belongs to is not active.");
198 evalAndExpectException("storeFromInactiveTransaction.openCursor()", "0", "'TransactionInactiveError'");
199 debug("The value for the direction parameter is invalid.");
200 evalAndExpectExceptionClass("store.openCursor(0, 'invalid-direction')", "TypeError");
201 // "Occurs if a request is made on a source object that has been deleted or removed." - covered in deleted-objects.html
204 debug("IDBObjectStore.openKeyCursor()");
205 debug("If the range parameter is specified but is not a valid key or a key range, this method throws a DOMException of type DataError.");
206 evalAndExpectException("store.openKeyCursor({})", "0", "'DataError'");
207 debug("The transaction this IDBObjectStore belongs to is not active.");
208 evalAndExpectException("storeFromInactiveTransaction.openKeyCursor()", "0", "'TransactionInactiveError'");
209 debug("The value for the direction parameter is invalid.");
210 evalAndExpectExceptionClass("store.openKeyCursor(0, 'invalid-direction')", "TypeError");
211 // "Occurs if a request is made on a source object that has been deleted or removed." - covered in deleted-objects.html
214 debug("IDBObjectStore.put()");
215 debug('This method throws a DOMException of type ReadOnlyError if the transaction which this IDBObjectStore belongs to is has its mode set to "readonly".');
216 evalAndExpectException("storeFromReadOnlyTransaction.put(0, 0)", "0", "'ReadOnlyError'");
217 // "If any of the following conditions are true, this method throws a DOMException of type DataError:" - covered in objectstore-basics.html
218 debug("The transaction this IDBObjectStore belongs to is not active.");
219 evalAndExpectException("storeFromInactiveTransaction.put(0, 0)", "0", "'TransactionInactiveError'");
220 // "Occurs if a request is made on a source object that has been deleted or removed." - covered in deleted-objects.html
221 debug("The data being stored could not be cloned by the internal structured cloning algorithm.");
222 evalAndExpectException("store.put(self, 0)", "DOMException.DATA_CLONE_ERR"); // FIXME: Test 'DataCloneError' name when DOM4 exceptions are used in binding.
224 evalAndLog("db.close()");
225 evalAndLog("ro_transaction.oncomplete = transactionComplete");
226 evalAndLog("rw_transaction.oncomplete = transactionComplete");
229 var numCompleted = 0;
230 function transactionComplete(evt)
234 if (numCompleted == 1) {
235 debug("First transaction completed");
238 evalAndLog("request = indexedDB.open(dbname, 3)");
239 request.onerror = unexpectedErrorCallback;
240 request.onblocked = unexpectedBlockedCallback;
241 evalAndLog("request.onupgradeneeded = onUpgradeNeeded3");
244 function onUpgradeNeeded3()
247 var trans = request.transaction;
248 trans.onabort = unexpectedAbortCallback;
249 trans.oncomplete = testOutsideVersionChangeTransaction;
250 store = trans.objectStore('store');
253 debug("IDBObjectStore.createIndex()");
254 debug("If an index with the same name already exists, the implementation must throw a DOMException of type ConstraintError. ");
255 evalAndExpectException("store.createIndex('index', 'keyPath')", "0", "'ConstraintError'");
256 debug("If keyPath is not a valid key path then a DOMException of type SyntaxError must be thrown.");
257 evalAndExpectException("store.createIndex('fail', '-invalid-')", "DOMException.SYNTAX_ERR", "'SyntaxError'");
258 debug("If keyPath is an Array and the multiEntry property in the optionalParameters is true, then a DOMException of type InvalidAccessError must be thrown.");
259 evalAndExpectException("store.createIndex('fail', ['a'], {multiEntry: true})", "DOMException.INVALID_ACCESS_ERR", "'InvalidAccessError'");
260 // "Occurs if a request is made on a source object that has been deleted or removed." - covered in deleted-objects.html
263 debug("IDBObjectStore.deleteIndex()");
264 debug("There is no index with the given name, compared in a case-sensitive manner, in the connected database.");
265 evalAndExpectException("store.deleteIndex('no-such-index')", "DOMException.NOT_FOUND_ERR", "'NotFoundError'");
268 function testOutsideVersionChangeTransaction() {
270 debug("One more IDBObjectStore.createIndex() test:");
271 debug('If this function is called from outside a "versionchange" transaction callback ... the implementation must throw a DOMException of type InvalidStateError.');
272 evalAndExpectException("db.transaction('store').objectStore('store').createIndex('fail', 'keyPath')", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
275 debug("One more IDBObjectStore.deleteIndex() test:");
276 debug('If this function is called from outside a "versionchange" transaction callback ... the implementation must throw a DOMException of type InvalidStateError.');
277 evalAndExpectException("db.transaction('store').objectStore('store').deleteIndex('fail', 'keyPath')", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
284 debug("3.2.6 Index");
285 evalAndLog("indexFromReadOnlyTransaction = db.transaction('store', 'readonly').objectStore('store').index('index')");
286 evalAndLog("index = db.transaction('store', 'readwrite').objectStore('store').index('index')");
289 debug("IDBIndex.count()");
290 debug("If the optional key parameter is not a valid key or a key range, this method throws a DOMException of type DataError.");
291 evalAndExpectException("index.count({})", "0", "'DataError'");
292 debug("The transaction this IDBIndex belongs to is not active.");
293 evalAndExpectException("indexFromInactiveTransaction.count()", "0", "'TransactionInactiveError'");
294 // "Occurs if a request is made on a source object that has been deleted or removed." - covered in deleted-objects.html
297 debug("IDBIndex.get()");
298 debug("If the key parameter is not a valid key or a key range, this method throws a DOMException of type DataError.");
299 evalAndExpectException("index.get({})", "0", "'DataError'");
300 debug("The transaction this IDBIndex belongs to is not active.");
301 evalAndExpectException("indexFromInactiveTransaction.get(0)", "0", "'TransactionInactiveError'");
302 // "Occurs if a request is made on a source object that has been deleted or removed." - covered in deleted-objects.html
305 debug("IDBIndex.getKey()");
306 debug("If the key parameter is not a valid key or a key range, this method throws a DOMException of type DataError.");
307 evalAndExpectException("index.getKey({})", "0", "'DataError'");
308 debug("The transaction this IDBIndex belongs to is not active.");
309 evalAndExpectException("indexFromInactiveTransaction.getKey(0)", "0", "'TransactionInactiveError'");
310 // "Occurs if a request is made on a source object that has been deleted or removed." - covered in deleted-objects.html
313 debug("IDBIndex.openCursor()");
314 debug("If the range parameter is specified but is not a valid key or a key range, this method throws a DOMException of type DataError.");
315 evalAndExpectException("index.openCursor({})", "0", "'DataError'");
316 debug("The transaction this IDBIndex belongs to is not active.");
317 evalAndExpectException("indexFromInactiveTransaction.openCursor()", "0", "'TransactionInactiveError'");
318 debug("The value for the direction parameter is invalid.");
319 evalAndExpectExceptionClass("index.openCursor(0, 'invalid-direction')", "TypeError");
320 // "Occurs if a request is made on a source object that has been deleted or removed." - covered in deleted-objects.html
323 debug("IDBIndex.openKeyCursor()");
324 debug("If the range parameter is specified but is not a valid key or a key range, this method throws a DOMException of type DataError.");
325 evalAndExpectException("index.openKeyCursor({})", "0", "'DataError'");
326 debug("The transaction this IDBIndex belongs to is not active.");
327 evalAndExpectException("indexFromInactiveTransaction.openKeyCursor()", "0", "'TransactionInactiveError'");
328 debug("The value for the direction parameter is invalid.");
329 evalAndExpectExceptionClass("index.openKeyCursor(0, 'invalid-direction')", "TypeError");
330 // "Occurs if a request is made on a source object that has been deleted or removed." - covered in deleted-objects.html
335 function testCursor()
338 debug("3.2.7 Cursor");
339 evalAndLog("transaction = db.transaction(['store', 'inlineKeyStore'], 'readwrite')");
343 function makeCursor() {
344 evalAndLog("request = transaction.objectStore('store').openCursor()");
345 primaryCursorRequest = request;
346 request.onerror = unexpectedErrorCallback;
347 request.onsuccess = function() {
348 evalAndLog("cursor = request.result");
349 request.onsuccess = null;
354 function makeKeyCursor() {
355 evalAndLog("request = transaction.objectStore('store').index('index').openKeyCursor()");
356 request.onerror = unexpectedErrorCallback;
357 request.onsuccess = function() {
358 evalAndLog("keyCursor = request.result");
359 request.onsuccess = null;
364 function makeReverseCursor() {
365 evalAndLog("request = transaction.objectStore('store').openCursor(IDBKeyRange.lowerBound(-Infinity), 'prev')");
366 request.onerror = unexpectedErrorCallback;
367 request.onsuccess = function() {
368 evalAndLog("reverseCursor = request.result");
369 request.onsuccess = null;
374 function makeInlineCursor() {
375 evalAndLog("request = transaction.objectStore('inlineKeyStore').openCursor()");
376 request.onerror = unexpectedErrorCallback;
377 request.onsuccess = function() {
378 evalAndLog("inlineCursor = request.result");
379 request.onsuccess = null;
384 function testCursorAdvance() {
386 debug("IDBCursor.advance()");
387 debug("Calling this method more than once before new cursor data has been loaded is not allowed and results in a DOMException of type InvalidStateError being thrown.");
388 debug("If the value for count is 0 (zero) or a negative number, this method must throw a JavaScript TypeError exception.");
389 evalAndExpectExceptionClass("cursor.advance(0)", "TypeError");
390 evalAndLog("cursor.advance(1)");
391 evalAndExpectException("cursor.advance(1)", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
392 debug("The transaction this IDBCursor belongs to is not active.");
393 evalAndExpectException("cursorFromInactiveTransaction.advance(1)", "0", "'TransactionInactiveError'");
394 primaryCursorRequest.onsuccess = testCursorContinue;
397 function testCursorContinue() {
399 debug("IDBCursor.continue()");
400 debug("The parameter is not a valid key.");
401 evalAndExpectException("cursor.continue({})", "0", "'DataError'");
402 debug("The parameter is less than or equal to this cursor's position and this cursor's direction is \"next\" or \"nextunique\".");
403 evalAndExpectException("cursor.continue(-Infinity)", "0", "'DataError'");
404 debug("The parameter is greater than or equal to this cursor's position and this cursor's direction is \"prev\" or \"prevunique\".");
405 evalAndExpectException("reverseCursor.continue(100)", "0", "'DataError'");
406 debug("Calling this method more than once before new cursor data has been loaded is not allowed and results in a DOMException of type InvalidStateError being thrown.");
407 evalAndLog("cursor.continue()");
408 evalAndExpectException("cursor.continue()", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
409 debug("The transaction this IDBCursor belongs to is not active.");
410 evalAndExpectException("cursorFromInactiveTransaction.continue()", "0", "'TransactionInactiveError'");
414 function testCursorDelete() {
416 debug("IDBCursor.delete()");
417 debug("If this cursor's got value flag is false, or if this cursor was created using openKeyCursor a DOMException of type InvalidStateError is thrown.");
418 evalAndExpectException("keyCursor.delete()", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
419 debug("The transaction this IDBCursor belongs to is not active.");
420 evalAndExpectException("cursorFromInactiveTransaction.delete()", "0", "'TransactionInactiveError'");
421 primaryCursorRequest.onsuccess = testCursorUpdate;
424 function testCursorUpdate() {
426 debug("IDBCursor.update()");
427 debug("If this cursor's got value flag is false or if this cursor was created using openKeyCursor. This method throws a DOMException of type InvalidStateError.");
428 evalAndExpectException("keyCursor.update({})", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
429 debug("If the effective object store of this cursor uses in-line keys and evaluating the key path of the value parameter results in a different value than the cursor's effective key, this method throws a DOMException of type DataError.");
430 evalAndExpectException("inlineCursor.update({id: 1})", "0", "'DataError'");
431 debug("If the structured clone algorithm throws an exception, that exception is rethrown.");
432 evalAndExpectException("cursor.update(self)", "DOMException.DATA_CLONE_ERR"); // FIXME: Test 'DataCloneError' name when DOM4 exceptions are used in binding.
433 debug("The transaction this IDBCursor belongs to is not active.");
434 evalAndExpectException("cursorFromInactiveTransaction.update({})", "0", "'TransactionInactiveError'");
436 primaryCursorRequest.onsuccess = null;
437 makeReadOnlyCursor();
440 // Can't have both transactions running at once, so these tests must be separated out.
441 function makeReadOnlyCursor() {
442 evalAndLog("readOnlyTransaction = db.transaction('store', 'readonly')");
443 evalAndLog("request = readOnlyTransaction.objectStore('store').openCursor()");
444 request.onerror = unexpectedErrorCallback;
445 request.onsuccess = function() {
446 evalAndLog("cursorFromReadOnlyTransaction = request.result");
447 doReadOnlyCursorTests();
451 function doReadOnlyCursorTests() {
453 debug("One more IDBCursor.delete() test:");
454 debug('This method throws a DOMException of type ReadOnlyError if the transaction which this IDBCursor belongs to has its mode set to "readonly".');
455 evalAndExpectException("cursorFromReadOnlyTransaction.delete()", "0", "'ReadOnlyError'");
458 debug("One more IDBCursor.update() test:");
459 debug('This method throws a DOMException of type ReadOnlyError if the transaction which this IDBCursor belongs to has its mode set to "readonly".');
460 evalAndExpectException("cursorFromReadOnlyTransaction.update({})", "0", "'ReadOnlyError'");
466 function testTransaction()
469 debug("3.2.8 Transaction");
472 debug("IDBTransaction.abort()");
473 debug("If this transaction is finished, throw a DOMException of type InvalidStateError. ");
474 evalAndExpectException("finishedTransaction.abort()", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
475 debug("If the requested object store is not in this transaction's scope.");
476 evalAndExpectException("db.transaction('store').objectStore('otherStore')", "DOMException.NOT_FOUND_ERR", "'NotFoundError'");