Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

redis-dataloader

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

redis-dataloader - npm Package Compare versions

Comparing version 0.3.0 to 0.4.1

LICENSE

2

gulpfile.js

@@ -1,3 +0,1 @@

'use strict';
const gulp = require('gulp');

@@ -4,0 +2,0 @@ const mocha = require('gulp-mocha');

@@ -1,150 +0,165 @@

'use strict';
const _ = require('lodash');
const Q = require('q');
const Promise = require('bluebird');
const DataLoader = require('dataloader');
const stringify = require('json-stable-stringify');
module.exports = fig => {
const redis = fig.redis;
const redis = fig.redis;
const parse = (resp, opt) => Q.Promise((resolve, reject) => {
try {
if(resp === '' || resp === null) {
resolve(resp);
}
else if(opt.deserialize) {
resolve(opt.deserialize(resp));
}
else {
resolve(JSON.parse(resp));
}
const parse = (resp, opt) =>
new Promise((resolve, reject) => {
try {
if (resp === '' || resp === null) {
resolve(resp);
} else if (opt.deserialize) {
resolve(opt.deserialize(resp));
} else {
resolve(JSON.parse(resp));
}
catch(err) {
reject(err);
}
} catch (err) {
reject(err);
}
});
const toString = (val, opt) => {
if(val === null) {
return Q('');
}
else if(opt.serialize) {
return Q(opt.serialize(val));
}
else if(_.isObject(val)) {
return Q(JSON.stringify(val));
}
else {
return Q.reject(new Error('Must be Object or Null'));
}
};
const toString = (val, opt) => {
if (val === null) {
return Promise.resolve('');
} else if (opt.serialize) {
return Promise.resolve(opt.serialize(val));
} else if (_.isObject(val)) {
return Promise.resolve(JSON.stringify(val));
} else {
return Promise.reject(new Error('Must be Object or Null'));
}
};
const makeKey = (keySpace, key) => `${keySpace}:${key}`;
const makeKey = (keySpace, key, cacheKeyFn) =>
`${keySpace}:${cacheKeyFn(key)}`;
const rSetAndGet = (keySpace, key, rawVal, opt) => toString(rawVal, opt)
.then(val => Q.Promise((resolve, reject) => {
const fullKey = makeKey(keySpace, key);
const multi = redis.multi();
multi.set(fullKey, val);
if(opt.expire) {
const rSetAndGet = (keySpace, key, rawVal, opt) =>
toString(rawVal, opt).then(
val =>
new Promise((resolve, reject) => {
const fullKey = makeKey(keySpace, key, opt.cacheKeyFn);
const multi = redis.multi();
multi.set(fullKey, val);
if (opt.expire) {
multi.expire(fullKey, opt.expire);
}
multi.get(fullKey);
multi.exec((err, replies) => err ?
reject(err) : parse(_.last(replies), opt).then(resolve)
);
}));
}
multi.get(fullKey);
multi.exec(
(err, replies) =>
err ? reject(err) : parse(_.last(replies), opt).then(resolve)
);
})
);
const rGet = (keySpace, key, opt) => Q.Promise(
(resolve, reject) => redis.get(
makeKey(keySpace, key),
(err, result) => err ? reject(err) : parse(result, opt).then(resolve)
)
const rGet = (keySpace, key, opt) =>
new Promise((resolve, reject) =>
redis.get(
makeKey(keySpace, key, opt.cacheKeyFn),
(err, result) => (err ? reject(err) : parse(result, opt).then(resolve))
)
);
const rMGet = (keySpace, keys, opt) => Q.Promise(
(resolve, reject) => redis.mget(
_.map(keys, k => makeKey(keySpace, k)),
(err, results) => err ?
reject(err) :
Q.all(_.map(results, r => parse(r, opt))).then(resolve)
)
const rMGet = (keySpace, keys, opt) =>
new Promise((resolve, reject) =>
redis.mget(
_.map(keys, k => makeKey(keySpace, k, opt.cacheKeyFn)),
(err, results) =>
err
? reject(err)
: Promise.map(results, r => parse(r, opt)).then(resolve)
)
);
const rDel = (keySpace, key) => Q.Promise((resolve, reject) => redis.del(
makeKey(keySpace, key), (err, resp) => err ? reject(err) : resolve(resp)
));
const rDel = (keySpace, key, opt) =>
new Promise((resolve, reject) =>
redis.del(
makeKey(keySpace, key, opt.cacheKeyFn),
(err, resp) => (err ? reject(err) : resolve(resp))
)
);
return class RedisDataLoader {
constructor(ks, userLoader, opt) {
const customOptions = ['expire', 'serialize', 'deserialize'];
this.opt = _.pick(opt, customOptions) || {};
this.keySpace = ks;
this.loader = new DataLoader(
keys => rMGet(this.keySpace, keys, this.opt)
.then(results => Q.all(_.map(
results,
(v, i) => {
if(v === '') {
return Q(null);
}
else if(v === null) {
return userLoader.load(keys[i])
.then(resp => rSetAndGet(
this.keySpace, keys[i], resp, this.opt
))
.then(r => r === '' ? null : r);
}
else {
return Q(v);
}
}
))),
_.omit(opt, customOptions)
);
}
return class RedisDataLoader {
constructor(ks, userLoader, opt) {
const customOptions = [
'expire',
'serialize',
'deserialize',
'cacheKeyFn',
];
this.opt = _.pick(opt, customOptions) || {};
load(key) {
return key ?
Q(this.loader.load(key)) :
Q.reject(new TypeError('key parameter is required'));
}
this.opt.cacheKeyFn =
this.opt.cacheKeyFn || (k => (_.isObject(k) ? stringify(k) : k));
loadMany(keys) {
return keys ?
Q(this.loader.loadMany(keys)) :
Q.reject(new TypeError('keys parameter is required'));
}
this.keySpace = ks;
this.loader = new DataLoader(
keys =>
rMGet(
this.keySpace,
_.map(keys, this.opt.cacheKeyFn),
this.opt
).then(results =>
Promise.map(results, (v, i) => {
if (v === '') {
return Promise.resolve(null);
} else if (v === null) {
return userLoader
.load(keys[i])
.then(resp =>
rSetAndGet(this.keySpace, keys[i], resp, this.opt)
)
.then(r => (r === '' ? null : r));
} else {
return Promise.resolve(v);
}
})
),
_.chain(opt)
.omit(customOptions)
.extend({ cacheKeyFn: this.opt.cacheKeyFn })
.value()
);
}
prime(key, val) {
if(!key) {
return Q.reject(new TypeError('key parameter is required'));
}
else if(val === undefined) {
return Q.reject(new TypeError('value parameter is required'));
}
else {
return rSetAndGet(this.keySpace, key, val, this.opt)
.then(r => {
this.loader.clear(key)
.prime(key, r === '' ? null : r);
});
}
}
load(key) {
return key
? Promise.resolve(this.loader.load(key))
: Promise.reject(new TypeError('key parameter is required'));
}
clear(key) {
return key ?
rDel(this.keySpace, key).then(() => this.loader.clear(key)) :
Q.reject(new TypeError('key parameter is required'));
}
loadMany(keys) {
return keys
? Promise.resolve(this.loader.loadMany(keys))
: Promise.reject(new TypeError('keys parameter is required'));
}
clearAllLocal() {
return Q(this.loader.clearAll());
}
prime(key, val) {
if (!key) {
return Promise.reject(new TypeError('key parameter is required'));
} else if (val === undefined) {
return Promise.reject(new TypeError('value parameter is required'));
} else {
return rSetAndGet(this.keySpace, key, val, this.opt).then(r => {
this.loader.clear(key).prime(key, r === '' ? null : r);
});
}
}
clearLocal(key) {
return Q(this.loader.clear(key));
}
};
clear(key) {
return key
? rDel(this.keySpace, key, this.opt).then(() => this.loader.clear(key))
: Promise.reject(new TypeError('key parameter is required'));
}
clearAllLocal() {
return Promise.resolve(this.loader.clearAll());
}
clearLocal(key) {
return Promise.resolve(this.loader.clear(key));
}
};
};
{
"name": "redis-dataloader",
"version": "0.3.0",
"version": "0.4.1",
"description": "DataLoader Using Redis as a Cache",

@@ -27,8 +27,10 @@ "main": "index.js",

"dependencies": {
"bluebird": "^3.5.0",
"dataloader": "^1.2.0",
"lodash": "^4.17.2",
"q": "^1.4.1"
"json-stable-stringify": "^1.0.1",
"lodash": "^4.17.2"
},
"devDependencies": {
"chai": "^3.5.0",
"chai-as-promised": "^7.1.1",
"gulp": "^3.9.1",

@@ -35,0 +37,0 @@ "gulp-mocha": "^3.0.1",

@@ -93,2 +93,3 @@ # Redis Dataloader

By default, the "cacheKeyFn" will serialize objects and arrays using [json-stable-stringify](https://github.com/substack/json-stable-stringify) and allow all other values to pass through unchanged.

@@ -95,0 +96,0 @@ ### Caching

@@ -1,6 +0,6 @@

'use strict';
const _ = require('lodash');
const Q = require('q');
const expect = require('chai').expect;
const Promise = require('bluebird');
const chai = require('chai');
chai.use(require('chai-as-promised'));
const { expect } = chai;
const sinon = require('sinon');

@@ -12,286 +12,320 @@ const redis = require('redis').createClient();

describe('redis-dataloader', () => {
beforeEach(done => {
const rDel = key => Q.Promise((resolve, reject) => redis.del(
key, (err, resp) => err ? reject(err) : resolve(resp)
));
beforeEach(() => {
const rDel = key =>
new Promise((resolve, reject) =>
redis.del(key, (err, resp) => (err ? reject(err) : resolve(resp)))
);
this.rSet = (k, v) => Q.Promise((resolve, reject) => redis.set(
k, v, (err, resp) => err ? reject(err) : resolve(resp)
));
this.rSet = (k, v) =>
new Promise((resolve, reject) =>
redis.set(k, v, (err, resp) => (err ? reject(err) : resolve(resp)))
);
this.keySpace = 'key-space';
this.data = {
json: { foo: 'bar' },
'null': null
};
this.rGet = k =>
new Promise((resolve, reject) => {
redis.get(k, (err, resp) => (err ? rejecte(err) : resolve(resp)));
});
this.stubs = {};
this.keySpace = 'key-space';
this.data = {
json: { foo: 'bar' },
null: null,
};
this.loadFn = sinon.stub();
this.stubs = {};
_.each(this.data, (v, k) => {
this.loadFn.withArgs(k).returns(Q(v));
});
this.loadFn = sinon.stub();
this.userLoader = () => new DataLoader(
keys => Q.all(_.map(keys, this.loadFn)),
{ cache: false }
);
_.each(this.data, (v, k) => {
this.loadFn.withArgs(k).returns(Promise.resolve(v));
});
Q.all(_.map(_.keys(this.data), k => rDel(`${this.keySpace}:${k}`)))
.then(() => {
this.loader = new RedisDataLoader(this.keySpace, this.userLoader());
this.loadFn
.withArgs(sinon.match({ a: 1, b: 2 }))
.returns(Promise.resolve({ bar: 'baz' }));
this.noCacheLoader = new RedisDataLoader(
this.keySpace,
this.userLoader(),
{ cache: false }
);
this.loadFn
.withArgs(sinon.match([1, 2]))
.returns(Promise.resolve({ ball: 'bat' }));
done();
}).done();
this.userLoader = () =>
new DataLoader(keys => Promise.map(keys, this.loadFn), {
cache: false,
});
return Promise.map(
_.keys(this.data).concat(['{"a":1,"b":2}', '[1,2]']),
k => rDel(`${this.keySpace}:${k}`)
).then(() => {
this.loader = new RedisDataLoader(this.keySpace, this.userLoader());
this.noCacheLoader = new RedisDataLoader(
this.keySpace,
this.userLoader(),
{ cache: false }
);
});
});
afterEach(() => _.each(this.stubs, s => s.restore()));
afterEach(() => {
_.each(this.stubs, s => s.restore());
});
describe('load', () => {
it('should load json value', done => {
this.loader.load('json').then(data => {
expect(data).to.deep.equal(this.data.json);
done();
}).done();
});
describe('load', () => {
it('should load json value', () =>
this.loader.load('json').then(data => {
expect(data).to.deep.equal(this.data.json);
}));
it('should require key', done => {
this.loader.load().catch(err => {
expect(err).to.be.instanceof(TypeError);
done();
}).done();
});
it('should allow for object key', () =>
this.loader
.load({ a: 1, b: 2 })
.then(data => {
expect(data).to.deep.equal({ bar: 'baz' });
return this.rGet(`${this.keySpace}:{"a":1,"b":2}`);
})
.then(data => {
expect(JSON.parse(data)).to.deep.equal({ bar: 'baz' });
}));
it('should use local cache on second load', done => {
this.stubs.redisMGet = sinon.stub(redis, 'mget', (keys, cb) => {
cb(null, [JSON.stringify(this.data.json)]);
});
it('should ignore key order on object key', () =>
this.loader
.load({ b: 2, a: 1 })
.then(data => {
expect(data).to.deep.equal({ bar: 'baz' });
return this.rGet(`${this.keySpace}:{"a":1,"b":2}`);
})
.then(data => {
expect(JSON.parse(data)).to.deep.equal({ bar: 'baz' });
}));
this.loader.load('json')
.then(data => {
expect(this.loadFn.callCount).to.equal(0);
expect(this.stubs.redisMGet.callCount).to.equal(1);
return this.loader.load('json');
})
.then(data => {
expect(this.loadFn.callCount).to.equal(0);
expect(this.stubs.redisMGet.callCount).to.equal(1);
done();
}).done();
});
it('should handle key that is array', () =>
this.loader
.load([1, 2])
.then(data => {
expect(data).to.deep.equal({ ball: 'bat' });
return this.rGet(`${this.keySpace}:[1,2]`);
})
.then(data => {
expect(JSON.parse(data)).to.deep.equal({ ball: 'bat' });
}));
it('should not use in memory cache if option is passed', done => {
this.stubs.redisMGet = sinon.stub(redis, 'mget', (keys, cb) => {
cb(null, [JSON.stringify(this.data.json)]);
});
it('should require key', () =>
expect(this.loader.load()).to.be.rejectedWith(TypeError));
this.noCacheLoader.load('json')
.then(data => {
expect(this.loadFn.callCount).to.equal(0);
expect(this.stubs.redisMGet.callCount).to.equal(1);
return this.noCacheLoader.load('json');
})
.then(data => {
expect(this.loadFn.callCount).to.equal(0);
expect(this.stubs.redisMGet.callCount).to.equal(2);
done();
}).done();
});
it('should use local cache on second load', () => {
this.stubs.redisMGet = sinon.stub(redis, 'mget', (keys, cb) => {
cb(null, [JSON.stringify(this.data.json)]);
});
it('should load null values', done => {
this.loader.load('null')
.then(data => {
expect(data).to.be.null;
return this.loader.load('null');
})
.then(data => {
expect(data).to.be.null;
done();
}).done();
return this.loader
.load('json')
.then(data => {
expect(this.loadFn.callCount).to.equal(0);
expect(this.stubs.redisMGet.callCount).to.equal(1);
return this.loader.load('json');
})
.then(data => {
expect(this.loadFn.callCount).to.equal(0);
expect(this.stubs.redisMGet.callCount).to.equal(1);
});
});
it('should handle redis cacheing of null values', done => {
this.noCacheLoader.load('null')
.then(data => {
expect(data).to.be.null;
return this.noCacheLoader.load('null');
})
.then(data => {
expect(data).to.be.null;
done();
}).done();
it('should not use in memory cache if option is passed', () => {
this.stubs.redisMGet = sinon.stub(redis, 'mget', (keys, cb) => {
cb(null, [JSON.stringify(this.data.json)]);
});
return this.noCacheLoader
.load('json')
.then(data => {
expect(this.loadFn.callCount).to.equal(0);
expect(this.stubs.redisMGet.callCount).to.equal(1);
return this.noCacheLoader.load('json');
})
.then(data => {
expect(this.loadFn.callCount).to.equal(0);
expect(this.stubs.redisMGet.callCount).to.equal(2);
});
});
it('should handle redis key expiration if set', done => {
const loader = new RedisDataLoader(
this.keySpace,
this.userLoader(),
{ cache: false, expire: 1 }
);
it('should load null values', () =>
this.loader
.load('null')
.then(data => {
expect(data).to.be.null;
return this.loader.load('null');
})
.then(data => {
expect(data).to.be.null;
}));
loader.load('json')
.then(data => {
expect(data).to.deep.equal(this.data.json);
setTimeout(() => {
loader.load('json')
.then(data => {
expect(data).to.deep.equal(this.data.json);
expect(this.loadFn.callCount).to.equal(2);
done();
}).done();
}, 1100);
}).done();
});
it('should handle redis cacheing of null values', () =>
this.noCacheLoader
.load('null')
.then(data => {
expect(data).to.be.null;
return this.noCacheLoader.load('null');
})
.then(data => {
expect(data).to.be.null;
}));
it('should handle custom serialize and deserialize method', done => {
const loader = new RedisDataLoader(
this.keySpace,
this.userLoader(),
{
serialize: v => 100,
deserialize: v => new Date(Number(v))
}
);
it('should handle redis key expiration if set', done => {
const loader = new RedisDataLoader(this.keySpace, this.userLoader(), {
cache: false,
expire: 1,
});
loader.load('json')
.then(data => {
expect(data).to.be.instanceof(Date);
expect(data.getTime()).to.equal(100);
loader
.load('json')
.then(data => {
expect(data).to.deep.equal(this.data.json);
setTimeout(() => {
loader
.load('json')
.then(data => {
expect(data).to.deep.equal(this.data.json);
expect(this.loadFn.callCount).to.equal(2);
done();
}).done();
});
})
.done();
}, 1100);
})
.catch(done)
.done();
});
describe('loadMany', () => {
it('should load multiple keys', done => {
this.loader.loadMany(['json', 'null'])
.then(results => {
expect(results).to.deep.equal([this.data.json, this.data.null]);
done();
}).done();
});
it('should handle custom serialize and deserialize method', () => {
const loader = new RedisDataLoader(this.keySpace, this.userLoader(), {
serialize: v => 100,
deserialize: v => new Date(Number(v)),
});
it('should handle empty array', done => {
this.loader.loadMany([])
.then(results => {
expect(results).to.deep.equal([]);
done();
}).done();
});
it('should require array', done => {
this.loader.loadMany().catch(err => {
expect(err).to.be.instanceof(TypeError);
done();
}).done();
});
return loader.load('json').then(data => {
expect(data).to.be.instanceof(Date);
expect(data.getTime()).to.equal(100);
});
});
});
describe('prime', () => {
it('should set cache', done => {
this.loader.prime('json', { new: 'value' })
.then(() => this.loader.load('json'))
.then(data => {
expect(data).to.deep.equal({ new: 'value' });
done();
}).done();
});
describe('loadMany', () => {
it('should load multiple keys', () =>
this.loader.loadMany(['json', 'null']).then(results => {
expect(results).to.deep.equal([this.data.json, this.data.null]);
}));
it('should handle primeing without local cache', done => {
this.noCacheLoader.prime('json', { new: 'value' })
.then(() => this.noCacheLoader.load('json'))
.then(data => {
expect(data).to.deep.equal({ new: 'value' });
done();
}).done();
});
it('should handle object key', () =>
this.loader.loadMany([{ a: 1, b: 2 }]).then(results => {
expect(results).to.deep.equal([{ bar: 'baz' }]);
}));
it('should require key', done => {
this.loader.prime(undefined, { new: 'value' })
.catch(err => {
expect(err).to.be.instanceof(TypeError);
done();
}).done();
});
it('should handle empty array', () =>
this.loader.loadMany([]).then(results => {
expect(results).to.deep.equal([]);
}));
it('should require value', done => {
this.loader.prime('json').catch(err => {
expect(err).to.be.instanceof(TypeError);
done();
}).done();
});
it('should require array', () =>
expect(this.loader.loadMany()).to.be.rejectedWith(TypeError));
});
it('should allow null for value', done => {
this.loader.prime('json', null)
.then(() => this.loader.load('json'))
.then(data => {
expect(data).to.be.null;
done();
}).done();
});
});
describe('prime', () => {
it('should set cache', () =>
this.loader
.prime('json', { new: 'value' })
.then(() => this.loader.load('json'))
.then(data => {
expect(data).to.deep.equal({ new: 'value' });
}));
describe('clear', () => {
it('should clear cache', done => {
this.loader.load('json')
.then(() => this.loader.clear('json'))
.then(() => this.loader.load('json'))
.then(data => {
expect(data).to.deep.equal(this.data.json);
expect(this.loadFn.callCount).to.equal(2);
done();
}).done();
});
it('should handle object key', () =>
this.loader
.prime({ a: 1, b: 2 }, { new: 'val' })
.then(() => this.loader.load({ a: 1, b: 2 }))
.then(data => {
expect(data).to.deep.equal({ new: 'val' });
}));
it('should require a key', done => {
this.loader.clear()
.catch(err => {
expect(err).to.be.instanceof(TypeError);
done();
}).done();
});
});
it('should handle primeing without local cache', () =>
this.noCacheLoader
.prime('json', { new: 'value' })
.then(() => this.noCacheLoader.load('json'))
.then(data => {
expect(data).to.deep.equal({ new: 'value' });
}));
describe('clearAllLocal', () => {
it('should clear all local in-memory cache', done => {
this.loader.loadMany(['json', 'null'])
.then(() => this.loader.clearAllLocal())
.then(() => this.rSet(
`${this.keySpace}:json`, JSON.stringify({ new: 'valeo' })
))
.then(() => this.rSet(
`${this.keySpace}:null`, JSON.stringify({ foo: 'bar' })
))
.then(() => this.loader.loadMany(['null', 'json']))
.then(data => {
expect(data).to.deep.equal([{ foo: 'bar' }, { new: 'valeo' }]);
done();
}).done();
});
});
it('should require key', () =>
expect(this.loader.prime(undefined, { new: 'value' })).to.be.rejectedWith(
TypeError
));
describe('clearLocal', () => {
it('should clear local cache for a specific key', done => {
this.loader.loadMany(['json', 'null'])
.then(() => this.loader.clearLocal('json'))
.then(() => this.rSet(
`${this.keySpace}:json`, JSON.stringify({ new: 'valeo' })
))
.then(() => this.rSet(
`${this.keySpace}:null`, JSON.stringify({ foo: 'bar' })
))
.then(() => this.loader.loadMany(['null', 'json']))
.then(data => {
expect(data).to.deep.equal([null, { new: 'valeo' }]);
done();
}).done();
});
});
it('should require value', () =>
expect(this.loader.prime('json')).to.be.rejectedWith(TypeError));
it('should allow null for value', () =>
this.loader
.prime('json', null)
.then(() => this.loader.load('json'))
.then(data => {
expect(data).to.be.null;
}));
});
describe('clear', () => {
it('should clear cache', () =>
this.loader
.load('json')
.then(() => this.loader.clear('json'))
.then(() => this.loader.load('json'))
.then(data => {
expect(data).to.deep.equal(this.data.json);
expect(this.loadFn.callCount).to.equal(2);
}));
it('should handle object key', () =>
this.loader
.load({ a: 1, b: 2 })
.then(() => this.loader.clear({ a: 1, b: 2 }))
.then(() => this.loader.load({ a: 1, b: 2 }))
.then(data => {
expect(data).to.deep.equal({ bar: 'baz' });
expect(this.loadFn.callCount).to.equal(2);
}));
it('should require a key', () =>
expect(this.loader.clear()).to.be.rejectedWith(TypeError));
});
describe('clearAllLocal', () => {
it('should clear all local in-memory cache', () =>
this.loader
.loadMany(['json', 'null'])
.then(() => this.loader.clearAllLocal())
.then(() =>
this.rSet(`${this.keySpace}:json`, JSON.stringify({ new: 'valeo' }))
)
.then(() =>
this.rSet(`${this.keySpace}:null`, JSON.stringify({ foo: 'bar' }))
)
.then(() => this.loader.loadMany(['null', 'json']))
.then(data => {
expect(data).to.deep.equal([{ foo: 'bar' }, { new: 'valeo' }]);
}));
});
describe('clearLocal', () => {
it('should clear local cache for a specific key', () =>
this.loader
.loadMany(['json', 'null'])
.then(() => this.loader.clearLocal('json'))
.then(() =>
this.rSet(`${this.keySpace}:json`, JSON.stringify({ new: 'valeo' }))
)
.then(() =>
this.rSet(`${this.keySpace}:null`, JSON.stringify({ foo: 'bar' }))
)
.then(() => this.loader.loadMany(['null', 'json']))
.then(data => {
expect(data).to.deep.equal([null, { new: 'valeo' }]);
}));
});
});

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc