feat: Add Be and tbd skill, also added Roadmap file

This commit is contained in:
2026-05-10 16:32:12 -04:00
parent 3500ade13f
commit 0bb8885802
29587 changed files with 10611695 additions and 0 deletions

View File

@@ -0,0 +1,426 @@
(function() {
'use strict';
var dummyStorage = {};
// Config the localStorage backend, using options set in the config.
function _initStorage(options) {
var self = this;
var dbInfo = {};
if (options) {
for (var i in options) {
dbInfo[i] = options[i];
}
}
dummyStorage[dbInfo.name] = dbInfo.db = {};
self._dbInfo = dbInfo;
return Promise.resolve();
}
var SERIALIZED_MARKER = '__lfsc__:';
var SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER.length;
// OMG the serializations!
var TYPE_ARRAYBUFFER = 'arbf';
var TYPE_BLOB = 'blob';
var TYPE_INT8ARRAY = 'si08';
var TYPE_UINT8ARRAY = 'ui08';
var TYPE_UINT8CLAMPEDARRAY = 'uic8';
var TYPE_INT16ARRAY = 'si16';
var TYPE_INT32ARRAY = 'si32';
var TYPE_UINT16ARRAY = 'ur16';
var TYPE_UINT32ARRAY = 'ui32';
var TYPE_FLOAT32ARRAY = 'fl32';
var TYPE_FLOAT64ARRAY = 'fl64';
var TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH +
TYPE_ARRAYBUFFER.length;
function clear(callback) {
var self = this;
var promise = new Promise(function(resolve, reject) {
self.ready().then(function() {
var db = self._dbInfo.db;
for (var key in db) {
if (db.hasOwnProperty(key)) {
delete db[key];
// db[key] = undefined;
}
}
resolve();
}).catch(reject);
});
executeCallback(promise, callback);
return promise;
}
function getItem(key, callback) {
var self = this;
// Cast the key to a string, as that's all we can set as a key.
if (typeof key !== 'string') {
window.console.warn(key +
' used as a key, but it is not a string.');
key = String(key);
}
var promise = new Promise(function(resolve, reject) {
self.ready().then(function() {
try {
var db = self._dbInfo.db;
var result = db[key];
if (result) {
result = _deserialize(result);
}
resolve(result);
} catch (e) {
reject(e);
}
}).catch(reject);
});
executeCallback(promise, callback);
return promise;
}
function iterate(callback) {
var self = this;
var promise = new Promise(function(resolve, reject) {
self.ready().then(function() {
try {
var db = self._dbInfo.db;
for (var key in db) {
var result = db[key];
if (result) {
result = _deserialize(result);
}
callback(result, key);
}
resolve();
} catch (e) {
reject(e);
}
}).catch(reject);
});
executeCallback(promise, callback);
return promise;
}
function key(n, callback) {
var self = this;
var promise = new Promise(function(resolve, reject) {
self.ready().then(function() {
var db = self._dbInfo.db;
var result = null;
var index = 0;
for (var key in db) {
if (db.hasOwnProperty(key) && db[key] !== undefined) {
if (n === index) {
result = key;
break;
}
index++;
}
}
resolve(result);
}).catch(reject);
});
executeCallback(promise, callback);
return promise;
}
function keys(callback) {
var self = this;
var promise = new Promise(function(resolve, reject) {
self.ready().then(function() {
var db = self._dbInfo.db;
var keys = [];
for (var key in db) {
if (db.hasOwnProperty(key)) {
keys.push(key);
}
}
resolve(keys);
}).catch(reject);
});
executeCallback(promise, callback);
return promise;
}
function length(callback) {
var self = this;
var promise = new Promise(function(resolve, reject) {
self.keys().then(function(keys) {
resolve(keys.length);
}).catch(reject);
});
executeCallback(promise, callback);
return promise;
}
function removeItem(key, callback) {
var self = this;
// Cast the key to a string, as that's all we can set as a key.
if (typeof key !== 'string') {
window.console.warn(key +
' used as a key, but it is not a string.');
key = String(key);
}
var promise = new Promise(function(resolve, reject) {
self.ready().then(function() {
var db = self._dbInfo.db;
if (db.hasOwnProperty(key)) {
delete db[key];
// db[key] = undefined;
}
resolve();
}).catch(reject);
});
executeCallback(promise, callback);
return promise;
}
function setItem(key, value, callback) {
var self = this;
// Cast the key to a string, as that's all we can set as a key.
if (typeof key !== 'string') {
window.console.warn(key +
' used as a key, but it is not a string.');
key = String(key);
}
var promise = new Promise(function(resolve, reject) {
self.ready().then(function() {
// Convert undefined values to null.
// https://github.com/mozilla/localForage/pull/42
if (value === undefined) {
value = null;
}
// Save the original value to pass to the callback.
var originalValue = value;
_serialize(value, function(value, error) {
if (error) {
reject(error);
} else {
try {
var db = self._dbInfo.db;
db[key] = value;
resolve(originalValue);
} catch (e) {
reject(e);
}
}
});
}).catch(reject);
});
executeCallback(promise, callback);
return promise;
}
// _serialize just like in LocalStorage
function _serialize(value, callback) {
var valueString = '';
if (value) {
valueString = value.toString();
}
// Cannot use `value instanceof ArrayBuffer` or such here, as these
// checks fail when running the tests using casper.js...
//
// TODO: See why those tests fail and use a better solution.
if (value && (value.toString() === '[object ArrayBuffer]' ||
value.buffer &&
value.buffer.toString() === '[object ArrayBuffer]')) {
// Convert binary arrays to a string and prefix the string with
// a special marker.
var buffer;
var marker = SERIALIZED_MARKER;
if (value instanceof ArrayBuffer) {
buffer = value;
marker += TYPE_ARRAYBUFFER;
} else {
buffer = value.buffer;
if (valueString === '[object Int8Array]') {
marker += TYPE_INT8ARRAY;
} else if (valueString === '[object Uint8Array]') {
marker += TYPE_UINT8ARRAY;
} else if (valueString === '[object Uint8ClampedArray]') {
marker += TYPE_UINT8CLAMPEDARRAY;
} else if (valueString === '[object Int16Array]') {
marker += TYPE_INT16ARRAY;
} else if (valueString === '[object Uint16Array]') {
marker += TYPE_UINT16ARRAY;
} else if (valueString === '[object Int32Array]') {
marker += TYPE_INT32ARRAY;
} else if (valueString === '[object Uint32Array]') {
marker += TYPE_UINT32ARRAY;
} else if (valueString === '[object Float32Array]') {
marker += TYPE_FLOAT32ARRAY;
} else if (valueString === '[object Float64Array]') {
marker += TYPE_FLOAT64ARRAY;
} else {
callback(new Error('Failed to get type for BinaryArray'));
}
}
callback(marker + _bufferToString(buffer));
} else if (valueString === '[object Blob]') {
// Conver the blob to a binaryArray and then to a string.
var fileReader = new FileReader();
fileReader.onload = function() {
var str = _bufferToString(this.result);
callback(SERIALIZED_MARKER + TYPE_BLOB + str);
};
fileReader.readAsArrayBuffer(value);
} else {
try {
callback(JSON.stringify(value));
} catch (e) {
window.console.error("Couldn't convert value into a JSON " +
'string: ', value);
callback(e);
}
}
}
// _deserialize just like in LocalStorage
function _deserialize(value) {
// If we haven't marked this string as being specially serialized (i.e.
// something other than serialized JSON), we can just return it and be
// done with it.
if (value.substring(0,
SERIALIZED_MARKER_LENGTH) !== SERIALIZED_MARKER) {
return JSON.parse(value);
}
// The following code deals with deserializing some kind of Blob or
// TypedArray. First we separate out the type of data we're dealing
// with from the data itself.
var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH);
var type = value.substring(SERIALIZED_MARKER_LENGTH,
TYPE_SERIALIZED_MARKER_LENGTH);
// Fill the string into a ArrayBuffer.
// 2 bytes for each char.
var buffer = new ArrayBuffer(serializedString.length * 2);
var bufferView = new Uint16Array(buffer);
for (var i = serializedString.length - 1; i >= 0; i--) {
bufferView[i] = serializedString.charCodeAt(i);
}
// Return the right type based on the code/type set during
// serialization.
switch (type) {
case TYPE_ARRAYBUFFER:
return buffer;
case TYPE_BLOB:
return new Blob([buffer]);
case TYPE_INT8ARRAY:
return new Int8Array(buffer);
case TYPE_UINT8ARRAY:
return new Uint8Array(buffer);
case TYPE_UINT8CLAMPEDARRAY:
return new Uint8ClampedArray(buffer);
case TYPE_INT16ARRAY:
return new Int16Array(buffer);
case TYPE_UINT16ARRAY:
return new Uint16Array(buffer);
case TYPE_INT32ARRAY:
return new Int32Array(buffer);
case TYPE_UINT32ARRAY:
return new Uint32Array(buffer);
case TYPE_FLOAT32ARRAY:
return new Float32Array(buffer);
case TYPE_FLOAT64ARRAY:
return new Float64Array(buffer);
default:
throw new Error('Unkown type: ' + type);
}
}
// _bufferToString just like in LocalStorage
function _bufferToString(buffer) {
var str = '';
var uint16Array = new Uint16Array(buffer);
try {
str = String.fromCharCode.apply(null, uint16Array);
} catch (e) {
// This is a fallback implementation in case the first one does
// not work. This is required to get the phantomjs passing...
for (var i = 0; i < uint16Array.length; i++) {
str += String.fromCharCode(uint16Array[i]);
}
}
return str;
}
function executeCallback(promise, callback) {
if (callback) {
promise.then(function(result) {
callback(null, result);
}, function(error) {
callback(error);
});
}
}
var dummyStorageDriver = {
_driver: 'dummyStorageDriver',
_initStorage: _initStorage,
// _supports: function() { return true; }
iterate: iterate,
getItem: getItem,
setItem: setItem,
removeItem: removeItem,
clear: clear,
length: length,
key: key,
keys: keys
};
if (typeof define === 'function' && define.amd) {
define('dummyStorageDriver', function() {
return dummyStorageDriver;
});
} else if (typeof module !== 'undefined' && module.exports && typeof require !== 'undefined') {
module.exports = dummyStorageDriver;
} else {
this.dummyStorageDriver = dummyStorageDriver;
}
}).call(window);

BIN
Skills/@be/be/node_modules/localforage/test/photo.jpg generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

BIN
Skills/@be/be/node_modules/localforage/test/photo2.jpg generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@@ -0,0 +1,5 @@
// if (typeof Promise === 'undefined') {
// require('../bower_components/es6-promise/promise');
// }
// require localforage as defined in package.json
window.localforage = require('../');

76
Skills/@be/be/node_modules/localforage/test/runner.js generated vendored Normal file
View File

@@ -0,0 +1,76 @@
/* global requirejs:true */
// Run before window.onload to make sure the specs have access to describe()
// and other mocha methods. All feels very hacky though :-/
this.mocha.setup('bdd');
function runTests() {
var runner = this.mocha.run();
var failedTests = [];
runner.on('end', function() {
window.mochaResults = runner.stats;
window.mochaResults.reports = failedTests;
});
function flattenTitles(test) {
var titles = [];
while (test.parent.title) {
titles.push(test.parent.title);
test = test.parent;
}
return titles.reverse();
}
function logFailure(test, err) {
failedTests.push({
name: test.title,
result: false,
message: err.message,
stack: err.stack,
titles: flattenTitles(test)
});
}
runner.on('fail', logFailure);
}
if (!Array.prototype.forEach) {
Array.prototype.forEach = function(callback, thisArg) {
if (typeof(callback) !== 'function') {
throw new TypeError(callback + ' is not a function!');
}
var len = this.length;
for (var i = 0; i < len; i++) {
callback.call(thisArg, this[i], i, this);
}
};
}
var require = this.require;
if (require) {
requirejs.config({
paths: {
localforage: '/dist/localforage'
}
});
require(['localforage'], function(localforage) {
window.localforage = localforage;
require([
'/test/test.api.js',
'/test/test.config.js',
'/test/test.datatypes.js',
'/test/test.drivers.js',
'/test/test.iframes.js',
'/test/test.webworkers.js'
], runTests);
});
} else if (this.addEventListener) {
this.addEventListener('load', runTests);
} else if (this.attachEvent) {
this.attachEvent('onload', runTests);
}

View File

@@ -0,0 +1,6 @@
// if (typeof Promise === 'undefined') {
// require('../bower_components/es6-promise/promise');
// }
// require localforage as defined in package.json
window.localforage = require('../');
// require('script!../'); // optionally use webpack/script-loader

View File

@@ -0,0 +1,60 @@
/*jshint node:true */
var SAUCELAB_BROWSERS = [
{
base: 'SauceLabs',
browserName: 'chrome',
platform: 'Windows 7',
version: '34',
},
{
base: 'SauceLabs',
browserName: 'firefox',
platform: 'Windows 7',
version: '28',
},
{
base: 'SauceLabs',
browserName: 'firefox',
platform: 'Windows 7',
version: '29',
},
// {
// base: 'SauceLabs',
// browserName: 'internet explorer',
// version: '8',
// platform: 'Windows XP'
// },
{
base: 'SauceLabs',
browserName: 'internet explorer',
version: '9',
},
{
base: 'SauceLabs',
browserName: 'internet explorer',
version: '10',
},
{
base: 'SauceLabs',
browserName: 'internet explorer',
version: '11',
},
{
base: 'SauceLabs',
browserName: 'internet explorer',
version: '10',
platform: 'Windows 8'
},
{
base: 'SauceLabs',
browserName: 'internet explorer',
version: '11',
platform: 'Windows 8.1'
},
];
module.exports = SAUCELAB_BROWSERS;

View File

@@ -0,0 +1,40 @@
/*globals importScripts:true, self:true */
importScripts("/dist/localforage.js");
self.onmessage = function(messageEvent) {
return localforage
.setDriver(messageEvent.data.driver)
.then(function() {
return localforage.setItem('service worker', messageEvent.data.value);
})
.then(function() {
return localforage.getItem('service worker');
})
.then(function(value) {
messageEvent
.ports[0]
.postMessage({
body: value + ' using ' + localforage.driver()
});
})
.catch(function(error) {
messageEvent
.ports[0]
.postMessage({
error: JSON.stringify(error),
body: error,
fail: true
});
});
};
self.oninstall = function(event) {
event.waitUntil(
localforage
.setItem('service worker registration', 'serviceworker present')
.then(function(value) {
console.log(value);
})
);
};

1530
Skills/@be/be/node_modules/localforage/test/test.api.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,34 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>localForage Browserify Tests!</title>
<link rel="stylesheet" href="/bower_components/mocha/mocha.css">
<script src="/bower_components/assert/assert.js"></script>
<script src="/bower_components/mocha/mocha.js"></script>
<script src="/bower_components/expect/index.js"></script>
<!-- Modernizr -->
<script src="/bower_components/modernizr/modernizr.js"></script>
<!-- localForage -->
<script src="/test/localforage.browserify.js"></script>
<!-- Test runner -->
<script src="/test/runner.js"></script>
<!-- specs -->
<script src="/test/test.api.js"></script>
<script src="/test/test.config.js"></script>
<script src="/test/test.datatypes.js"></script>
<script src="/test/test.drivers.js"></script>
<script src="/test/test.iframes.js"></script>
<script src="/test/test.webworkers.js"></script>
</head>
<body>
<div id="mocha"></div>
</body>
</html>

View File

@@ -0,0 +1,41 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>localForage callWhenReady Tests!</title>
<link rel="stylesheet" href="/bower_components/mocha/mocha.css">
<script src="/bower_components/assert/assert.js"></script>
<script src="/bower_components/mocha/mocha.js"></script>
<script src="/bower_components/expect/index.js"></script>
<!-- require.js -->
<script src="/bower_components/requirejs/require.js"></script>
<!-- Modernizr -->
<script src="/bower_components/modernizr/modernizr.js"></script>
<!-- Apply "root" level beforeEach hook to run test suite against
callWhenReady API method stubs -->
<script src="/test/test.callwhenready.js"></script>
<!-- Test runner -->
<script>
// Skip irrelevant config tests by mapping them to API tests so that
// they will not be called.
requirejs.config({
map: {
'*': {
'/test/test.config.js': '/test/test.api.js'
}
}
});
</script>
<script src="/test/runner.js"></script>
</head>
<body>
<div id="mocha"></div>
</body>
</html>

View File

@@ -0,0 +1,34 @@
/* global beforeEach:true */
this.mocha.setup('bdd');
beforeEach(function(done) {
var previousDriver = localforage.driver();
function rerequirelocalforage() {
// The API method stubs inserted by callWhenReady must be tested before
// they are replaced by the driver, which happens as soon as it loads.
//
// To ensure that they work when the drivers are loaded asynchronously,
// we run the entire test suite (except for config tests), but undefine
// the localforage module and force it to reload before each test, so that
// it will be initialized again.
//
// This ensures that the synchronous parts of localforage initialization
// and the API calls in the tests occur first in every test, such that the
// callWhenReady API method stubs are called before RequireJS
// asynchronously loads the drivers that replace them.
require.undef('localforage');
require(['localforage'], function(localforage) {
localforage.setDriver(previousDriver);
window.localforage = localforage;
done();
});
}
localforage.ready().then(function() {
previousDriver = localforage.driver();
rerequirelocalforage();
}, function() {
rerequirelocalforage();
});
});

