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