Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / LayoutTests / storage / indexeddb / resources / exceptions.js
1 if (this.importScripts) {
2     importScripts('../../../resources/js-test.js');
3     importScripts('shared.js');
4 }
5
6 description("Test that expected exceptions are thrown per IndexedDB spec.");
7
8 indexedDBTest(prepareDatabase, testDatabase);
9 function prepareDatabase()
10 {
11     db = event.target.result;
12
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'})");
27
28     evalAndLog("request = inlineKeyStore.put({id: 0})");
29     shouldBeEqualToString("request.readyState", "pending");
30
31     debug("");
32     debug("3.2.1 The IDBRequest Interface");
33
34     debug("");
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'");
38
39     debug("");
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'");
43
44     debug("");
45     debug("3.2.3 Opening a database");
46
47     debug("");
48     debug("IDBFactory.cmp()");
49     debug("One of the supplied keys was not a valid key.");
50     evalAndExpectException("indexedDB.cmp(null, 0)", "0", "'DataError'");
51 }
52
53 function testDatabase()
54 {
55     evalAndLog("db.close()");
56
57     debug("");
58     debug("3.2.4 Database");
59
60     request = evalAndLog("indexedDB.open(dbname, 2)");
61     request.onerror = unexpectedErrorCallback;
62     request.onblocked = unexpectedBlockedCallback;
63     request.onsuccess = checkTransactionAndObjectStoreExceptions;
64     request.onupgradeneeded = function() {
65         db = request.result;
66         var trans = request.transaction;
67         trans.onabort = unexpectedAbortCallback;
68
69         debug("");
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'");
78
79         debug("");
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'");
83
84         debug("");
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'");
88     };
89 }
90
91 function checkTransactionAndObjectStoreExceptions()
92 {
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'");
101
102     debug("");
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'");
106
107     debug("");
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'");
111
112     prepareStoreAndIndex();
113 }
114
115 function prepareStoreAndIndex()
116 {
117     debug("");
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");
127     };
128     inactiveTransaction.oncomplete = testObjectStore;
129 }
130
131 function testObjectStore()
132 {
133     debug("");
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')");
139
140     debug("");
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.
150
151     debug("");
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
158
159     debug("");
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
166
167     debug("");
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
176
177     debug("");
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
184
185     debug("");
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
192
193     debug("");
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
202
203     debug("");
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
212
213     debug("");
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.
223
224     evalAndLog("db.close()");
225     evalAndLog("ro_transaction.oncomplete = transactionComplete");
226     evalAndLog("rw_transaction.oncomplete = transactionComplete");
227 }
228
229 var numCompleted = 0;
230 function transactionComplete(evt)
231 {
232     preamble(evt);
233     numCompleted++;
234     if (numCompleted == 1) {
235         debug("First transaction completed");
236         return;
237     }
238     evalAndLog("request = indexedDB.open(dbname, 3)");
239     request.onerror = unexpectedErrorCallback;
240     request.onblocked = unexpectedBlockedCallback;
241     evalAndLog("request.onupgradeneeded = onUpgradeNeeded3");
242 }
243
244 function onUpgradeNeeded3()
245 {
246     db = request.result;
247     var trans = request.transaction;
248     trans.onabort = unexpectedAbortCallback;
249     trans.oncomplete = testOutsideVersionChangeTransaction;
250     store = trans.objectStore('store');
251
252     debug("");
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
261
262     debug("");
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'");
266 }
267
268 function testOutsideVersionChangeTransaction() {
269     debug("");
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'");
273
274     debug("");
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'");
278     testIndex();
279 }
280
281 function testIndex()
282 {
283     debug("");
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')");
287
288     debug("");
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
295
296     debug("");
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
303
304     debug("");
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
311
312     debug("");
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
321
322     debug("");
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
331
332     testCursor();
333 }
334
335 function testCursor()
336 {
337     debug("");
338     debug("3.2.7 Cursor");
339     evalAndLog("transaction = db.transaction(['store', 'inlineKeyStore'], 'readwrite')");
340
341     makeCursor();
342
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;
350             makeKeyCursor();
351         };
352     }
353
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;
360             makeReverseCursor();
361         };
362     }
363
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;
370             makeInlineCursor();
371         };
372     }
373
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;
380             testCursorAdvance();
381         };
382     }
383
384     function testCursorAdvance() {
385         debug("");
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;
395     }
396
397     function testCursorContinue() {
398         debug("");
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'");
411         testCursorDelete();
412     }
413
414     function testCursorDelete() {
415         debug("");
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;
422     }
423
424     function testCursorUpdate() {
425         debug("");
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'");
435
436         primaryCursorRequest.onsuccess = null;
437         makeReadOnlyCursor();
438     }
439
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();
448         };
449     }
450
451     function doReadOnlyCursorTests() {
452        debug("");
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'");
456
457        debug("");
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'");
461
462        testTransaction();
463     }
464 }
465
466 function testTransaction()
467 {
468     debug("");
469     debug("3.2.8 Transaction");
470
471     debug("");
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'");
477
478     finishJSTest();
479 }