View File

@@ -0,0 +1,251 @@
/* global before:true, beforeEach:true, describe:true, expect:true, it:true */
describe('Config API', function() {
'use strict';
var DRIVERS = [
localforage.INDEXEDDB,
localforage.LOCALSTORAGE,
localforage.WEBSQL
];
var supportedDrivers = [];
before(function() {
this.defaultConfig = localforage.config();
supportedDrivers = [];
for (var i = 0; i <= DRIVERS.length; i++) {
if (localforage.supports(DRIVERS[i])) {
supportedDrivers.push(DRIVERS[i]);
}
}
});
// Reset localForage before each test so we can call `config()` without
// errors.
beforeEach(function() {
localforage._ready = null;
localforage.config(this.defaultConfig);
});
it('returns the default values', function(done) {
expect(localforage.config('description')).to.be('');
expect(localforage.config('name')).to.be('localforage');
expect(localforage.config('size')).to.be(4980736);
expect(localforage.config('storeName')).to.be('keyvaluepairs');
expect(localforage.config('version')).to.be(1.0);
localforage.ready(function() {
expect(localforage.config('driver')).to.be(localforage.driver());
done();
});
});
it('returns error if API call was already made', function(done) {
localforage.length(function() {
var configResult = localforage.config({
description: '123',
driver: 'I a not set driver',
name: 'My Cool App',
storeName: 'myStoreName',
version: 2.0
});
var error = "Error: Can't call config() after localforage " +
'has been used.';
expect(configResult).to.not.be(true);
expect(configResult.toString()).to.be(error);
// Expect the config values to be as they were before.
expect(localforage.config('description')).to.not.be('123');
expect(localforage.config('description')).to.be('');
expect(localforage.config('driver')).to.be(localforage.driver());
expect(localforage.config('driver')).to.not
.be('I a not set driver');
expect(localforage.config('name')).to.be('localforage');
expect(localforage.config('name')).to.not.be('My Cool App');
expect(localforage.config('size')).to.be(4980736);
expect(localforage.config('storeName')).to.be('keyvaluepairs');
expect(localforage.config('version')).to.be(1.0);
done();
});
});
it('sets new values and returns them properly', function(done) {
var secondSupportedDriver = supportedDrivers.length >= 2 ? supportedDrivers[1] : null;
localforage.config({
description: 'The offline datastore for my cool app',
driver: secondSupportedDriver,
name: 'My Cool App',
storeName: 'myStoreName',
version: 2.0
});
expect(localforage.config('description')).to.not.be('');
expect(localforage.config('description')).to
.be('The offline datastore for my cool app');
expect(localforage.config('driver')).to
.be(secondSupportedDriver);
expect(localforage.config('name')).to.be('My Cool App');
expect(localforage.config('size')).to.be(4980736);
expect(localforage.config('storeName')).to.be('myStoreName');
expect(localforage.config('version')).to.be(2.0);
localforage.ready(function() {
if (supportedDrivers.length >= 2) {
expect(localforage.config('driver')).to
.be(secondSupportedDriver);
} else {
expect(localforage.config('driver')).to
.be(supportedDrivers[0]);
}
done();
});
});
if (supportedDrivers.length >= 2) {
it('sets new driver using preference order', function(done) {
var otherSupportedDrivers = supportedDrivers.slice(1);
var configResult = localforage.config({
driver: otherSupportedDrivers
});
expect(configResult).to.be.a(Promise);
localforage.ready(function() {
expect(localforage.config('driver')).to
.be(otherSupportedDrivers[0]);
return configResult;
}).then(function() {
done();
});
});
}
it('it does not set an unsupported driver', function(done) {
var oldDriver = localforage.driver();
var configResult = localforage.config({
driver: 'I am a not supported driver'
});
expect(configResult).to.be.a(Promise);
localforage.ready(function() {
expect(localforage.config('driver')).to
.be(oldDriver);
return configResult;
}).catch(function(error) {
expect(error).to.be.an(Error);
expect(error.message).to
.be('No available storage method found.');
done();
});
});
it('it does not set an unsupported driver using preference order', function(done) {
var oldDriver = localforage.driver();
localforage.config({
driver: [
'I am a not supported driver',
'I am a an other not supported driver'
]
});
localforage.ready(function() {
expect(localforage.config('driver')).to
.be(oldDriver);
done();
});
});
it('converts bad config values across drivers', function() {
localforage.config({
name: 'My Cool App',
// https://github.com/mozilla/localForage/issues/247
storeName: 'my store&name-v1',
version: 2.0
});
expect(localforage.config('name')).to.be('My Cool App');
expect(localforage.config('storeName')).to.be('my_store_name_v1');
expect(localforage.config('version')).to.be(2.0);
});
it('uses the config values in ' + localforage.driver(), function(done) {
localforage.config({
description: 'The offline datastore for my cool app',
driver: localforage.driver(),
name: 'My Cool App',
storeName: 'myStoreName',
version: 2.0
});
localforage.setItem('some key', 'some value').then(function(value) {
if (localforage.driver() === localforage.INDEXEDDB) {
var indexedDB = (indexedDB || window.indexedDB ||
window.webkitIndexedDB ||
window.mozIndexedDB || window.OIndexedDB ||
window.msIndexedDB);
var req = indexedDB.open('My Cool App', 2.0);
req.onsuccess = function() {
var dbValue = req.result
.transaction('myStoreName', 'readonly')
.objectStore('myStoreName')
.get('some key');
expect(dbValue).to.be(value);
done();
};
} else if (localforage.driver() === localforage.WEBSQL) {
window.openDatabase('My Cool App', String(2.0), '',
4980736).transaction(function(t) {
t.executeSql('SELECT * FROM myStoreName WHERE key = ? ' +
'LIMIT 1', ['some key'], function(t, results) {
var dbValue = JSON.parse(results.rows.item(0).value);
expect(dbValue).to.be(value);
done();
});
});
} else if (localforage.driver() === localforage.LOCALSTORAGE) {
var dbValue = JSON.parse(
localStorage['My Cool App/myStoreName/some key']);
expect(dbValue).to.be(value);
done();
}
});
});
it("returns all values when config isn't passed arguments", function() {
expect(localforage.config()).to.be.an('object');
expect(Object.keys(localforage.config()).length).to.be(6);
});
// This may go away when https://github.com/mozilla/localForage/issues/168
// is fixed.
it('maintains config values across setDriver calls', function(done) {
localforage.config({
name: 'Mega Mozilla Dino'
});
localforage.length().then(function() {
return localforage.setDriver(localforage.LOCALSTORAGE);
}).then(function() {
expect(localforage.config('name')).to.be('Mega Mozilla Dino');
done();
});
});
it('returns error if database version is not a number', function(done) {
var configResult = localforage.config({
version: '2.0'
});
var error = 'Error: Database version must be a number.';
expect(configResult).to.not.be(true);
expect(configResult.toString()).to.be(error);
done();
});
});

View File

@@ -0,0 +1,29 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>localForage Custom Driver Tests!</title>
<link rel="stylesheet" href="/bower_components/mocha/mocha.css">
<script src="/bower_components/assert/assert.js"></script>
<script src="/bower_components/mocha/mocha.js"></script>
<script src="/bower_components/expect/index.js"></script>
<!-- Test runner -->
<script src="/test/runner.js"></script>
<!-- localForage -->
<script src="/dist/localforage.js"></script>
<!-- dummy custom localForage driver -->
<script src="/test/dummyStorageDriver.js"></script>
<!-- specs -->
<script src="/test/test.customdriver.js"></script>
</head>
<body>
<div id="mocha"></div>
</body>
</html>

View File

@@ -0,0 +1,203 @@
/* global describe:true, expect:true, it:true, dummyStorageDriver:true */
describe('When Custom Drivers are used', function() {
'use strict';
var errorMessage = 'Custom driver not compliant; see ' +
'https://mozilla.github.io/localForage/#definedriver';
it('fails to define a no-name custom driver', function(done) {
localforage.defineDriver({
_initStorage: function() {},
iterate: function() {},
getItem: function() {},
setItem: function() {},
removeItem: function() {},
clear: function() {},
length: function() {},
key: function() {},
keys: function() {}
}, null, function(err) {
expect(err).to.be.an(Error);
expect(err.message).to.be(errorMessage);
done();
});
});
it('fails to define a no-name custom driver [promise]', function(done) {
localforage.defineDriver({
_initStorage: function() {},
iterate: function() {},
getItem: function() {},
setItem: function() {},
removeItem: function() {},
clear: function() {},
length: function() {},
key: function() {},
keys: function() {}
}).then(null, function(err) {
expect(err).to.be.an(Error);
expect(err.message).to.be(errorMessage);
done();
});
});
it('fails to define a custom driver with missing methods', function(done) {
localforage.defineDriver({
_driver: 'missingMethodsDriver',
_initStorage: function() {},
iterate: function() {},
getItem: function() {},
setItem: function() {},
removeItem: function() {},
clear: function() {}
}, null, function(err) {
expect(err).to.be.an(Error);
expect(err.message).to.be(errorMessage);
done();
});
});
it('fails to define a custom driver with missing methods [promise]', function(done) {
localforage.defineDriver({
_driver: 'missingMethodsDriver',
_initStorage: function() {},
iterate: function() {},
getItem: function() {},
setItem: function() {},
removeItem: function() {},
clear: function() {}
}).then(null, function(err) {
expect(err).to.be.an(Error);
expect(err.message).to.be(errorMessage);
done();
});
});
it('defines a compliant custom driver', function(done) {
localforage.defineDriver(dummyStorageDriver, function() {
done();
});
});
it('defines a compliant custom driver [promise]', function(done) {
localforage.defineDriver(dummyStorageDriver).then(function() {
done();
});
});
it('sets a custom driver', function(done) {
localforage.defineDriver(dummyStorageDriver, function() {
localforage.setDriver(dummyStorageDriver._driver, function() {
expect(localforage.driver()).to.be(dummyStorageDriver._driver);
done();
});
});
});
it('sets a custom driver [promise]', function(done) {
localforage.defineDriver(dummyStorageDriver).then(function() {
return localforage.setDriver(dummyStorageDriver._driver);
}).then(function() {
expect(localforage.driver()).to.be(dummyStorageDriver._driver);
done();
});
});
it('defines a driver synchronously when it doesn\'t have _supports()', function(done) {
var customDriver = {
_driver: 'dummyStorageDriver' + (+new Date()),
_initStorage: function() { },
// _support: function() { return true; }
iterate: function() { },
getItem: function() { },
setItem: function() { },
removeItem: function() { },
clear: function() { },
length: function() { },
key: function() { },
keys: function() { }
};
localforage.defineDriver(customDriver);
localforage.setDriver(customDriver._driver).then(function() {
expect(localforage.driver()).to.be(customDriver._driver);
done();
});
});
it('defines a driver synchronously when it has boolean _supports()', function(done) {
var customDriver = {
_driver: 'dummyStorageDriver' + (+new Date()),
_initStorage: function() { },
_support: true,
iterate: function() { },
getItem: function() { },
setItem: function() { },
removeItem: function() { },
clear: function() { },
length: function() { },
key: function() { },
keys: function() { }
};
localforage.defineDriver(customDriver);
localforage.setDriver(customDriver._driver).then(function() {
expect(localforage.driver()).to.be(customDriver._driver);
done();
});
});
it('defines a driver asynchronously when _supports() returns a Promise<boolean>', function(done) {
var customDriver = {
_driver: 'dummyStorageDriver' + (+new Date()),
_initStorage: function() { },
_support: function() {
return Promise.resolve(true);
},
iterate: function() { },
getItem: function() { },
setItem: function() { },
removeItem: function() { },
clear: function() { },
length: function() { },
key: function() { },
keys: function() { }
};
localforage.defineDriver(customDriver).then(function() {
return localforage.setDriver(customDriver._driver);
}).then(function() {
expect(localforage.driver()).to.be(customDriver._driver);
done();
});
});
it('sets and uses a custom driver', function(done) {
localforage.defineDriver(dummyStorageDriver, function() {
localforage.setDriver(dummyStorageDriver._driver, function(err) {
expect(err).to.be(undefined);
localforage.setItem('testCallbackKey', 'testCallbackValue', function(err) {
expect(err).to.be(null);
localforage.getItem('testCallbackKey', function(err, value) {
expect(err).to.be(null);
expect(value).to.be('testCallbackValue');
done();
});
});
});
});
});
it('sets and uses a custom driver [promise]', function(done) {
localforage.defineDriver(dummyStorageDriver).then(function() {
return localforage.setDriver(dummyStorageDriver._driver);
}).then(function() {
return localforage.setItem('testPromiseKey', 'testPromiseValue');
}).then(function() {
return localforage.getItem('testPromiseKey');
}).then(function(value) {
expect(value).to.be('testPromiseValue');
done();
});
});
});

View File

@@ -0,0 +1,594 @@
/* global before:true, beforeEach:true, describe:true, expect:true, it:true */
// kinda lame to define this twice, but it seems require() isn't available here
function createBlob(parts, properties) {
/* global BlobBuilder,MSBlobBuilder,MozBlobBuilder,WebKitBlobBuilder */
parts = parts || [];
properties = properties || {};
try {
return new Blob(parts, properties);
} catch (e) {
if (e.name !== 'TypeError') {
throw e;
}
var Builder = typeof BlobBuilder !== 'undefined' ? BlobBuilder :
typeof MSBlobBuilder !== 'undefined' ? MSBlobBuilder :
typeof MozBlobBuilder !== 'undefined' ? MozBlobBuilder :
WebKitBlobBuilder;
var builder = new Builder();
for (var i = 0; i < parts.length; i += 1) {
builder.append(parts[i]);
}
return builder.getBlob(properties.type);
}
}
var DRIVERS = [
localforage.INDEXEDDB,
localforage.LOCALSTORAGE,
localforage.WEBSQL
];
DRIVERS.forEach(function(driverName) {
if ((!localforage.supports(localforage.INDEXEDDB) &&
driverName === localforage.INDEXEDDB) ||
(!localforage.supports(localforage.LOCALSTORAGE) &&
driverName === localforage.LOCALSTORAGE) ||
(!localforage.supports(localforage.WEBSQL) &&
driverName === localforage.WEBSQL)) {
// Browser doesn't support this storage library, so we exit the API
// tests.
return;
}
describe('Type handler for ' + driverName, function() {
'use strict';
this.timeout(30000);
before(function(done) {
localforage.setDriver(driverName).then(done);
});
beforeEach(function(done) {
localforage.clear(done);
});
it('saves a string [callback]', function(done) {
localforage.setItem('office', 'Initech', function(err, setValue) {
expect(setValue).to.be('Initech');
localforage.getItem('office', function(err, value) {
expect(value).to.be(setValue);
done();
});
});
});
it('saves a string [promise]', function(done) {
localforage.setItem('office', 'Initech').then(function(setValue) {
expect(setValue).to.be('Initech');
return localforage.getItem('office');
}).then(function(value) {
expect(value).to.be('Initech');
done();
});
});
it('saves a string like "[object Blob]" [promise]', function(done) {
localforage.setItem('fake Blob', '[object Blob]').then(function(setValue) {
expect(setValue).to.be('[object Blob]');
return localforage.getItem('fake Blob');
}).then(function(value) {
expect(value).to.be('[object Blob]');
done();
});
});
it('saves a number [callback]', function(done) {
localforage.setItem('number', 546, function(err, setValue) {
expect(setValue).to.be(546);
expect(setValue).to.be.a('number');
localforage.getItem('number', function(err, value) {
expect(value).to.be(setValue);
expect(value).to.be.a('number');
done();
});
});
});
it('saves a number [promise]', function(done) {
localforage.setItem('number', 546).then(function(setValue) {
expect(setValue).to.be(546);
expect(setValue).to.be.a('number');
return localforage.getItem('number');
}).then(function(value) {
expect(value).to.be(546);
expect(value).to.be.a('number');
done();
});
});
it('saves a boolean [callback]', function(done) {
localforage.setItem('boolean', false, function(err, setValue) {
expect(setValue).to.be(false);
expect(setValue).to.be.a('boolean');
localforage.getItem('boolean', function(err, value) {
expect(value).to.be(setValue);
expect(value).to.be.a('boolean');
done();
});
});
});
it('saves a boolean [promise]', function(done) {
localforage.setItem('boolean', false).then(function(setValue) {
expect(setValue).to.be(false);
expect(setValue).to.be.a('boolean');
return localforage.getItem('boolean');
}).then(function(value) {
expect(value).to.be(false);
expect(value).to.be.a('boolean');
done();
});
});
it('saves null [callback]', function(done) {
localforage.setItem('null', null, function(err, setValue) {
expect(setValue).to.be(null);
localforage.getItem('null', function(err, value) {
expect(value).to.be(null);
done();
});
});
});
it('saves null [promise]', function(done) {
localforage.setItem('null', null).then(function(setValue) {
expect(setValue).to.be(null);
return localforage.getItem('null');
}).then(function(value) {
expect(value).to.be(null);
done();
});
});
it('saves undefined as null [callback]', function(done) {
localforage.setItem('null', undefined, function(err, setValue) {
expect(setValue).to.be(null);
localforage.getItem('null', function(err, value) {
expect(value).to.be(null);
done();
});
});
});
it('saves undefined as null [promise]', function(done) {
localforage.setItem('null', undefined).then(function(setValue) {
expect(setValue).to.be(null);
return localforage.getItem('null');
}).then(function(value) {
expect(value).to.be(null);
done();
});
});
it('saves a float [callback]', function(done) {
localforage.setItem('float', 546.041, function(err, setValue) {
expect(setValue).to.be(546.041);
expect(setValue).to.be.a('number');
localforage.getItem('float', function(err, value) {
expect(value).to.be(setValue);
expect(value).to.be.a('number');
done();
});
});
});
it('saves a float [promise]', function(done) {
localforage.setItem('float', 546.041).then(function(setValue) {
expect(setValue).to.be(546.041);
expect(setValue).to.be.a('number');
return localforage.getItem('float');
}).then(function(value) {
expect(value).to.be(546.041);
expect(value).to.be.a('number');
done();
});
});
var arrayToSave = [2, 'one', true];
it('saves an array [callback]', function(done) {
localforage.setItem('array', arrayToSave, function(err, setValue) {
expect(setValue.length).to.be(arrayToSave.length);
expect(setValue instanceof Array).to.be(true);
localforage.getItem('array', function(err, value) {
expect(value.length).to.be(arrayToSave.length);
expect(value instanceof Array).to.be(true);
expect(value[1]).to.be.a('string');
done();
});
});
});
it('saves an array [promise]', function(done) {
localforage.setItem('array', arrayToSave).then(function(setValue) {
expect(setValue.length).to.be(arrayToSave.length);
expect(setValue instanceof Array).to.be(true);
return localforage.getItem('array');
}).then(function(value) {
expect(value.length).to.be(arrayToSave.length);
expect(value instanceof Array).to.be(true);
expect(value[1]).to.be.a('string');
done();
});
});
var objectToSave = {
floating: 43.01,
nested: {
array: [1, 2, 3]
},
nestedObjects: [
{truth: true},
{theCake: 'is a lie'},
{happiness: 'is a warm gun'},
false
],
string: 'bar'
};
it('saves a nested object [callback]', function(done) {
localforage.setItem('obj', objectToSave, function(err, setValue) {
expect(Object.keys(setValue).length)
.to.be(Object.keys(objectToSave).length);
expect(setValue).to.be.an('object');
localforage.getItem('obj', function(err, value) {
expect(Object.keys(value).length)
.to.be(Object.keys(objectToSave).length);
expect(value).to.be.an('object');
expect(value.nested).to.be.an('object');
expect(value.nestedObjects[0].truth).to.be.a('boolean');
expect(value.nestedObjects[1].theCake).to.be.a('string');
expect(value.nestedObjects[3]).to.be(false);
done();
});
});
});
it('saves a nested object [promise]', function(done) {
localforage.setItem('obj', objectToSave).then(function(setValue) {
expect(Object.keys(setValue).length)
.to.be(Object.keys(objectToSave).length);
expect(setValue).to.be.an('object');
return localforage.getItem('obj');
}).then(function(value) {
expect(Object.keys(value).length)
.to.be(Object.keys(objectToSave).length);
expect(value).to.be.an('object');
expect(value.nested).to.be.an('object');
expect(value.nestedObjects[0].truth).to.be.a('boolean');
expect(value.nestedObjects[1].theCake).to.be.a('string');
expect(value.nestedObjects[3]).to.be(false);
done();
});
});
// Skip binary (ArrayBuffer) data tests if Array Buffer isn't supported.
if (typeof ArrayBuffer !== 'undefined') {
var runBinaryTest = function(url, done) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
// When the AJAX state changes, save the photo locally.
request.onreadystatechange = function() {
if (request.readyState === request.DONE) {
var response = request.response;
localforage.setItem('ab', response, function(err, sab) {
expect(sab.toString())
.to.be('[object ArrayBuffer]');
expect(sab.byteLength)
.to.be(response.byteLength);
}).then(function() {
// TODO: Running getItem from inside the setItem
// callback times out on IE 10/11. Could be an
// open transaction issue?
localforage.getItem('ab', function(err, arrayBuff) {
expect(arrayBuff.toString())
.to.be('[object ArrayBuffer]');
expect(arrayBuff.byteLength)
.to.be(response.byteLength);
});
done();
});
}
};
request.send();
};
it('saves binary (ArrayBuffer) data', function(done) {
runBinaryTest('/test/photo.jpg', done);
});
it('saves odd length binary (ArrayBuffer) data', function(done) {
runBinaryTest('/test/photo2.jpg', done);
});
} else {
it.skip('saves binary (ArrayBuffer) data (ArrayBuffer type does not exist)');
}
// This does not run on PhantomJS < 2.0.
// https://github.com/ariya/phantomjs/issues/11013
// Skip binary(Blob) data tests if Blob isn't supported.
if (typeof Blob === 'function') {
it('saves binary (Blob) data', function(done) {
var fileParts = ['<a id="a"><b id="b">hey!</b></a>'];
var mimeString = 'text/html';
var testBlob = createBlob(fileParts, { 'type' : mimeString });
localforage.setItem('blob', testBlob, function(err, blob) {
expect(err).to.be(null);
expect(blob.toString())
.to.be('[object Blob]');
expect(blob.size)
.to.be(testBlob.size);
expect(blob.type)
.to.be(testBlob.type);
}).then(function() {
localforage.getItem('blob', function(err, blob) {
expect(err).to.be(null);
expect(blob.toString())
.to.be('[object Blob]');
expect(blob.size)
.to.be(testBlob.size);
expect(blob.type)
.to.be(testBlob.type);
done();
});
});
});
} else {
it.skip('saves binary (Blob) data (Blob type does not exist)');
}
if (typeof Blob === 'function') {
it('saves binary (Blob) data, iterate back', function(done) {
var fileParts = ['<a id="a"><b id="b">hey!</b></a>'];
var mimeString = 'text/html';
var testBlob = createBlob(fileParts, { 'type' : mimeString });
localforage.setItem('blob', testBlob, function(err, blob) {
expect(err).to.be(null);
expect(blob.toString())
.to.be('[object Blob]');
expect(blob.size)
.to.be(testBlob.size);
expect(blob.type)
.to.be(testBlob.type);
}).then(function() {
localforage.iterate(function(blob, key) {
if (key !== 'blob') {
return;
}
expect(blob.toString())
.to.be('[object Blob]');
expect(blob.size)
.to.be(testBlob.size);
expect(blob.type)
.to.be(testBlob.type);
done();
});
});
});
} else {
it.skip('saves binary (Blob) data (Blob type does not exist)');
}
});
describe('Typed Array handling in ' + driverName, function() {
if (typeof Int8Array !== 'undefined') {
it('saves an Int8Array', function(done) {
var array = new Int8Array(8);
array[2] = 65;
array[4] = 0;
localforage.setItem('array', array, function(err, writeValue) {
localforage.getItem('array', function(err, readValue) {
expect(readValue instanceof Int8Array).to.be(true);
expect(readValue[2]).to.be(array[2]);
expect(readValue[4]).to.be(writeValue[4]);
expect(readValue.length).to.be(writeValue.length);
done();
});
});
});
} else {
it.skip("doesn't have the Int8Array type");
}
if (typeof Uint8Array !== 'undefined') {
it('saves an Uint8Array', function(done) {
var array = new Uint8Array(8);
array[0] = 65;
array[4] = 0;
localforage.setItem('array', array, function(err, writeValue) {
localforage.getItem('array', function(err, readValue) {
expect(readValue instanceof Uint8Array).to.be(true);
expect(readValue[0]).to.be(array[0]);
expect(readValue[4]).to.be(writeValue[4]);
expect(readValue.length).to.be(writeValue.length);
done();
});
});
});
} else {
it.skip("doesn't have the Uint8Array type");
}
if (typeof Uint8ClampedArray !== 'undefined') {
it('saves an Uint8ClampedArray', function(done) {
var array = new Uint8ClampedArray(8);
array[0] = 0;
array[1] = 93;
array[2] = 350;
localforage.setItem('array', array, function(err, writeValue) {
localforage.getItem('array', function(err, readValue) {
expect(readValue instanceof Uint8ClampedArray)
.to.be(true);
expect(readValue[0]).to.be(array[0]);
expect(readValue[1]).to.be(array[1]);
expect(readValue[2]).to.be(array[2]);
expect(readValue[1]).to.be(writeValue[1]);
expect(readValue.length).to.be(writeValue.length);
done();
});
});
});
} else {
it.skip("doesn't have the Uint8Array type");
}
if (typeof Int16Array !== 'undefined') {
it('saves an Int16Array', function(done) {
var array = new Int16Array(8);
array[0] = 65;
array[4] = 0;
localforage.setItem('array', array, function(err, writeValue) {
localforage.getItem('array', function(err, readValue) {
expect(readValue instanceof Int16Array).to.be(true);
expect(readValue[0]).to.be(array[0]);
expect(readValue[4]).to.be(writeValue[4]);
expect(readValue.length).to.be(writeValue.length);
done();
});
});
});
} else {
it.skip("doesn't have the Int16Array type");
}
if (typeof Uint16Array !== 'undefined') {
it('saves an Uint16Array', function(done) {
var array = new Uint16Array(8);
array[0] = 65;
array[4] = 0;
localforage.setItem('array', array, function(err, writeValue) {
localforage.getItem('array', function(err, readValue) {
expect(readValue instanceof Uint16Array).to.be(true);
expect(readValue[0]).to.be(array[0]);
expect(readValue[4]).to.be(writeValue[4]);
expect(readValue.length).to.be(writeValue.length);
done();
});
});
});
} else {
it.skip("doesn't have the Uint16Array type");
}
if (typeof Int32Array !== 'undefined') {
it('saves an Int32Array', function(done) {
var array = new Int32Array(8);
array[0] = 65;
array[4] = 0;
localforage.setItem('array', array, function(err, writeValue) {
localforage.getItem('array', function(err, readValue) {
expect(readValue instanceof Int32Array).to.be(true);
expect(readValue[0]).to.be(array[0]);
expect(readValue[4]).to.be(writeValue[4]);
expect(readValue.length).to.be(writeValue.length);
done();
});
});
});
} else {
it.skip("doesn't have the Int32Array type");
}
if (typeof Uint32Array !== 'undefined') {
it('saves an Uint32Array', function(done) {
var array = new Uint32Array(8);
array[0] = 65;
array[4] = 0;
localforage.setItem('array', array, function(err, writeValue) {
localforage.getItem('array', function(err, readValue) {
expect(readValue instanceof Uint32Array).to.be(true);
expect(readValue[0]).to.be(array[0]);
expect(readValue[4]).to.be(writeValue[4]);
expect(readValue.length).to.be(writeValue.length);
done();
});
});
});
} else {
it.skip("doesn't have the Uint32Array type");
}
if (typeof Float32Array !== 'undefined') {
it('saves a Float32Array', function(done) {
var array = new Float32Array(8);
array[0] = 6.5;
array[4] = 0.1;
localforage.setItem('array', array, function(err, writeValue) {
localforage.getItem('array', function(err, readValue) {
expect(readValue instanceof Float32Array).to.be(true);
expect(readValue[0]).to.be(array[0]);
expect(readValue[4]).to.be(writeValue[4]);
expect(readValue.length).to.be(writeValue.length);
done();
});
});
});
} else {
it.skip("doesn't have the Float32Array type");
}
if (typeof Float64Array !== 'undefined') {
it('saves a Float64Array', function(done) {
var array = new Float64Array(8);
array[0] = 6.5;
array[4] = 0.1;
localforage.setItem('array', array, function(err, writeValue) {
localforage.getItem('array', function(err, readValue) {
expect(readValue instanceof Float64Array).to.be(true);
expect(readValue[0]).to.be(array[0]);
expect(readValue[4]).to.be(writeValue[4]);
expect(readValue.length).to.be(writeValue.length);
done();
});
});
});
} else {
it.skip("doesn't have the Float64Array type");
}
});
});

