falcor
Version:
A JavaScript library for efficient data fetching.
381 lines (360 loc) • 13.1 kB
JavaScript
var ErrorDataSource = require("../../data/ErrorDataSource");
var LocalDataSource = require("../../data/ErrorDataSource");
var clean = require("../../cleanData").clean;
var falcor = require("../../../lib");
var Model = falcor.Model;
var noOp = function() {};
var InvalidSourceError = require('../../../lib/errors/InvalidSourceError');
var toObservable = require('../../toObs');
var isAssertionError = require('./../../isAssertionError');
function errorOnCompleted(done) {
return function() {
done(new Error('should not onCompleted'));
};
};
function doneOnError(done) {
return function(e) {
if (isAssertionError(e)) {
return done(e);
}
return done();
};
};
describe("Error", function() {
it("should get a hard error from the DataSource with _treatDataSourceErrorsAsJSONGraphErrors.", function(done) {
var model = new Model({
source: new ErrorDataSource(503, "Timeout"),
_treatDataSourceErrorsAsJSONGraphErrors: true
});
var onNext = jest.fn();
toObservable(model.
get(["test", {to: 5}, "summary"])).
doAction(onNext, function(err) {
expect(onNext).toHaveBeenCalledTimes(1);
expect(clean(onNext.mock.calls[0][0])).toEqual({
json: {
test: {
0: {},
1: {},
2: {},
3: {},
4: {},
5: {}
}
}
});
expect(err.length).toBe(6);
// not in boxValue mode
var expected = {
path: [],
value: {
status: 503,
message: "Timeout"
}
};
err.forEach(function(e, i) {
expected.path = ["test", i, "summary"];
expect(e).toEqual(expected);
});
}).
subscribe(noOp,
function(e) {
if (isAssertionError(e)) {
done(e);
} else {
done();
}
},
function() {
done('Should not onComplete');
});
});
it("should get a hard error from the DataSource.", function(done) {
var model = new Model({
source: new ErrorDataSource(503, "Timeout")
});
toObservable(model.
get(["test", {to: 5}, "summary"])).
doAction(noOp, function(err) {
// not in boxValue mode
var expected = {
$type: "error",
value: {
status: 503,
message: "Timeout"
}
};
expect(err).toEqual(expected);
}).
subscribe(noOp,
function(e) {
if (isAssertionError(e)) {
done(e);
} else {
done();
}
},
function() {
done('Should not onComplete');
});
});
it("should get a hard error from the DataSource with some data found in the cache with _treatDataSourceErrorsAsJSONGraphErrors.", function(done) {
var model = new Model({
_treatDataSourceErrorsAsJSONGraphErrors: true,
source: new ErrorDataSource(503, "Timeout"),
cache: {
test: {
0: {
summary: "in cache"
},
5: {
summary: "in cache"
}
}
}
});
var onNext = jest.fn();
toObservable(model.
get(["test", {to: 5}, "summary"])).
doAction(onNext, function(err) {
// Ensure onNext is called correctly
expect(onNext).toHaveBeenCalledTimes(1);
expect(err.length).toBe(4);
// not in boxValue mode
var expected = {
path: [],
value: {
status: 503,
message: "Timeout"
}
};
err.forEach(function(e, i) {
expected.path = ["test", i + 1, "summary"];
expect(e).toEqual(expected);
});
}).
subscribe(noOp, doneOnError(done), errorOnCompleted(done));
});
it("should get a hard error from the DataSource with some data found in the cache.", function(done) {
var model = new Model({
source: new ErrorDataSource(503, "Timeout"),
cache: {
test: {
0: {
summary: "in cache"
},
5: {
summary: "in cache"
}
}
}
});
var onNext = jest.fn();
toObservable(model.
get(["test", {to: 5}, "summary"])).
doAction(onNext, function(err) {
expect(onNext).toHaveBeenCalledTimes(1);
expect(clean(onNext.mock.calls[0][0])).toEqual({
json: {
test: {
0: {
summary: 'in cache'
},
5: {
summary: 'in cache'
}
}
}
});
// not in boxValue mode
var expected = {
$type: "error",
value: {
status: 503,
message: "Timeout"
}
};
expect(err).toEqual(expected);
}).
subscribe(noOp, doneOnError(done), errorOnCompleted(done));
});
it("should onNext when only receiving errors.", function(done) {
var model = new Model({
source: new Model({
cache: {
test: {
0: {
summary: {
$type: 'error',
value: {
message: 'Oops!',
status: 500
}
}
},
1: {
summary: {
$type: 'error',
value: {
message: 'Oops!',
status: 500
}
}
}
}
}
}).asDataSource()
});
var onNext = jest.fn();
toObservable(model.
get(["test", {to: 1}, "summary"])).
doAction(onNext, function(err) {
expect(onNext).toHaveBeenCalledTimes(1);
expect(clean(onNext.mock.calls[0][0])).toEqual({
json: {
test: {
0: {},
1: {}
}
}
});
// not in boxValue mode
var expected = [
{"path":["test",0,"summary"],"value":{"message":"Oops!","status":500}},
{"path":["test",1,"summary"],"value":{"message":"Oops!","status":500}}
];
expect(err).toEqual(expected);
}).
subscribe(noOp, doneOnError(done), errorOnCompleted(done));
});
it("should onNext when receiving errors and missing paths.", function(done) {
var model = new Model({
source: new Model({
cache: {
test: {
0: {
summary: {
$type: 'error',
value: {
message: 'Oops!',
status: 500
}
}
},
5: {
summary: {
$type: 'error',
value: {
message: 'Oops!',
status: 500
}
}
}
}
}
}).asDataSource()
});
var onNext = jest.fn();
toObservable(model.
get(["test", {to: 5}, "summary"])).
doAction(onNext, function(err) {
expect(onNext).toHaveBeenCalledTimes(1);
expect(clean(onNext.mock.calls[0][0]), 'json from onNext').toEqual({
json: {
test: {
0: {},
5: {}
}
}
});
// not in boxValue mode
var expected = [
{"path":["test",0,"summary"],"value":{"message":"Oops!","status":500}},
{"path":["test",5,"summary"],"value":{"message":"Oops!","status":500}}
];
expect(err).toEqual(expected);
}).
subscribe(noOp, doneOnError(done), errorOnCompleted(done));
});
it('should allow for dataSources to immediately throw an error (set)', function(done) {
var routes = {
set: function() {
return thisVarDoesNotExistAndThatsAFact;
}
};
var model = new falcor.Model({ source: routes });
var onNext = jest.fn();
var onError = jest.fn();
toObservable(model.
set({
paths: [['titlesById', 242, 'rating']],
jsonGraph: {
titlesById: {
242: {
rating: 5
}
}
}
})).
doAction(onNext, onError).
doAction(noOp, function() {
expect(onNext).not.toHaveBeenCalled();
expect(onError).toHaveBeenCalledTimes(1);
expect(onError.mock.calls[0][0].name).toBe(InvalidSourceError.name);
}).
subscribe(noOp, function(e) {
if (isAssertionError(e)) {
return done(e);
}
return done();
}, done.bind(null, new Error('should not complete')));
});
it('should allow for dataSources to immediately throw an error (get)', function(done) {
var routes = {
get: function() {
return thisVarDoesNotExistAndThatsAFact;
}
};
var model = new falcor.Model({ source: routes });
var onNext = jest.fn();
var onError = jest.fn();
toObservable(model.
get(['path', 'to', 'value'])).
doAction(onNext, function(e) {
expect(onNext).toHaveBeenCalledTimes(1);
expect(clean(onNext.mock.calls[0][0])).toEqual({
json: {
}
})
expect(e.name).toBe(InvalidSourceError.name);
}).
subscribe(noOp, function(e) {
if (isAssertionError(e)) {
return done(e);
}
return done();
}, done.bind(null, new Error('should not complete')));
});
it('should allow for dataSources to immediately throw an error (call)', function(done) {
var routes = {
call: function() {
return thisVarDoesNotExistAndThatsAFact;
}
};
var model = new falcor.Model({ source: routes });
var onNext = jest.fn();
toObservable(model.
call(['videos', 1234, 'rating'], 5)).
doAction(onNext).
doAction(noOp, function(err) {
expect(onNext).not.toHaveBeenCalled();
expect(err.name).toBe(InvalidSourceError.name);
}).
subscribe(noOp, function(e) {
if (isAssertionError(e)) {
return done(e);
}
return done();
}, done.bind(null, new Error('should not complete')));
});
});