test_transaction_abort.js 11 KB

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