View File

@@ -0,0 +1,176 @@
/* global beforeEach:true, describe:true, expect:true, it:true */
describe('Driver API', function() {
'use strict';
beforeEach(function(done) {
if (localforage.supports(localforage.INDEXEDDB)) {
localforage.setDriver(localforage.INDEXEDDB, function() {
done();
});
} else if (localforage.supports(localforage.WEBSQL)) {
localforage.setDriver(localforage.WEBSQL, function() {
done();
});
} else {
done();
}
});
if ((localforage.supports(localforage.INDEXEDDB) &&
localforage.driver() === localforage.INDEXEDDB) ||
(localforage.supports(localforage.WEBSQL) &&
localforage.driver() === localforage.WEBSQL)) {
it('can change to localStorage from ' + localforage.driver() +
' [callback]', function(done) {
var previousDriver = localforage.driver();
localforage.setDriver(localforage.LOCALSTORAGE, function() {
expect(localforage.driver()).to.be(localforage.LOCALSTORAGE);
expect(localforage.driver()).to.not.be(previousDriver);
done();
});
});
it('can change to localStorage from ' + localforage.driver() +
' [promise]', function(done) {
var previousDriver = localforage.driver();
localforage.setDriver(localforage.LOCALSTORAGE).then(function() {
expect(localforage.driver()).to.be(localforage.LOCALSTORAGE);
expect(localforage.driver()).to.not.be(previousDriver);
done();
});
});
}
if (!localforage.supports(localforage.INDEXEDDB)) {
it("can't use unsupported IndexedDB [callback]", function(done) {
var previousDriver = localforage.driver();
expect(previousDriver).to.not.be(localforage.INDEXEDDB);
// These should be rejected in component builds but aren't.
// TODO: Look into why.
localforage.setDriver(localforage.INDEXEDDB, null, function() {
expect(localforage.driver()).to.be(previousDriver);
done();
});
});
it("can't use unsupported IndexedDB [promise]", function(done) {
var previousDriver = localforage.driver();
expect(previousDriver).to.not.be(localforage.INDEXEDDB);
// These should be rejected in component builds but aren't.
// TODO: Look into why.
localforage.setDriver(localforage.INDEXEDDB)
.then(null, function() {
expect(localforage.driver()).to.be(previousDriver);
done();
});
});
} else {
it('can set already active IndexedDB [callback]', function(done) {
var previousDriver = localforage.driver();
expect(previousDriver).to.be(localforage.INDEXEDDB);
localforage.setDriver(localforage.INDEXEDDB, function() {
expect(localforage.driver()).to.be(previousDriver);
done();
});
});
it('can set already active IndexedDB [promise]', function(done) {
var previousDriver = localforage.driver();
expect(previousDriver).to.be(localforage.INDEXEDDB);
localforage.setDriver(localforage.INDEXEDDB).then(function() {
expect(localforage.driver()).to.be(previousDriver);
done();
});
});
}
if (!localforage.supports(localforage.LOCALSTORAGE)) {
it("can't use unsupported localStorage [callback]", function(done) {
var previousDriver = localforage.driver();
expect(previousDriver).to.not.be(localforage.LOCALSTORAGE);
localforage.setDriver(localforage.LOCALSTORAGE, null, function() {
expect(localforage.driver()).to.be(previousDriver);
done();
});
});
it("can't use unsupported localStorage [promise]", function(done) {
var previousDriver = localforage.driver();
expect(previousDriver).to.not.be(localforage.LOCALSTORAGE);
localforage.setDriver(localforage.LOCALSTORAGE)
.then(null, function() {
expect(localforage.driver()).to.be(previousDriver);
done();
});
});
} else if (!localforage.supports(localforage.INDEXEDDB) &&
!localforage.supports(localforage.WEBSQL)) {
it('can set already active localStorage [callback]', function(done) {
var previousDriver = localforage.driver();
expect(previousDriver).to.be(localforage.LOCALSTORAGE);
localforage.setDriver(localforage.LOCALSTORAGE, function() {
expect(localforage.driver()).to.be(previousDriver);
done();
});
});
it('can set already active localStorage [promise]', function(done) {
var previousDriver = localforage.driver();
expect(previousDriver).to.be(localforage.LOCALSTORAGE);
localforage.setDriver(localforage.LOCALSTORAGE).then(function() {
expect(localforage.driver()).to.be(previousDriver);
done();
});
});
}
if (!localforage.supports(localforage.WEBSQL)) {
it("can't use unsupported WebSQL [callback]", function(done) {
var previousDriver = localforage.driver();
expect(previousDriver).to.not.be(localforage.WEBSQL);
localforage.setDriver(localforage.WEBSQL, null, function() {
expect(localforage.driver()).to.be(previousDriver);
done();
});
});
it("can't use unsupported WebSQL [promise]", function(done) {
var previousDriver = localforage.driver();
expect(previousDriver).to.not.be(localforage.WEBSQL);
localforage.setDriver(localforage.WEBSQL)
.then(null, function() {
expect(localforage.driver()).to.be(previousDriver);
done();
});
});
} else {
it('can set already active WebSQL [callback]', function(done) {
localforage.setDriver(localforage.WEBSQL, function() {
var previousDriver = localforage.driver();
expect(previousDriver).to.be(localforage.WEBSQL);
localforage.setDriver(localforage.WEBSQL, function() {
expect(localforage.driver()).to.be(previousDriver);
done();
});
});
});
it('can set already active WebSQL [promise]', function(done) {
localforage.setDriver(localforage.WEBSQL).then(function() {
var previousDriver = localforage.driver();
expect(previousDriver).to.be(localforage.WEBSQL);
localforage.setDriver(localforage.WEBSQL).then(function() {
expect(localforage.driver()).to.be(previousDriver);
done();
});
});
});
}
});

