UNPKG

66.4 kBJavaScriptView Raw
1/* global after:true, afterEach:true, before:true, beforeEach:true, describe:true, expect:true, it:true, Promise:true */
2var DRIVERS = [
3 localforage.INDEXEDDB,
4 localforage.LOCALSTORAGE,
5 localforage.WEBSQL
6];
7
8var SUPPORTED_DRIVERS = DRIVERS.filter(function(driverName) {
9 return localforage.supports(driverName);
10});
11
12var driverApiMethods = [
13 'getItem',
14 'setItem',
15 'clear',
16 'length',
17 'removeItem',
18 'key',
19 'keys'
20];
21
22// eslint-disable-next-line no-use-before-define
23var indexedDB = (indexedDB || window.indexedDB ||
24 window.webkitIndexedDB ||
25 window.mozIndexedDB || window.OIndexedDB ||
26 window.msIndexedDB);
27
28describe('localForage API', function() {
29 // https://github.com/mozilla/localForage#working-on-localforage
30 it('has Promises available', function() {
31 expect(Promise).to.be.a('function');
32 });
33});
34
35describe('localForage', function() {
36 var appropriateDriver =
37 (localforage.supports(localforage.INDEXEDDB) &&
38 localforage.INDEXEDDB) ||
39 (localforage.supports(localforage.WEBSQL) &&
40 localforage.WEBSQL) ||
41 (localforage.supports(localforage.LOCALSTORAGE) &&
42 localforage.LOCALSTORAGE);
43
44 it('automatically selects the most appropriate driver (' +
45 appropriateDriver + ')', function(done) {
46 this.timeout(10000);
47 localforage.ready().then(function() {
48 expect(localforage.driver()).to.be(appropriateDriver);
49 done();
50 }, function(error) {
51 expect(error).to.be.an(Error);
52 expect(error.message).to
53 .be('No available storage method found.');
54 expect(localforage.driver()).to.be(null);
55 done();
56 });
57 });
58
59 it('errors when a requested driver is not found [callback]', function(done) {
60 localforage.getDriver('UnknownDriver', null, function(error) {
61 expect(error).to.be.an(Error);
62 expect(error.message).to
63 .be('Driver not found.');
64 done();
65 });
66 });
67
68 it('errors when a requested driver is not found [promise]', function(done) {
69 localforage.getDriver('UnknownDriver').then(null, function(error) {
70 expect(error).to.be.an(Error);
71 expect(error.message).to
72 .be('Driver not found.');
73 done();
74 });
75 });
76
77 it('retrieves the serializer [callback]', function(done) {
78 localforage.getSerializer(function(serializer) {
79 expect(serializer).to.be.an('object');
80 done();
81 });
82 });
83
84 it('retrieves the serializer [promise]', function(done) {
85 var serializerPromise = localforage.getSerializer();
86 expect(serializerPromise).to.be.an('object');
87 expect(serializerPromise.then).to.be.a('function');
88
89 serializerPromise.then(function(serializer) {
90 expect(serializer).to.be.an('object');
91 done();
92 });
93 });
94
95 it('does not support object parameter to setDriver', function(done) {
96 var driverPreferedOrder = {
97 '0': localforage.INDEXEDDB,
98 '1': localforage.WEBSQL,
99 '2': localforage.LOCALSTORAGE,
100 length: 3
101 };
102
103 localforage.setDriver(driverPreferedOrder).then(null, function(error) {
104 expect(error).to.be.an(Error);
105 expect(error.message).to
106 .be('No available storage method found.');
107 done();
108 });
109 });
110
111 it('skips drivers that fail to initilize', function(done) {
112 var failingStorageDriver = (function() {
113 function driverDummyMethod() {
114 return Promise.reject(new Error('Driver Method Failed.'));
115 }
116
117 return {
118 _driver: 'failingStorageDriver',
119 _initStorage: function _initStorage() {
120 return Promise.reject(new Error('Driver Failed to Initialize.'));
121 },
122 iterate: driverDummyMethod,
123 getItem: driverDummyMethod,
124 setItem: driverDummyMethod,
125 removeItem: driverDummyMethod,
126 clear: driverDummyMethod,
127 length: driverDummyMethod,
128 key: driverDummyMethod,
129 keys: driverDummyMethod
130 };
131 })();
132
133 var driverPreferedOrder = [
134 failingStorageDriver._driver,
135 localforage.INDEXEDDB,
136 localforage.WEBSQL,
137 localforage.LOCALSTORAGE
138 ];
139
140 localforage.defineDriver(failingStorageDriver).then(function() {
141 return localforage.setDriver(driverPreferedOrder);
142 }).then(function() {
143 return localforage.ready();
144 }).then(function() {
145 expect(localforage.driver()).to.be(appropriateDriver);
146 done();
147 });
148
149 });
150
151 describe('createInstance()', function() {
152 var oldConsoleInfo;
153
154 before(function() {
155 oldConsoleInfo = console.info;
156 var logs = [];
157 console.info = function() {
158 console.info.logs.push({
159 args: arguments
160 });
161 oldConsoleInfo.apply(this, arguments);
162 };
163 console.info.logs = logs;
164 });
165
166 after(function() {
167 console.info = oldConsoleInfo;
168 });
169
170 it('does not log unnecessary messages', function() {
171 var oldLogCount = console.info.logs.length;
172 var localforage2 = localforage.createInstance();
173 var localforage3 = localforage.createInstance();
174
175 return Promise.all([
176 localforage.ready(),
177 localforage2.ready(),
178 localforage3.ready()
179 ]).then(function() {
180 expect(console.info.logs.length).to.be(oldLogCount);
181 });
182 });
183 });
184
185});
186
187SUPPORTED_DRIVERS.forEach(function(driverName) {
188 describe(driverName + ' driver', function() {
189 'use strict';
190
191 this.timeout(30000);
192
193 before(function(done) {
194 localforage.setDriver(driverName).then(done);
195 });
196
197 beforeEach(function(done) {
198 localStorage.clear();
199 localforage.ready().then(function() {
200 localforage.clear(done);
201 });
202 });
203
204 it('has a localStorage API', function() {
205 expect(localforage.getItem).to.be.a('function');
206 expect(localforage.setItem).to.be.a('function');
207 expect(localforage.clear).to.be.a('function');
208 expect(localforage.length).to.be.a('function');
209 expect(localforage.removeItem).to.be.a('function');
210 expect(localforage.key).to.be.a('function');
211 });
212
213 it('has the localForage API', function() {
214 expect(localforage._initStorage).to.be.a('function');
215 expect(localforage.config).to.be.a('function');
216 expect(localforage.defineDriver).to.be.a('function');
217 expect(localforage.driver).to.be.a('function');
218 expect(localforage.supports).to.be.a('function');
219 expect(localforage.iterate).to.be.a('function');
220 expect(localforage.getItem).to.be.a('function');
221 expect(localforage.setItem).to.be.a('function');
222 expect(localforage.clear).to.be.a('function');
223 expect(localforage.length).to.be.a('function');
224 expect(localforage.removeItem).to.be.a('function');
225 expect(localforage.key).to.be.a('function');
226 expect(localforage.getDriver).to.be.a('function');
227 expect(localforage.setDriver).to.be.a('function');
228 expect(localforage.ready).to.be.a('function');
229 expect(localforage.createInstance).to.be.a('function');
230 expect(localforage.getSerializer).to.be.a('function');
231 expect(localforage.dropInstance).to.be.a('function');
232 });
233
234 // Make sure we don't support bogus drivers.
235 it('supports ' + driverName + ' database driver', function() {
236 expect(localforage.supports(driverName) === true);
237 expect(localforage.supports('I am not a driver') === false);
238 });
239
240 it('sets the right database driver', function() {
241 expect(localforage.driver() === driverName);
242 });
243
244 it('has an empty length by default', function(done) {
245 localforage.length(function(err, length) {
246 expect(length).to.be(0);
247 done();
248 });
249 });
250
251 if (driverName === localforage.INDEXEDDB) {
252 describe('Blob support', function() {
253 var transaction;
254 var called;
255 var db;
256 var blob = new Blob([''], {type: 'image/png'});
257
258 before(function() {
259 db = localforage._dbInfo.db;
260 transaction = db.transaction;
261 db.transaction = function() {
262 called += 1;
263 return transaction.apply(db, arguments);
264 };
265 });
266
267 beforeEach(function() {
268 called = 0;
269 });
270
271 it('not check for non Blob', function(done) {
272 localforage.setItem('key', {}).then(function() {
273 expect(called).to.be(1);
274 done();
275 }, function(error) {
276 done(error || 'error');
277 });
278 });
279
280 it('check for Blob', function(done) {
281 localforage.setItem('key', blob).then(function() {
282 expect(called).to.be.above(1);
283 done();
284 }, function(error) {
285 done(error || 'error');
286 });
287 });
288
289 it('check for Blob once', function(done) {
290 localforage.setItem('key', blob).then(function() {
291 expect(called).to.be(1);
292 done();
293 }, function(error) {
294 done(error || 'error');
295 });
296 });
297
298 after(function() {
299 localforage._dbInfo.db.transaction = transaction;
300 });
301 });
302
303 describe('recover (reconnect) from IDBDatabase InvalidStateError', function() {
304
305 beforeEach(function(done) {
306 Promise.all([
307 localforage.setItem('key', 'value1'),
308 localforage.setItem('key1', 'value1'),
309 localforage.setItem('key2', 'value2'),
310 localforage.setItem('key3', 'value3')
311 ]).then(function() {
312 localforage._dbInfo.db.close();
313 done();
314 }, function(error) {
315 done(error || 'error');
316 });
317 });
318
319 it('retrieves an item from the storage', function(done) {
320 localforage.getItem('key').then(function(value) {
321 expect(value).to.be('value1');
322 done();
323 }, function(error) {
324 done(error || 'error');
325 });
326 });
327
328 it('retrieves more than one items from the storage', function(done) {
329 Promise.all([
330 localforage.getItem('key1'),
331 localforage.getItem('key2'),
332 localforage.getItem('key3')
333 ]).then(function(values) {
334 expect(values).to.eql([
335 'value1',
336 'value2',
337 'value3'
338 ]);
339 done();
340 }, function(error) {
341 done(error || 'error');
342 });
343 });
344
345 it('stores and retrieves an item from the storage', function(done) {
346 localforage.setItem('key', 'value1b').then(function() {
347 return localforage.getItem('key');
348 }).then(function(value) {
349 expect(value).to.be('value1b');
350 done();
351 }, function(error) {
352 done(error || 'error');
353 });
354 });
355
356 it('stores and retrieves more than one items from the storage', function(done) {
357 Promise.all([
358 localforage.setItem('key1', 'value1b'),
359 localforage.setItem('key2', 'value2b'),
360 localforage.setItem('key3', 'value3b')
361 ]).then(function() {
362 return Promise.all([
363 localforage.getItem('key1'),
364 localforage.getItem('key2'),
365 localforage.getItem('key3')
366 ]);
367 }).then(function(values) {
368 expect(values).to.eql([
369 'value1b',
370 'value2b',
371 'value3b'
372 ]);
373 done();
374 }, function(error) {
375 done(error || 'error');
376 });
377 });
378 });
379 }
380
381 if (driverName === localforage.WEBSQL) {
382 describe('on QUOTA ERROR', function() {
383 var transaction;
384 var called;
385 var db;
386
387 function getQuotaErrorCode(transaction) {
388 return new Promise(function(resolve) {
389 transaction(function(t) {
390 t.executeSql('');
391 }, function(err) {
392 resolve(err.QUOTA_ERR);
393 });
394 }).catch(function(err) {
395 return err.QUOTA_ERR;
396 });
397 }
398
399 beforeEach(function() {
400 called = 0;
401 db = localforage._dbInfo.db;
402 transaction = db.transaction;
403
404 db.transaction = function(fn, errFn) {
405 called += 1;
406 // restore the normal transaction,
407 // so that subsequent operations work
408 db.transaction = transaction;
409
410 getQuotaErrorCode(transaction).then(function(QUOTA_ERR) {
411 var error = new Error();
412 error.code = QUOTA_ERR;
413 errFn(error);
414 });
415 };
416 });
417
418 it('should retry setItem', function(done) {
419 localforage.setItem('key', {}).then(function() {
420 expect(called).to.be(1);
421 done();
422 }, function(error) {
423 done(error || 'error');
424 });
425 });
426
427 after(function() {
428 db.transaction = transaction || db.transaction;
429 });
430 });
431 }
432
433 it('should iterate [callback]', function(done) {
434 localforage.setItem('officeX', 'InitechX', function(err, setValue) {
435 expect(setValue).to.be('InitechX');
436
437 localforage.getItem('officeX', function(err, value) {
438 expect(value).to.be(setValue);
439
440 localforage.setItem('officeY', 'InitechY', function(err, setValue) {
441 expect(setValue).to.be('InitechY');
442
443 localforage.getItem('officeY', function(err, value) {
444 expect(value).to.be(setValue);
445
446 var accumulator = {};
447 var iterationNumbers = [];
448
449 localforage.iterate(function(value, key, iterationNumber) {
450 accumulator[key] = value;
451 iterationNumbers.push(iterationNumber);
452 }, function() {
453 try {
454 expect(accumulator.officeX).to.be('InitechX');
455 expect(accumulator.officeY).to.be('InitechY');
456 expect(iterationNumbers).to.eql([1, 2]);
457 done();
458 } catch (e) {
459 done(e);
460 }
461 });
462 });
463 });
464 });
465 });
466 });
467
468 it('should iterate [promise]', function(done) {
469 var accumulator = {};
470 var iterationNumbers = [];
471
472 return localforage.setItem('officeX',
473 'InitechX').then(function(setValue) {
474 expect(setValue).to.be('InitechX');
475 return localforage.getItem('officeX');
476 }).then(function(value) {
477 expect(value).to.be('InitechX');
478 return localforage.setItem('officeY', 'InitechY');
479 }).then(function(setValue) {
480 expect(setValue).to.be('InitechY');
481 return localforage.getItem('officeY');
482 }).then(function(value) {
483 expect(value).to.be('InitechY');
484
485 return localforage.iterate(function(value, key,
486 iterationNumber) {
487 accumulator[key] = value;
488 iterationNumbers.push(iterationNumber);
489 });
490 }).then(function() {
491 expect(accumulator.officeX).to.be('InitechX');
492 expect(accumulator.officeY).to.be('InitechY');
493 expect(iterationNumbers).to.eql([1, 2]);
494 done();
495 });
496 });
497
498 it('should break iteration with defined return value [callback]', function(done) {
499 var breakCondition = 'Some value!';
500
501 localforage.setItem('officeX', 'InitechX', function(err, setValue) {
502 expect(setValue).to.be('InitechX');
503
504 localforage.getItem('officeX', function(err, value) {
505 expect(value).to.be(setValue);
506
507 localforage.setItem('officeY', 'InitechY', function(err, setValue) {
508 expect(setValue).to.be('InitechY');
509
510 localforage.getItem('officeY', function(err, value) {
511 expect(value).to.be(setValue);
512
513 // Loop is broken within first iteration.
514 localforage.iterate(function() {
515 // Returning defined value will break the cycle.
516 return breakCondition;
517 }, function(err, loopResult) {
518 // The value that broken the cycle is returned
519 // as a result.
520 expect(loopResult).to.be(breakCondition);
521
522 done();
523 });
524 });
525 });
526 });
527 });
528 });
529
530 it('should break iteration with defined return value [promise]', function(done) {
531 var breakCondition = 'Some value!';
532
533 localforage.setItem('officeX', 'InitechX').then(function(setValue) {
534 expect(setValue).to.be('InitechX');
535 return localforage.getItem('officeX');
536 }).then(function(value) {
537 expect(value).to.be('InitechX');
538 return localforage.setItem('officeY', 'InitechY');
539 }).then(function(setValue) {
540 expect(setValue).to.be('InitechY');
541 return localforage.getItem('officeY');
542 }).then(function(value) {
543 expect(value).to.be('InitechY');
544 return localforage.iterate(function() {
545 return breakCondition;
546 });
547 }).then(function(result) {
548 expect(result).to.be(breakCondition);
549 done();
550 });
551 });
552
553 it('should iterate() through only its own keys/values', function(done) {
554 localStorage.setItem('local', 'forage');
555 localforage.setItem('office', 'Initech').then(function() {
556 return localforage.setItem('name', 'Bob');
557 }).then(function() {
558 // Loop through all key/value pairs; {local: 'forage'} set
559 // manually should not be returned.
560 var numberOfItems = 0;
561 var iterationNumberConcat = '';
562
563 localStorage.setItem('locals', 'forages');
564
565 localforage.iterate(function(value, key, iterationNumber) {
566 expect(key).to.not.be('local');
567 expect(value).to.not.be('forage');
568 numberOfItems++;
569 iterationNumberConcat += iterationNumber;
570 }, function(err) {
571 if (!err) {
572 // While there are 4 items in localStorage,
573 // only 2 items were set using localForage.
574 expect(numberOfItems).to.be(2);
575
576 // Only 2 items were set using localForage,
577 // so we should get '12' and not '1234'
578 expect(iterationNumberConcat).to.be('12');
579
580 done();
581 }
582 });
583 });
584 });
585
586 // Test for https://github.com/mozilla/localForage/issues/175
587 it('nested getItem inside clear works [callback]', function(done) {
588 localforage.setItem('hello', 'Hello World !', function() {
589 localforage.clear(function() {
590 localforage.getItem('hello', function(secondValue) {
591 expect(secondValue).to.be(null);
592 done();
593 });
594 });
595 });
596 });
597 it('nested getItem inside clear works [promise]', function(done) {
598 localforage.setItem('hello', 'Hello World !').then(function() {
599 return localforage.clear();
600 }).then(function() {
601 return localforage.getItem('hello');
602 }).then(function(secondValue) {
603 expect(secondValue).to.be(null);
604 done();
605 });
606 });
607
608 // Because localStorage doesn't support saving the `undefined` type, we
609 // always return `null` so that localForage is consistent across
610 // browsers.
611 // https://github.com/mozilla/localForage/pull/42
612 it('returns null for undefined key [callback]', function(done) {
613 localforage.getItem('key', function(err, value) {
614 expect(value).to.be(null);
615 done();
616 });
617 });
618
619 it('returns null for undefined key [promise]', function(done) {
620 localforage.getItem('key').then(function(value) {
621 expect(value).to.be(null);
622 done();
623 });
624 });
625
626 it('saves an item [callback]', function(done) {
627 localforage.setItem('office', 'Initech', function(err, setValue) {
628 expect(setValue).to.be('Initech');
629
630 localforage.getItem('office', function(err, value) {
631 expect(value).to.be(setValue);
632 done();
633 });
634 });
635 });
636
637 it('saves an item [promise]', function(done) {
638 localforage.setItem('office', 'Initech').then(function(setValue) {
639 expect(setValue).to.be('Initech');
640
641 return localforage.getItem('office');
642 }).then(function(value) {
643 expect(value).to.be('Initech');
644 done();
645 });
646 });
647
648 it('saves an item over an existing key [callback]', function(done) {
649 localforage.setItem('4th floor', 'Mozilla', function(err, setValue) {
650 expect(setValue).to.be('Mozilla');
651
652 localforage.setItem('4th floor', 'Quora', function(err, newValue) {
653 expect(newValue).to.not.be(setValue);
654 expect(newValue).to.be('Quora');
655
656 localforage.getItem('4th floor', function(err, value) {
657 expect(value).to.not.be(setValue);
658 expect(value).to.be(newValue);
659 done();
660 });
661 });
662 });
663 });
664 it('saves an item over an existing key [promise]', function(done) {
665 localforage.setItem('4e', 'Mozilla').then(function(setValue) {
666 expect(setValue).to.be('Mozilla');
667
668 return localforage.setItem('4e', 'Quora');
669 }).then(function(newValue) {
670 expect(newValue).to.not.be('Mozilla');
671 expect(newValue).to.be('Quora');
672
673 return localforage.getItem('4e');
674 }).then(function(value) {
675 expect(value).to.not.be('Mozilla');
676 expect(value).to.be('Quora');
677 done();
678 });
679 });
680
681 it('returns null when saving undefined [callback]', function(done) {
682 localforage.setItem('undef', undefined, function(err, setValue) {
683 expect(setValue).to.be(null);
684
685 done();
686 });
687 });
688 it('returns null when saving undefined [promise]', function(done) {
689 localforage.setItem('undef', undefined).then(function(setValue) {
690 expect(setValue).to.be(null);
691
692 done();
693 });
694 });
695
696 it('returns null when saving null [callback]', function(done) {
697 localforage.setItem('null', null, function(err, setValue) {
698 expect(setValue).to.be(null);
699
700 done();
701 });
702 });
703 it('returns null when saving null [promise]', function(done) {
704 localforage.setItem('null', null).then(function(setValue) {
705 expect(setValue).to.be(null);
706
707 done();
708 });
709 });
710
711 it('returns null for a non-existant key [callback]', function(done) {
712 localforage.getItem('undef', function(err, value) {
713 expect(value).to.be(null);
714
715 done();
716 });
717 });
718 it('returns null for a non-existant key [promise]', function(done) {
719 localforage.getItem('undef').then(function(value) {
720 expect(value).to.be(null);
721
722 done();
723 });
724 });
725
726 // github.com/mozilla/localforage/pull/24#discussion-diff-9389662R158
727 // localStorage's method API (`localStorage.getItem('foo')`) returns
728 // `null` for undefined keys, even though its getter/setter API
729 // (`localStorage.foo`) returns `undefined` for the same key. Gaia's
730 // asyncStorage API, which is based on localStorage and upon which
731 // localforage is based, ALSO returns `null`. BLARG! So for now, we
732 // just return null, because there's no way to know from localStorage
733 // if the key is ACTUALLY `null` or undefined but returning `null`.
734 // And returning `undefined` here would break compatibility with
735 // localStorage fallback. Maybe in the future we won't care...
736 it('returns null from an undefined key [callback]', function(done) {
737 localforage.key(0, function(err, key) {
738 expect(key).to.be(null);
739
740 done();
741 });
742 });
743 it('returns null from an undefined key [promise]', function(done) {
744 localforage.key(0).then(function(key) {
745 expect(key).to.be(null);
746
747 done();
748 });
749 });
750
751 it('returns key name [callback]', function(done) {
752 localforage.setItem('office', 'Initech').then(function() {
753 localforage.key(0, function(err, key) {
754 expect(key).to.be('office');
755
756 done();
757 });
758 });
759 });
760 it('returns key name [promise]', function(done) {
761 localforage.setItem('office', 'Initech').then(function() {
762 return localforage.key(0);
763 }).then(function(key) {
764 expect(key).to.be('office');
765
766 done();
767 });
768 });
769
770 it('removes an item [callback]', function(done) {
771 localforage.setItem('office', 'Initech', function() {
772 localforage.setItem('otherOffice', 'Initrode', function() {
773 localforage.removeItem('office', function() {
774 localforage.getItem('office', function(err, emptyValue) {
775 expect(emptyValue).to.be(null);
776
777 localforage.getItem('otherOffice', function(err, value) {
778 expect(value).to.be('Initrode');
779
780 done();
781 });
782 });
783 });
784 });
785 });
786 });
787 it('removes an item [promise]', function(done) {
788 localforage.setItem('office', 'Initech').then(function() {
789 return localforage.setItem('otherOffice', 'Initrode');
790 }).then(function() {
791 return localforage.removeItem('office');
792 }).then(function() {
793 return localforage.getItem('office');
794 }).then(function(emptyValue) {
795 expect(emptyValue).to.be(null);
796
797 return localforage.getItem('otherOffice');
798 }).then(function(value) {
799 expect(value).to.be('Initrode');
800
801 done();
802 });
803 });
804
805 it('removes all items [callback]', function(done) {
806 localforage.setItem('office', 'Initech', function() {
807 localforage.setItem('otherOffice', 'Initrode', function() {
808 localforage.length(function(err, length) {
809 expect(length).to.be(2);
810
811 localforage.clear(function() {
812 localforage.getItem('office', function(err, value) {
813 expect(value).to.be(null);
814
815 localforage.length(function(err, length) {
816 expect(length).to.be(0);
817
818 done();
819 });
820 });
821 });
822 });
823 });
824 });
825 });
826 it('removes all items [promise]', function(done) {
827 localforage.setItem('office', 'Initech').then(function() {
828 return localforage.setItem('otherOffice', 'Initrode');
829 }).then(function() {
830 return localforage.length();
831 }).then(function(length) {
832 expect(length).to.be(2);
833
834 return localforage.clear();
835 }).then(function() {
836 return localforage.getItem('office');
837 }).then(function(value) {
838 expect(value).to.be(null);
839
840 return localforage.length();
841 }).then(function(length) {
842 expect(length).to.be(0);
843
844 done();
845 });
846 });
847
848 if (driverName === localforage.LOCALSTORAGE) {
849 it('removes only own items upon clear', function(done) {
850 localStorage.setItem('local', 'forage');
851
852 localforage.setItem('office', 'Initech').then(function() {
853 return localforage.clear();
854 }).then(function() {
855 expect(localStorage.getItem('local')).to.be('forage');
856
857 localStorage.clear();
858
859 done();
860 });
861 });
862
863 it('returns only its own keys from keys()', function(done) {
864 localStorage.setItem('local', 'forage');
865
866 localforage.setItem('office', 'Initech').then(function() {
867 return localforage.keys();
868 }).then(function(keys) {
869 expect(keys).to.eql(['office']);
870
871 localStorage.clear();
872
873 done();
874 });
875 });
876
877 it('counts only its own items with length()', function(done) {
878 localStorage.setItem('local', 'forage');
879 localStorage.setItem('another', 'value');
880
881 localforage.setItem('office', 'Initech').then(function() {
882 return localforage.length();
883 }).then(function(length) {
884 expect(length).to.be(1);
885
886 localStorage.clear();
887
888 done();
889 });
890 });
891 }
892
893 it('has a length after saving an item [callback]', function(done) {
894 localforage.length(function(err, length) {
895 expect(length).to.be(0);
896 localforage.setItem('rapper', 'Black Thought', function() {
897 localforage.length(function(err, length) {
898 expect(length).to.be(1);
899
900 done();
901 });
902 });
903 });
904 });
905 it('has a length after saving an item [promise]', function(done) {
906 localforage.length().then(function(length) {
907 expect(length).to.be(0);
908
909 return localforage.setItem('lame rapper', 'Vanilla Ice');
910 }).then(function() {
911 return localforage.length();
912 }).then(function(length) {
913 expect(length).to.be(1);
914
915 done();
916 });
917 });
918
919 // Deal with non-string keys, see issue #250
920 // https://github.com/mozilla/localForage/issues/250
921 it('casts an undefined key to a String', function(done) {
922 localforage.setItem(undefined, 'goodness!').then(function(value) {
923 expect(value).to.be('goodness!');
924
925 return localforage.getItem(undefined);
926 }).then(function(value) {
927 expect(value).to.be('goodness!');
928
929 return localforage.removeItem(undefined);
930 }).then(function() {
931 return localforage.length();
932 }).then(function(length) {
933 expect(length).to.be(0);
934 done();
935 });
936 });
937
938 it('casts a null key to a String', function(done) {
939 localforage.setItem(null, 'goodness!').then(function(value) {
940 expect(value).to.be('goodness!');
941
942 return localforage.getItem(null);
943 }).then(function(value) {
944 expect(value).to.be('goodness!');
945
946 return localforage.removeItem(null);
947 }).then(function() {
948 return localforage.length();
949 }).then(function(length) {
950 expect(length).to.be(0);
951 done();
952 });
953 });
954
955 it('casts a float key to a String', function(done) {
956 localforage.setItem(537.35737, 'goodness!').then(function(value) {
957 expect(value).to.be('goodness!');
958
959 return localforage.getItem(537.35737);
960 }).then(function(value) {
961 expect(value).to.be('goodness!');
962
963 return localforage.removeItem(537.35737);
964 }).then(function() {
965 return localforage.length();
966 }).then(function(length) {
967 expect(length).to.be(0);
968 done();
969 });
970 });
971
972 it('is retrieved by getDriver [callback]', function(done) {
973 localforage.getDriver(driverName, function(driver) {
974 expect(typeof driver).to.be('object');
975 driverApiMethods.concat('_initStorage').forEach(function(methodName) {
976 expect(typeof driver[methodName]).to.be('function');
977 });
978 expect(driver._driver).to.be(driverName);
979 done();
980 });
981 });
982
983 it('is retrieved by getDriver [promise]', function(done) {
984 localforage.getDriver(driverName).then(function(driver) {
985 expect(typeof driver).to.be('object');
986 driverApiMethods.concat('_initStorage').forEach(function(methodName) {
987 expect(typeof driver[methodName]).to.be('function');
988 });
989 expect(driver._driver).to.be(driverName);
990 done();
991 });
992 });
993
994 if (driverName === localforage.WEBSQL ||
995 driverName === localforage.LOCALSTORAGE) {
996 it('exposes the serializer on the dbInfo object', function(done) {
997 localforage.ready().then(function() {
998 expect(localforage._dbInfo.serializer).to.be.an('object');
999 done();
1000 });
1001 });
1002 }
1003 });
1004
1005 function prepareStorage(storageName) {
1006 // Delete IndexedDB storages (start from scratch)
1007 // Refers to issue #492 - https://github.com/mozilla/localForage/issues/492
1008 if (driverName === localforage.INDEXEDDB) {
1009 return new Promise(function(resolve) {
1010 indexedDB.deleteDatabase(storageName).onsuccess = resolve;
1011 });
1012 }
1013
1014 // Otherwise, do nothing
1015 return Promise.resolve();
1016 }
1017
1018 describe(driverName + ' driver multiple instances', function() {
1019 'use strict';
1020
1021 this.timeout(30000);
1022
1023 var localforage2 = null;
1024 var localforage3 = null;
1025
1026 before(function(done) {
1027
1028 prepareStorage('storage2').then(function() {
1029 localforage2 = localforage.createInstance({
1030 name: 'storage2',
1031 // We need a small value here
1032 // otherwise local PhantomJS test
1033 // will fail with SECURITY_ERR.
1034 // TravisCI seem to work fine though.
1035 size: 1024,
1036 storeName: 'storagename2'
1037 });
1038
1039 // Same name, but different storeName since this has been
1040 // malfunctioning before w/ IndexedDB.
1041 localforage3 = localforage.createInstance({
1042 name: 'storage2',
1043 // We need a small value here
1044 // otherwise local PhantomJS test
1045 // will fail with SECURITY_ERR.
1046 // TravisCI seem to work fine though.
1047 size: 1024,
1048 storeName: 'storagename3'
1049 });
1050
1051 Promise.all([
1052 localforage.setDriver(driverName),
1053 localforage2.setDriver(driverName),
1054 localforage3.setDriver(driverName)
1055 ]).then(function() {
1056 done();
1057 });
1058 });
1059 });
1060
1061 beforeEach(function(done) {
1062 Promise.all([
1063 localforage.clear(),
1064 localforage2.clear(),
1065 localforage3.clear()
1066 ]).then(function() {
1067 done();
1068 });
1069 });
1070
1071 it('is not be able to access values of other instances', function(done) {
1072 Promise.all([
1073 localforage.setItem('key1', 'value1a'),
1074 localforage2.setItem('key2', 'value2a'),
1075 localforage3.setItem('key3', 'value3a')
1076 ]).then(function() {
1077 return Promise.all([
1078 localforage.getItem('key2').then(function(value) {
1079 expect(value).to.be(null);
1080 }),
1081 localforage2.getItem('key1').then(function(value) {
1082 expect(value).to.be(null);
1083 }),
1084 localforage2.getItem('key3').then(function(value) {
1085 expect(value).to.be(null);
1086 }),
1087 localforage3.getItem('key2').then(function(value) {
1088 expect(value).to.be(null);
1089 })
1090 ]);
1091 }).then(function() {
1092 done();
1093 }, function(errors) {
1094 done(new Error(errors));
1095 });
1096 });
1097
1098 it('retrieves the proper value when using the same key with other instances', function(done) {
1099 Promise.all([
1100 localforage.setItem('key', 'value1'),
1101 localforage2.setItem('key', 'value2'),
1102 localforage3.setItem('key', 'value3')
1103 ]).then(function() {
1104 return Promise.all([
1105 localforage.getItem('key').then(function(value) {
1106 expect(value).to.be('value1');
1107 }),
1108 localforage2.getItem('key').then(function(value) {
1109 expect(value).to.be('value2');
1110 }),
1111 localforage3.getItem('key').then(function(value) {
1112 expect(value).to.be('value3');
1113 })
1114 ]);
1115 }).then(function() {
1116 done();
1117 }, function(errors) {
1118 done(new Error(errors));
1119 });
1120 });
1121 });
1122
1123 // Refers to issue #492 - https://github.com/mozilla/localForage/issues/492
1124 describe(driverName + ' driver multiple instances (concurrent on same database)', function() {
1125
1126 'use strict';
1127
1128 this.timeout(30000);
1129
1130 before(function() {
1131 return Promise.all([
1132 prepareStorage('storage3'),
1133 prepareStorage('commonStorage'),
1134 prepareStorage('commonStorage2'),
1135 prepareStorage('commonStorage3')
1136 ]);
1137 });
1138
1139 it('chains operation on multiple stores', function() {
1140 var localforage1 = localforage.createInstance({
1141 name: 'storage3',
1142 storeName: 'store1',
1143 size: 1024
1144 });
1145
1146 var localforage2 = localforage.createInstance({
1147 name: 'storage3',
1148 storeName: 'store2',
1149 size: 1024
1150 });
1151
1152 var localforage3 = localforage.createInstance({
1153 name: 'storage3',
1154 storeName: 'store3',
1155 size: 1024
1156 });
1157
1158 var promise1 = localforage1.setItem('key', 'value1').then(function() {
1159 return localforage1.getItem('key');
1160 }).then(function(value) {
1161 expect(value).to.be('value1');
1162 });
1163
1164 var promise2 = localforage2.setItem('key', 'value2').then(function() {
1165 return localforage2.getItem('key');
1166 }).then(function(value) {
1167 expect(value).to.be('value2');
1168 });
1169
1170 var promise3 = localforage3.setItem('key', 'value3').then(function() {
1171 return localforage3.getItem('key');
1172 }).then(function(value) {
1173 expect(value).to.be('value3');
1174 });
1175
1176 return Promise.all([
1177 promise1,
1178 promise2,
1179 promise3
1180 ]);
1181 });
1182
1183 it('can create multiple instances of the same store', function() {
1184 var localforage1;
1185 var localforage2;
1186 var localforage3;
1187
1188 Promise.resolve()
1189 .then(function() {
1190 localforage1 = localforage.createInstance({
1191 name: 'commonStorage',
1192 storeName: 'commonStore',
1193 size: 1024
1194 });
1195 return localforage1.ready();
1196 })
1197 .then(function() {
1198 localforage2 = localforage.createInstance({
1199 name: 'commonStorage',
1200 storeName: 'commonStore',
1201 size: 1024
1202 });
1203 return localforage2.ready();
1204 })
1205 .then(function() {
1206 localforage3 = localforage.createInstance({
1207 name: 'commonStorage',
1208 storeName: 'commonStore',
1209 size: 1024
1210 });
1211 return localforage3.ready();
1212 }).then(function() {
1213 return Promise.resolve()
1214 .then(function() {
1215 return localforage1.setItem('key1', 'value1').then(function() {
1216 return localforage1.getItem('key1');
1217 }).then(function(value) {
1218 expect(value).to.be('value1');
1219 });
1220 })
1221 .then(function() {
1222 return localforage2.setItem('key2', 'value2').then(function() {
1223 return localforage2.getItem('key2');
1224 }).then(function(value) {
1225 expect(value).to.be('value2');
1226 });
1227 })
1228 .then(function() {
1229 return localforage3.setItem('key3', 'value3').then(function() {
1230 return localforage3.getItem('key3');
1231 }).then(function(value) {
1232 expect(value).to.be('value3');
1233 });
1234 });
1235 });
1236 });
1237
1238 it('can create multiple instances of the same store and do concurrent operations', function() {
1239 var localforage1;
1240 var localforage2;
1241 var localforage3;
1242 var localforage3b;
1243
1244 Promise.resolve()
1245 .then(function() {
1246 localforage1 = localforage.createInstance({
1247 name: 'commonStorage2',
1248 storeName: 'commonStore',
1249 size: 1024
1250 });
1251 return localforage1.ready();
1252 })
1253 .then(function() {
1254 localforage2 = localforage.createInstance({
1255 name: 'commonStorage2',
1256 storeName: 'commonStore',
1257 size: 1024
1258 });
1259 return localforage2.ready();
1260 })
1261 .then(function() {
1262 localforage3 = localforage.createInstance({
1263 name: 'commonStorage2',
1264 storeName: 'commonStore',
1265 size: 1024
1266 });
1267 return localforage3.ready();
1268 })
1269 .then(function() {
1270 localforage3b = localforage.createInstance({
1271 name: 'commonStorage2',
1272 storeName: 'commonStore',
1273 size: 1024
1274 });
1275 return localforage3b.ready();
1276 }).then(function() {
1277 var promise1 = localforage1.setItem('key1', 'value1').then(function() {
1278 return localforage1.getItem('key1');
1279 }).then(function(value) {
1280 expect(value).to.be('value1');
1281 });
1282
1283 var promise2 = localforage2.setItem('key2', 'value2').then(function() {
1284 return localforage2.getItem('key2');
1285 }).then(function(value) {
1286 expect(value).to.be('value2');
1287 });
1288
1289 var promise3 = localforage3.setItem('key3', 'value3').then(function() {
1290 return localforage3.getItem('key3');
1291 }).then(function(value) {
1292 expect(value).to.be('value3');
1293 });
1294
1295 var promise4 = localforage3b.setItem('key3', 'value3').then(function() {
1296 return localforage3.getItem('key3');
1297 }).then(function(value) {
1298 expect(value).to.be('value3');
1299 });
1300
1301 return Promise.all([
1302 promise1,
1303 promise2,
1304 promise3,
1305 promise4
1306 ]);
1307 });
1308 });
1309
1310 it('can create multiple instances of the same store concurrently', function() {
1311 var localforage1 = localforage.createInstance({
1312 name: 'commonStorage3',
1313 storeName: 'commonStore',
1314 size: 1024
1315 });
1316
1317 var localforage2 = localforage.createInstance({
1318 name: 'commonStorage3',
1319 storeName: 'commonStore',
1320 size: 1024
1321 });
1322
1323 var localforage3 = localforage.createInstance({
1324 name: 'commonStorage3',
1325 storeName: 'commonStore',
1326 size: 1024
1327 });
1328
1329 var localforage3b = localforage.createInstance({
1330 name: 'commonStorage3',
1331 storeName: 'commonStore',
1332 size: 1024
1333 });
1334
1335 var promise1 = localforage1.setItem('key1', 'value1').then(function() {
1336 return localforage1.getItem('key1');
1337 }).then(function(value) {
1338 expect(value).to.be('value1');
1339 });
1340
1341 var promise2 = localforage2.setItem('key2', 'value2').then(function() {
1342 return localforage2.getItem('key2');
1343 }).then(function(value) {
1344 expect(value).to.be('value2');
1345 });
1346
1347 var promise3 = localforage3.setItem('key3', 'value3').then(function() {
1348 return localforage3.getItem('key3');
1349 }).then(function(value) {
1350 expect(value).to.be('value3');
1351 });
1352
1353 var promise4 = localforage3b.setItem('key3', 'value3').then(function() {
1354 return localforage3.getItem('key3');
1355 }).then(function(value) {
1356 expect(value).to.be('value3');
1357 });
1358
1359 return Promise.all([
1360 promise1,
1361 promise2,
1362 promise3,
1363 promise4
1364 ]);
1365 });
1366 });
1367
1368 describe(driverName + ' driver', function() {
1369 'use strict';
1370
1371 var driverPreferedOrder;
1372
1373 before(function() {
1374 // add some unsupported drivers before
1375 // and after the target driver
1376 driverPreferedOrder = ['I am a not supported driver'];
1377
1378 if (!localforage.supports(localforage.WEBSQL)) {
1379 driverPreferedOrder.push(localforage.WEBSQL);
1380 }
1381 if (!localforage.supports(localforage.INDEXEDDB)) {
1382 driverPreferedOrder.push(localforage.INDEXEDDB);
1383 }
1384 if (!localforage.supports(localforage.LOCALSTORAGE)) {
1385 driverPreferedOrder.push(localforage.localStorage);
1386 }
1387
1388 driverPreferedOrder.push(driverName);
1389
1390 driverPreferedOrder.push('I am another not supported driver');
1391 });
1392
1393 it('is used according to setDriver preference order', function(done) {
1394 localforage.setDriver(driverPreferedOrder).then(function() {
1395 expect(localforage.driver()).to.be(driverName);
1396 done();
1397 });
1398 });
1399 });
1400
1401 describe(driverName + ' driver when the callback throws an Error', function() {
1402 'use strict';
1403
1404 var testObj = {
1405 throwFunc: function() {
1406 testObj.throwFuncCalls++;
1407 throw new Error('Thrown test error');
1408 },
1409 throwFuncCalls: 0
1410 };
1411
1412 beforeEach(function(done) {
1413 testObj.throwFuncCalls = 0;
1414 done();
1415 });
1416
1417 it('resolves the promise of getItem()', function(done) {
1418 localforage.getItem('key', testObj.throwFunc).then(function() {
1419 expect(testObj.throwFuncCalls).to.be(1);
1420 done();
1421 });
1422 });
1423
1424 it('resolves the promise of setItem()', function(done) {
1425 localforage.setItem('key', 'test', testObj.throwFunc).then(function() {
1426 expect(testObj.throwFuncCalls).to.be(1);
1427 done();
1428 });
1429 });
1430
1431 it('resolves the promise of clear()', function(done) {
1432 localforage.clear(testObj.throwFunc).then(function() {
1433 expect(testObj.throwFuncCalls).to.be(1);
1434 done();
1435 });
1436 });
1437
1438 it('resolves the promise of length()', function(done) {
1439 localforage.length(testObj.throwFunc).then(function() {
1440 expect(testObj.throwFuncCalls).to.be(1);
1441 done();
1442 });
1443 });
1444
1445 it('resolves the promise of removeItem()', function(done) {
1446 localforage.removeItem('key', testObj.throwFunc).then(function() {
1447 expect(testObj.throwFuncCalls).to.be(1);
1448 done();
1449 });
1450 });
1451
1452 it('resolves the promise of key()', function(done) {
1453 localforage.key('key', testObj.throwFunc).then(function() {
1454 expect(testObj.throwFuncCalls).to.be(1);
1455 done();
1456 });
1457 });
1458
1459 it('resolves the promise of keys()', function(done) {
1460 localforage.keys(testObj.throwFunc).then(function() {
1461 expect(testObj.throwFuncCalls).to.be(1);
1462 done();
1463 });
1464 });
1465 });
1466
1467 describe(driverName + ' driver when ready() gets rejected', function() {
1468 'use strict';
1469
1470 this.timeout(30000);
1471
1472 var _oldReady;
1473
1474 beforeEach(function(done) {
1475 _oldReady = localforage.ready;
1476 localforage.ready = function() {
1477 return Promise.reject();
1478 };
1479 done();
1480 });
1481
1482 afterEach(function(done) {
1483 localforage.ready = _oldReady;
1484 _oldReady = null;
1485 done();
1486 });
1487
1488 driverApiMethods.forEach(function(methodName) {
1489 it('rejects ' + methodName + '() promise', function(done) {
1490 localforage[methodName]().then(null, function(/*err*/) {
1491 done();
1492 });
1493 });
1494 });
1495 });
1496});
1497
1498DRIVERS.forEach(function(driverName) {
1499 describe(driverName + ' driver instance', function() {
1500 it('creates a new instance and sets the driver', function(done) {
1501 var localforage2 = localforage.createInstance({
1502 name: 'storage2',
1503 driver: driverName,
1504 // We need a small value here
1505 // otherwise local PhantomJS test
1506 // will fail with SECURITY_ERR.
1507 // TravisCI seem to work fine though.
1508 size: 1024,
1509 storeName: 'storagename2'
1510 });
1511
1512 // since config actually uses setDriver which is async,
1513 // and since driver() and supports() are not defered (are sync),
1514 // we have to wait till an async method returns
1515 localforage2.length().then(function() {
1516 expect(localforage2.driver()).to.be(driverName);
1517 done();
1518 }, function() {
1519 expect(localforage2.driver()).to.be(null);
1520 done();
1521 });
1522 });
1523 });
1524});
1525
1526SUPPORTED_DRIVERS.forEach(function(driverName) {
1527 describe(driverName + ' driver dropInstance', function() {
1528
1529 this.timeout(30000);
1530
1531 var nodropInstance;
1532 var nodropInstanceOptions = {
1533 name: 'dropStoreDb',
1534 driver: driverName,
1535 size: 1024,
1536 storeName: 'nodropStore'
1537 };
1538
1539 var dropStoreInstance1;
1540 var dropStoreInstance1Options = {
1541 name: 'dropStoreDb',
1542 driver: driverName,
1543 size: 1024,
1544 storeName: 'dropStore'
1545 };
1546
1547 var dropStoreInstance2;
1548 var dropStoreInstance2Options = {
1549 name: 'dropStoreDb',
1550 driver: driverName,
1551 size: 1024,
1552 storeName: 'dropStore2'
1553 };
1554
1555 var dropStoreInstance3;
1556 var dropStoreInstance3Options = {
1557 name: 'dropStoreDb',
1558 driver: driverName,
1559 size: 1024,
1560 storeName: 'dropStore3'
1561 };
1562
1563 var dropDbInstance;
1564 var dropDbInstanceOptions = {
1565 name: 'dropDb',
1566 driver: driverName,
1567 size: 1024,
1568 storeName: 'dropStore'
1569 };
1570
1571 var dropDb2Instance;
1572 var dropDb2InstanceOptions = {
1573 name: 'dropDb2',
1574 driver: driverName,
1575 size: 1024,
1576 storeName: 'dropStore'
1577 };
1578
1579 before(function() {
1580 nodropInstance = localforage.createInstance(nodropInstanceOptions);
1581 dropStoreInstance1 = localforage.createInstance(dropStoreInstance1Options);
1582 dropStoreInstance2 = localforage.createInstance(dropStoreInstance2Options);
1583 dropStoreInstance3 = localforage.createInstance(dropStoreInstance2Options);
1584 dropDbInstance = localforage.createInstance(dropDbInstanceOptions);
1585 dropDb2Instance = localforage.createInstance(dropDb2InstanceOptions);
1586 return Promise.resolve().then(function() {
1587 return nodropInstance.setItem('key1', 'value0');
1588 }).then(function() {
1589 return dropStoreInstance1.setItem('key1', 'value1');
1590 }).then(function() {
1591 return dropStoreInstance2.setItem('key1', 'value2');
1592 }).then(function() {
1593 return dropStoreInstance3.setItem('key1', 'value3');
1594 }).then(function() {
1595 return dropDbInstance.setItem('key1', 'value3');
1596 }).then(function() {
1597 return dropDb2Instance.setItem('key1', 'value3');
1598 });
1599 });
1600
1601 function expectStoreToNotExistAsync(options) {
1602 return new Promise(function(resolve, reject) {
1603 if (driverName === localforage.INDEXEDDB) {
1604 var req = indexedDB.open(options.name);
1605 req.onsuccess = function() {
1606 var db = req.result;
1607 if (!db) {
1608 reject();
1609 return;
1610 }
1611 expect(db.objectStoreNames.contains(options.storeName)).to.be(false);
1612 db.close();
1613 resolve();
1614 };
1615 req.onerror = req.onblocked = reject;
1616 } else if (driverName === localforage.WEBSQL) {
1617 var db = openDatabase(options.name, '', '', 0);
1618 db.transaction(function(t) {
1619 t.executeSql(
1620 "SELECT name FROM sqlite_master WHERE type='table' AND name = ?",
1621 [options.storeName],
1622 function(t, results) {
1623 expect(results.rows.length).to.be(0);
1624 resolve();
1625 },
1626 reject
1627 );
1628 }, reject);
1629 } else if (driverName === localforage.LOCALSTORAGE) {
1630 var keyPrefix = (function _getKeyPrefix(options, defaultConfig) {
1631 var keyPrefix = options.name + '/';
1632
1633 if (options.storeName !== defaultConfig.storeName) {
1634 keyPrefix += options.storeName + '/';
1635 }
1636 return keyPrefix;
1637 })(options, {
1638 name: 'localforage',
1639 storeName: 'keyvaluepairs'
1640 });
1641
1642 var foundLocalStorageKey = false;
1643 for (var i = 0, length = localStorage.length; i < length; i++) {
1644 if (localStorage.key(i).indexOf(keyPrefix) === 0) {
1645 foundLocalStorageKey = true;
1646 break;
1647 }
1648 }
1649 expect(foundLocalStorageKey).to.be(false);
1650 resolve();
1651 } else {
1652 throw new Error('Not Implemented Exception');
1653 }
1654 });
1655 }
1656
1657 it('drops the current instance without affecting the rest', function() {
1658 return dropStoreInstance1.dropInstance().then(function() {
1659 return nodropInstance.getItem('key1');
1660 }).then(function(value) {
1661 expect(value).to.be('value0');
1662 });
1663 });
1664
1665 it('can recreate and set values to previously dropped instances', function() {
1666 return dropStoreInstance1.dropInstance().then(function() {
1667 return dropStoreInstance1.getItem('key1');
1668 }).then(function(value) {
1669 expect(value).to.be(null);
1670 return dropStoreInstance1.length();
1671 }).then(function(length) {
1672 expect(length).to.be(0);
1673 }).then(function() {
1674 return dropStoreInstance1.setItem('key1', 'newvalue2');
1675 }).then(function() {
1676 return dropStoreInstance1.getItem('key1');
1677 }).then(function(value) {
1678 expect(value).to.be('newvalue2');
1679 });
1680 });
1681
1682 it('drops an other instance without affecting the rest', function() {
1683 var opts = {
1684 name: dropStoreInstance2Options.name,
1685 storeName: dropStoreInstance2Options.storeName
1686 };
1687 return nodropInstance.dropInstance(opts).then(function() {
1688 return nodropInstance.getItem('key1');
1689 }).then(function(value) {
1690 expect(value).to.be('value0');
1691 });
1692 });
1693
1694 it('the dropped instance is completely removed', function() {
1695 var opts = {
1696 name: dropStoreInstance3Options.name,
1697 storeName: dropStoreInstance3Options.storeName
1698 };
1699 return dropStoreInstance3.dropInstance().then(function() {
1700 return expectStoreToNotExistAsync(opts);
1701 });
1702 });
1703
1704 function expectDBToNotExistAsync(options) {
1705 return new Promise(function(resolve, reject) {
1706 if (driverName === localforage.INDEXEDDB) {
1707 var req = indexedDB.open(options.name);
1708 req.onsuccess = function() {
1709 var db = req.result;
1710 if (!db) {
1711 reject();
1712 return;
1713 }
1714 expect(db.objectStoreNames.length).to.be(0);
1715 db.close();
1716 resolve();
1717 };
1718 req.onerror = req.onblocked = reject;
1719 } else if (driverName === localforage.WEBSQL) {
1720 var db = openDatabase(options.name, '', '', 0);
1721 db.transaction(function(t) {
1722 t.executeSql(
1723 "SELECT name FROM sqlite_master WHERE type='table'",
1724 [],
1725 function(t, results) {
1726 var stores = Array.prototype.filter.call(results.rows, function(obj) {
1727 return obj && obj.name && obj.name.indexOf('__') !== 0;
1728 });
1729 expect(stores.length).to.be(0);
1730 resolve();
1731 },
1732 reject
1733 );
1734 }, reject);
1735 } else if (driverName === localforage.LOCALSTORAGE) {
1736 var keyPrefix = (function _getKeyPrefix(options) {
1737 return options.name + '/';
1738 })(options);
1739
1740 var foundLocalStorageKey = false;
1741 for (var i = 0, length = localStorage.length; i < length; i++) {
1742 if (localStorage.key(i).indexOf(keyPrefix) === 0) {
1743 foundLocalStorageKey = true;
1744 break;
1745 }
1746 }
1747 expect(foundLocalStorageKey).to.be(false);
1748 resolve();
1749 } else {
1750 throw new Error('Not Implemented Exception');
1751 }
1752 });
1753 }
1754
1755 it('the dropped "DB" can be recreated', function() {
1756 var opts = {
1757 name: dropDbInstanceOptions.name
1758 };
1759 return dropDbInstance.dropInstance(opts).then(function() {
1760 return dropDbInstance.getItem('key1');
1761 }).then(function(value) {
1762 expect(value).to.be(null);
1763 });
1764 });
1765
1766 it('the dropped "DB" is completely removed', function() {
1767 var opts = {
1768 name: dropDb2InstanceOptions.name
1769 };
1770 return dropDb2Instance.dropInstance(opts).then(function() {
1771 return expectDBToNotExistAsync(opts);
1772 });
1773 });
1774 });
1775});