test_transaction_abort.js (10834B)
1 /** 2 * Any copyright is dedicated to the Public Domain. 3 * http://creativecommons.org/publicdomain/zero/1.0/ 4 */ 5 6 var testGenerator = testSteps(); 7 8 var abortFired = false; 9 10 function abortListener(evt) { 11 abortFired = true; 12 is(evt.target.error, null, "Expect a null error for an aborted transaction"); 13 } 14 15 function* testSteps() { 16 const name = this.window ? window.location.pathname : "Splendid Test"; 17 18 let request = indexedDB.open(name, 1); 19 request.onerror = errorHandler; 20 request.onupgradeneeded = grabEventAndContinueHandler; 21 request.onsuccess = grabEventAndContinueHandler; 22 let event = yield undefined; 23 24 let db = event.target.result; 25 db.onabort = abortListener; 26 27 let transaction; 28 let objectStore; 29 let index; 30 31 transaction = event.target.transaction; 32 33 is(transaction.error, null, "Expect a null error"); 34 35 objectStore = db.createObjectStore("foo", { autoIncrement: true }); 36 index = objectStore.createIndex("fooindex", "indexKey", { unique: true }); 37 38 is(transaction.db, db, "Correct database"); 39 is(transaction.mode, "versionchange", "Correct mode"); 40 is(transaction.objectStoreNames.length, 1, "Correct names length"); 41 is(transaction.objectStoreNames.item(0), "foo", "Correct name"); 42 is(transaction.objectStore("foo"), objectStore, "Can get stores"); 43 is(transaction.oncomplete, null, "No complete listener"); 44 is(transaction.onabort, null, "No abort listener"); 45 46 is(objectStore.name, "foo", "Correct name"); 47 is(objectStore.keyPath, null, "Correct keyPath"); 48 49 is(objectStore.indexNames.length, 1, "Correct indexNames length"); 50 is(objectStore.indexNames[0], "fooindex", "Correct indexNames name"); 51 is(objectStore.index("fooindex"), index, "Can get index"); 52 53 // Wait until it's complete! 54 transaction.oncomplete = grabEventAndContinueHandler; 55 event = yield undefined; 56 57 is(transaction.db, db, "Correct database"); 58 is(transaction.mode, "versionchange", "Correct mode"); 59 is(transaction.objectStoreNames.length, 1, "Correct names length"); 60 is(transaction.objectStoreNames.item(0), "foo", "Correct name"); 61 is(transaction.onabort, null, "No abort listener"); 62 63 try { 64 is(transaction.objectStore("foo").name, "foo", "Can't get stores"); 65 ok(false, "Should have thrown"); 66 } catch (e) { 67 ok(true, "Out of scope transaction can't make stores"); 68 } 69 70 is(objectStore.name, "foo", "Correct name"); 71 is(objectStore.keyPath, null, "Correct keyPath"); 72 73 is(objectStore.indexNames.length, 1, "Correct indexNames length"); 74 is(objectStore.indexNames[0], "fooindex", "Correct indexNames name"); 75 76 try { 77 objectStore.add({}); 78 ok(false, "Should have thrown"); 79 } catch (e) { 80 ok(true, "Add threw"); 81 } 82 83 try { 84 objectStore.put({}, 1); 85 ok(false, "Should have thrown"); 86 } catch (e) { 87 ok(true, "Put threw"); 88 } 89 90 try { 91 objectStore.put({}, 1); 92 ok(false, "Should have thrown"); 93 } catch (e) { 94 ok(true, "Put threw"); 95 } 96 97 try { 98 objectStore.delete(1); 99 ok(false, "Should have thrown"); 100 } catch (e) { 101 ok(true, "Remove threw"); 102 } 103 104 try { 105 objectStore.get(1); 106 ok(false, "Should have thrown"); 107 } catch (e) { 108 ok(true, "Get threw"); 109 } 110 111 try { 112 objectStore.getAll(null); 113 ok(false, "Should have thrown"); 114 } catch (e) { 115 ok(true, "GetAll threw"); 116 } 117 118 try { 119 objectStore.openCursor(); 120 ok(false, "Should have thrown"); 121 } catch (e) { 122 ok(true, "OpenCursor threw"); 123 } 124 125 try { 126 objectStore.createIndex("bar", "id"); 127 ok(false, "Should have thrown"); 128 } catch (e) { 129 ok(true, "CreateIndex threw"); 130 } 131 132 try { 133 objectStore.index("bar"); 134 ok(false, "Should have thrown"); 135 } catch (e) { 136 ok(true, "Index threw"); 137 } 138 139 try { 140 objectStore.deleteIndex("bar"); 141 ok(false, "Should have thrown"); 142 } catch (e) { 143 ok(true, "RemoveIndex threw"); 144 } 145 146 yield undefined; 147 148 request = db.transaction("foo", "readwrite").objectStore("foo").add({}); 149 request.onerror = errorHandler; 150 request.onsuccess = grabEventAndContinueHandler; 151 event = yield undefined; 152 153 event.target.transaction.onabort = function () { 154 ok(false, "Shouldn't see an abort event!"); 155 }; 156 event.target.transaction.oncomplete = grabEventAndContinueHandler; 157 event = yield undefined; 158 159 is(event.type, "complete", "Right kind of event"); 160 161 let key; 162 163 request = db.transaction("foo", "readwrite").objectStore("foo").add({}); 164 request.onerror = errorHandler; 165 request.onsuccess = grabEventAndContinueHandler; 166 event = yield undefined; 167 168 key = event.target.result; 169 170 event.target.transaction.onabort = grabEventAndContinueHandler; 171 event.target.transaction.oncomplete = function () { 172 ok(false, "Shouldn't see a complete event here!"); 173 }; 174 175 event.target.transaction.abort(); 176 177 event = yield undefined; 178 179 is(event.type, "abort", "Right kind of event"); 180 181 request = db.transaction("foo").objectStore("foo").get(key); 182 request.onerror = errorHandler; 183 request.onsuccess = grabEventAndContinueHandler; 184 event = yield undefined; 185 186 is(event.target.result, undefined, "Object was removed"); 187 188 executeSoon(function () { 189 testGenerator.next(); 190 }); 191 yield undefined; 192 193 let keys = []; 194 let abortEventCount = 0; 195 function abortErrorHandler(event) { 196 is(event.target.error.name, "AbortError", "Good error"); 197 abortEventCount++; 198 event.preventDefault(); 199 } 200 objectStore = db.transaction("foo", "readwrite").objectStore("foo"); 201 202 for (let i = 0; i < 10; i++) { 203 request = objectStore.add({}); 204 request.onerror = abortErrorHandler; 205 request.onsuccess = function (event) { 206 keys.push(event.target.result); 207 if (keys.length == 5) { 208 event.target.transaction.onabort = grabEventAndContinueHandler; 209 event.target.transaction.abort(); 210 } 211 }; 212 } 213 event = yield undefined; 214 215 is(event.type, "abort", "Got abort event"); 216 is(keys.length, 5, "Added 5 items in this transaction"); 217 is(abortEventCount, 5, "Got 5 abort error events"); 218 219 for (let i in keys) { 220 request = db.transaction("foo").objectStore("foo").get(keys[i]); 221 request.onerror = errorHandler; 222 request.onsuccess = grabEventAndContinueHandler; 223 event = yield undefined; 224 225 is(event.target.result, undefined, "Object was removed by abort"); 226 } 227 228 // Set up some predictible data 229 transaction = db.transaction("foo", "readwrite"); 230 objectStore = transaction.objectStore("foo"); 231 objectStore.clear(); 232 objectStore.add({}, 1); 233 objectStore.add({}, 2); 234 request = objectStore.add({}, 1); 235 request.onsuccess = function () { 236 ok(false, "inserting duplicate key should fail"); 237 }; 238 request.onerror = function (event) { 239 ok(true, "inserting duplicate key should fail"); 240 event.preventDefault(); 241 }; 242 transaction.oncomplete = grabEventAndContinueHandler; 243 yield undefined; 244 245 // Check when aborting is allowed 246 abortEventCount = 0; 247 let expectedAbortEventCount = 0; 248 249 // During INITIAL 250 transaction = db.transaction("foo"); 251 transaction.abort(); 252 try { 253 transaction.abort(); 254 ok(false, "second abort should throw an error"); 255 } catch (ex) { 256 ok(true, "second abort should throw an error"); 257 } 258 259 // During LOADING 260 transaction = db.transaction("foo"); 261 transaction.objectStore("foo").get(1).onerror = abortErrorHandler; 262 expectedAbortEventCount++; 263 transaction.abort(); 264 try { 265 transaction.abort(); 266 ok(false, "second abort should throw an error"); 267 } catch (ex) { 268 ok(true, "second abort should throw an error"); 269 } 270 271 // During LOADING from callback 272 transaction = db.transaction("foo"); 273 transaction.objectStore("foo").get(1).onsuccess = grabEventAndContinueHandler; 274 event = yield undefined; 275 transaction.objectStore("foo").get(1).onerror = abortErrorHandler; 276 expectedAbortEventCount++; 277 transaction.abort(); 278 try { 279 transaction.abort(); 280 ok(false, "second abort should throw an error"); 281 } catch (ex) { 282 ok(true, "second abort should throw an error"); 283 } 284 285 // During LOADING from error callback 286 transaction = db.transaction("foo", "readwrite"); 287 transaction.objectStore("foo").add({}, 1).onerror = function (event) { 288 event.preventDefault(); 289 290 transaction.objectStore("foo").get(1).onerror = abortErrorHandler; 291 expectedAbortEventCount++; 292 293 transaction.abort(); 294 continueToNextStep(); 295 }; 296 yield undefined; 297 298 // In between callbacks 299 transaction = db.transaction("foo"); 300 function makeNewRequest() { 301 let r = transaction.objectStore("foo").get(1); 302 r.onsuccess = makeNewRequest; 303 r.onerror = abortErrorHandler; 304 } 305 makeNewRequest(); 306 transaction.objectStore("foo").get(1).onsuccess = function () { 307 executeSoon(function () { 308 transaction.abort(); 309 expectedAbortEventCount++; 310 continueToNextStep(); 311 }); 312 }; 313 yield undefined; 314 315 // During COMMITTING 316 transaction = db.transaction("foo", "readwrite"); 317 transaction.objectStore("foo").put({ hello: "world" }, 1).onsuccess = 318 function () { 319 continueToNextStep(); 320 }; 321 yield undefined; 322 try { 323 transaction.abort(); 324 ok(false, "second abort should throw an error"); 325 } catch (ex) { 326 ok(true, "second abort should throw an error"); 327 } 328 transaction.oncomplete = grabEventAndContinueHandler; 329 event = yield undefined; 330 331 // Since the previous transaction shouldn't have caused any error events, 332 // we know that all events should have fired by now. 333 is(abortEventCount, expectedAbortEventCount, "All abort errors fired"); 334 335 // Abort both failing and succeeding requests 336 transaction = db.transaction("foo", "readwrite"); 337 transaction.onabort = transaction.oncomplete = grabEventAndContinueHandler; 338 transaction.objectStore("foo").add({ indexKey: "key" }).onsuccess = 339 function () { 340 transaction.abort(); 341 }; 342 let request1 = transaction.objectStore("foo").add({ indexKey: "key" }); 343 request1.onsuccess = grabEventAndContinueHandler; 344 request1.onerror = grabEventAndContinueHandler; 345 let request2 = transaction.objectStore("foo").get(1); 346 request2.onsuccess = grabEventAndContinueHandler; 347 request2.onerror = grabEventAndContinueHandler; 348 349 event = yield undefined; 350 is(event.type, "error", "abort() should make all requests fail"); 351 is(event.target, request1, "abort() should make all requests fail"); 352 is( 353 event.target.error.name, 354 "AbortError", 355 "abort() should make all requests fail" 356 ); 357 event.preventDefault(); 358 359 event = yield undefined; 360 is(event.type, "error", "abort() should make all requests fail"); 361 is(event.target, request2, "abort() should make all requests fail"); 362 is( 363 event.target.error.name, 364 "AbortError", 365 "abort() should make all requests fail" 366 ); 367 event.preventDefault(); 368 369 event = yield undefined; 370 is(event.type, "abort", "transaction should fail"); 371 is(event.target, transaction, "transaction should fail"); 372 373 ok(abortFired, "Abort should have fired!"); 374 375 finishTest(); 376 }