View File

@@ -0,0 +1,61 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>localForage Tests!</title>
<link rel="stylesheet" href="/bower_components/mocha/mocha.css">
<script src="/bower_components/assert/assert.js"></script>
<script src="/bower_components/mocha/mocha.js"></script>
<script src="/bower_components/expect/index.js"></script>
<script>
try {
window.originalIdbOpen = window.indexedDB.open;
window.indexedDB.open = function faultyIdbOpen() {
var openreq = {};
setTimeout(function() {
if (typeof openreq.onerror === 'function') {
openreq.onerror(new Event(new Error('OpenDatabase Faulty Driver Test!')));
}
});
return openreq;
};
} catch (error) { }
try {
window.originalOpenDatabase = window.openDatabase;
window.openDatabase = function faultyOpenDatabase() {
throw new Error('OpenDatabase Faulty Driver Test!');
};
} catch (error) { }
try {
window.originalLocalStorageSetItem = window.localStorage.setItem;
window.localStorage.setItem = function faultySetItemQuotaError() {
throw new DOMException('The quota has been exceeded.', 'QuotaExceededError');
};
} catch (error) { }
</script>
<!-- Modernizr -->
<script src="/bower_components/modernizr/modernizr.js"></script>
<!-- Test runner -->
<script src="/test/runner.js"></script>
<!-- localForage -->
<script src="/dist/localforage.js"></script>
<!-- specs -->
<script src="/test/test.faultydriver.js"></script>
</head>
<body>
<div id="mocha"></div>
</body>
</html>

View File

@@ -0,0 +1,52 @@
/* global beforeEach:true, describe:true, expect:true, it:true */
describe('When Driver Fails to Initialize', function() {
'use strict';
var FAULTYDRIVERS = [
localforage.INDEXEDDB,
localforage.WEBSQL,
localforage.LOCALSTORAGE
]
.filter(localforage.supports)
.filter(function(driverName) {
// FF doesn't allow you to override `localStorage.setItem`
// so if the faulty driver setup didn't succeed
// then skip the localStorage tests
return !(
driverName === localforage.LOCALSTORAGE &&
localStorage.setItem.toString().indexOf('[native code]') >= 0
);
});
FAULTYDRIVERS.forEach(function(driverName) {
describe(driverName, function() {
beforeEach(function() {
if (driverName === localforage.LOCALSTORAGE) {
localStorage.clear();
}
});
it('fails to setDriver ' + driverName + ' [callback]', function(done) {
localforage.setDriver(driverName, function() {
localforage.ready(function(err) {
expect(err).to.be.an(Error);
expect(err.message).to.be('No available storage method found.');
done();
});
});
});
it('fails to setDriver ' + driverName + ' [promise]', function(done) {
localforage.setDriver(driverName).then(function() {
return localforage.ready();
}).then(null, function(err) {
expect(err).to.be.an(Error);
expect(err.message).to.be('No available storage method found.');
done();
});
});
});
});
});

View File

@@ -0,0 +1,18 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Sub iFrame Test</title>
</head>
<body>
<div id="my-text"></div>
<script src="/dist/localforage.js"></script>
<script>localforage.setItem('my cool key',
'I have been set').then(function() {
localforage.getItem('my cool key').then(function(value) {
document.getElementById('my-text').innerHTML = value;
});
});</script>
</body>
</html>

View File

@@ -0,0 +1,33 @@
/* global before:true, after:true, describe:true, expect:true, it:true */
describe('Inside iFrames', function() {
'use strict';
before(function() {
var iFrame = window.document.createElement('iframe');
iFrame.name = 'iframe';
iFrame.id = 'iframe';
// TODO: Get this to be cross-origin.
iFrame.src = 'http://' + window.location.host +
'/test/test.iframecontents.html';
window.document.body.appendChild(iFrame);
});
after(function() {
var iFrame = window.document.getElementById('iframe');
iFrame.parentNode.removeChild(iFrame);
});
it('can run localForage in an iFrame', function(done) {
var timer = setInterval(function() {
var element = window.document.getElementById('iframe')
.contentWindow.document
.getElementById('my-text');
if (element && element.innerHTML) {
clearInterval(timer);
expect(element.innerHTML).to.be('I have been set');
done();
}
}, 10);
});
});

View File

@@ -0,0 +1,35 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>localForage Tests!</title>
<link rel="stylesheet" href="/bower_components/mocha/mocha.css">
<script src="/bower_components/assert/assert.js"></script>
<script src="/bower_components/mocha/mocha.js"></script>
<script src="/bower_components/expect/index.js"></script>
<!-- Modernizr -->
<script src="/bower_components/modernizr/modernizr.js"></script>
<!-- Test runner -->
<script src="/test/runner.js"></script>
<!-- localForage -->
<script src="/dist/localforage.js"></script>
<!-- specs -->
<script src="/test/test.api.js"></script>
<script src="/test/test.config.js"></script>
<script src="/test/test.datatypes.js"></script>
<script src="/test/test.drivers.js"></script>
<script src="/test/test.iframes.js"></script>
<script src="/test/test.webworkers.js"></script>
<script src="/test/test.serviceworkers.js"></script>
</head>
<body>
<div id="mocha"></div>
</body>
</html>

View File

@@ -0,0 +1,35 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>localForage (minified) Tests!</title>
<link rel="stylesheet" type="text/css"
href="/bower_components/mocha/mocha.css">
<script src="/bower_components/assert/assert.js"></script>
<script src="/bower_components/mocha/mocha.js"></script>
<script src="/bower_components/expect/index.js"></script>
<!-- Modernizr -->
<script src="/bower_components/modernizr/modernizr.js"></script>
<!-- Test runner -->
<script src="/test/runner.js"></script>
<!-- localForage -->
<script src="/dist/localforage.min.js"></script>
<!-- specs -->
<script src="/test/test.api.js"></script>
<script src="/test/test.config.js"></script>
<script src="/test/test.datatypes.js"></script>
<script src="/test/test.drivers.js"></script>
<script src="/test/test.iframes.js"></script>
<script src="/test/test.webworkers.js"></script>
</head>
<body>
<div id="mocha"></div>
</body>
</html>

View File

@@ -0,0 +1,47 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>localForage Tests!</title>
<link rel="stylesheet" href="/bower_components/mocha/mocha.css">
<script src="/bower_components/assert/assert.js"></script>
<script src="/bower_components/mocha/mocha.js"></script>
<script src="/bower_components/expect/index.js"></script>
<script>
// Virtually remove support for the drivers.
// This has to be done before localforage
// and Modernizr execute.
try {
window.indexedDB.open = null;
} catch (error) { }
try {
window.localStorage.setItem = null;
} catch (error) { }
try {
window.openDatabase = null;
} catch (error) { }
</script>
<!-- Modernizr -->
<script src="/bower_components/modernizr/modernizr.js"></script>
<!-- Test runner -->
<script src="/test/runner.js"></script>
<!-- localForage -->
<script src="/dist/localforage.js"></script>
<!-- specs -->
<script src="/test/test.nodriver.js"></script>
</head>
<body>
<div id="mocha"></div>
</body>
</html>

View File

@@ -0,0 +1,83 @@
/* global describe:true, expect:true, it:true, Modernizr:true */
describe('When No Drivers Are Available', function() {
'use strict';
var DRIVERS = [
localforage.INDEXEDDB,
localforage.LOCALSTORAGE,
localforage.WEBSQL
];
it('agrees with Modernizr on storage drivers support', function() {
expect(localforage.supports(localforage.INDEXEDDB)).to.be(false);
expect(localforage.supports(localforage.INDEXEDDB))
.to.be(Modernizr.indexeddb);
expect(localforage.supports(localforage.LOCALSTORAGE))
.to.be(false);
expect(localforage.supports(localforage.LOCALSTORAGE))
.to.be(Modernizr.localstorage);
expect(localforage.supports(localforage.WEBSQL)).to.be(false);
expect(localforage.supports(localforage.WEBSQL))
.to.be(Modernizr.websqldatabase);
});
it('fails to load localForage [callback]', function(done) {
localforage.ready(function(err) {
expect(err).to.be.an(Error);
expect(err.message).to.be('No available storage method found.');
done();
});
});
it('fails to load localForage [promise]', function(done) {
localforage.ready().then(null, function(err) {
expect(err).to.be.an(Error);
expect(err.message).to.be('No available storage method found.');
done();
});
});
it('has no driver set', function(done) {
localforage.ready(function() {
expect(localforage.driver()).to.be(null);
done();
});
});
DRIVERS.forEach(function(driverName) {
it('fails to setDriver ' + driverName + ' [callback]', function(done) {
localforage.setDriver(driverName, null, function(err) {
expect(err).to.be.an(Error);
expect(err.message).to.be('No available storage method found.');
done();
});
});
it('fails to setDriver ' + driverName + ' [promise]', function(done) {
localforage.setDriver(driverName).then(null, function(err) {
expect(err).to.be.an(Error);
expect(err.message).to.be('No available storage method found.');
done();
});
});
});
it('fails to setDriver using array parameter [callback]', function(done) {
localforage.setDriver(DRIVERS, null, function(err) {
expect(err).to.be.an(Error);
expect(err.message).to.be('No available storage method found.');
done();
});
});
it('fails to setDriver using array parameter [promise]', function(done) {
localforage.setDriver(DRIVERS).then(null, function(err) {
expect(err).to.be.an(Error);
expect(err.message).to.be('No available storage method found.');
done();
});
});
});

View File

@@ -0,0 +1,26 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>localForage require.js Tests!</title>
<link rel="stylesheet" href="/bower_components/mocha/mocha.css">
<script src="/bower_components/assert/assert.js"></script>
<script src="/bower_components/mocha/mocha.js"></script>
<script src="/bower_components/expect/index.js"></script>
<!-- require.js -->
<script src="/bower_components/requirejs/require.js"></script>
<!-- Modernizr -->
<script src="/bower_components/modernizr/modernizr.js"></script>
<!-- Test runner -->
<script src="/test/runner.js"></script>
</head>
<body>
<div id="mocha"></div>
</body>
</html>

View File

@@ -0,0 +1,109 @@
/* global navigator:true, window:true, Modernizr:true, describe:true, expect:true, it:true, xit:true, before:true, beforeEach:true, after:true*/
var DRIVERS = [
localforage.INDEXEDDB,
localforage.LOCALSTORAGE,
localforage.WEBSQL
];
DRIVERS.forEach(function(driverName) {
if ((!Modernizr.indexeddb && driverName === localforage.INDEXEDDB) ||
(!Modernizr.localstorage && driverName === localforage.LOCALSTORAGE) ||
(!Modernizr.websqldatabase && driverName === localforage.WEBSQL)) {
// Browser doesn't support this storage library, so we exit the API
// tests.
return;
}
describe('Service Worker support in ' + driverName, function() {
'use strict';
// Use this until a test is added to Modernizr
if (!('serviceworker' in Modernizr)) {
Modernizr.serviceworker = 'serviceWorker' in navigator;
}
if (!Modernizr.serviceworker) {
before.skip("doesn't have service worker support");
beforeEach.skip("doesn't have service worker support");
it.skip("doesn't have service worker support");
after.skip("doesn't have service worker support");
return;
}
if (!window.MessageChannel) {
before.skip("doesn't have MessageChannel support");
beforeEach.skip("doesn't have MessageChannel support");
it.skip("doesn't have MessageChannel support");
after.skip("doesn't have MessageChannel support");
return;
}
before(function(done) {
navigator.serviceWorker
.register('/test/serviceworker-client.js')
.then(function() {
return localforage.setDriver(driverName);
})
.then(done);
});
after(function(done) {
navigator.serviceWorker.ready
.then(function(registration) {
return registration.unregister();
})
.then(function(bool) {
if (bool) {
done();
} else {
done('service worker failed to unregister');
}
});
});
beforeEach(function(done) {
localforage.clear(done);
});
if (driverName === localforage.LOCALSTORAGE ||
driverName === localforage.WEBSQL) {
it.skip(driverName + ' is not supported in service workers');
return;
}
xit('should set a value on registration', function(done) {
navigator.serviceWorker.ready
.then(function() {
return localforage.getItem('service worker registration');
})
.then(function(result) {
expect(result)
.to.equal('serviceworker present');
done();
})
.catch(function(error) {
done(error);
});
});
it('saves data', function(done) {
var messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function(event) {
expect(event.data.body)
.to.be('I have been set using ' + driverName);
done();
};
navigator.serviceWorker.ready
.then(function(registration) {
registration.active.postMessage({
driver: driverName,
value: 'I have been set'
}, [messageChannel.port2]);
})
.catch(function(error) {
done(error);
});
});
});
});

View File

@@ -0,0 +1,34 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>localForage WebPack Tests!</title>
<link rel="stylesheet" href="/bower_components/mocha/mocha.css">
<script src="/bower_components/assert/assert.js"></script>
<script src="/bower_components/mocha/mocha.js"></script>
<script src="/bower_components/expect/index.js"></script>
<!-- Modernizr -->
<script src="/bower_components/modernizr/modernizr.js"></script>
<!-- localForage -->
<script src="/test/localforage.webpack.js"></script>
<!-- Test runner -->
<script src="/test/runner.js"></script>
<!-- specs -->
<script src="/test/test.api.js"></script>
<script src="/test/test.config.js"></script>
<script src="/test/test.datatypes.js"></script>
<script src="/test/test.drivers.js"></script>
<script src="/test/test.iframes.js"></script>
<script src="/test/test.webworkers.js"></script>
</head>
<body>
<div id="mocha"></div>
</body>
</html>

View File

@@ -0,0 +1,63 @@
/* global before:true, beforeEach:true, describe:true, expect:true, it:true, Modernizr:true */
var DRIVERS = [
localforage.INDEXEDDB,
localforage.LOCALSTORAGE,
localforage.WEBSQL
];
DRIVERS.forEach(function(driverName) {
if ((!localforage.supports(localforage.INDEXEDDB) &&
driverName === localforage.INDEXEDDB) ||
(!localforage.supports(localforage.LOCALSTORAGE) &&
driverName === localforage.LOCALSTORAGE) ||
(!localforage.supports(localforage.WEBSQL) &&
driverName === localforage.WEBSQL)) {
// Browser doesn't support this storage library, so we exit the API
// tests.
return;
}
describe('Web Worker support in ' + driverName, function() {
'use strict';
before(function(done) {
localforage.setDriver(driverName).then(done);
});
beforeEach(function(done) {
localforage.clear(done);
});
if (!Modernizr.webworkers) {
it.skip('doesn\'t have web worker support');
return;
}
if (driverName === localforage.LOCALSTORAGE ||
driverName === localforage.WEBSQL) {
it.skip(driverName + ' is not supported in web workers');
return;
}
it('saves data', function(done) {
var webWorker = new Worker('/test/webworker-client.js');
webWorker.addEventListener('message', function(e) {
var body = e.data.body;
window.console.log(body);
expect(body).to.be('I have been set');
done();
});
webWorker.addEventListener('error', function(e) {
window.console.log(e);
});
webWorker.postMessage({
driver: driverName,
value: 'I have been set'
});
});
});
});

View File

@@ -0,0 +1,22 @@
/*globals importScripts:true, self:true */
importScripts("/dist/localforage.js");
self.addEventListener('message', function(e) {
function handleError(e) {
self.postMessage({
error: JSON.stringify(e),
body: e,
fail: true
});
}
localforage.setDriver(e.data.driver, function() {
localforage.setItem('web worker', e.data.value, function() {
localforage.getItem('web worker', function(err, value) {
self.postMessage({
body: value
});
});
}, handleError).catch(handleError);
}, handleError);
}, false);