describe('railsResourceFactory', function () { 'use strict'; beforeEach(function() { module('rails'); angular.module('rails').factory('railsTestInterceptor', function () { return function (promise) { return promise.then(function (response) { response.data.interceptorAdded = 'x'; return response; }); } }); }); describe('singular', function() { var $httpBackend, $rootScope, factory, Test, testInterceptor, config = { url: '/test', name: 'test' }; beforeEach(inject(function (_$httpBackend_, _$rootScope_, railsResourceFactory, railsTestInterceptor) { $httpBackend = _$httpBackend_; $rootScope = _$rootScope_; factory = railsResourceFactory; Test = railsResourceFactory(config); testInterceptor = railsTestInterceptor; })); afterEach(function() { $httpBackend.verifyNoOutstandingExpectation(); $httpBackend.verifyNoOutstandingRequest(); }); it('query should return resource object when response is single object', inject(function($httpBackend) { var promise, result; $httpBackend.expectGET('/test').respond(200, {test: {abc: 'xyz'}}); expect(promise = Test.query()).toBeDefined(); promise.then(function (response) { result = response; }); $httpBackend.flush(); expect(result).toBeInstanceOf(Test); expect(result).toEqualData({abc: 'xyz'}); })); it('query should return no data on 204', inject(function($httpBackend) { var promise, result; $httpBackend.expectGET('/test').respond(204); expect(promise = Test.query()).toBeDefined(); promise.then(function (response) { result = response; }); $httpBackend.flush(); expect(result).toBeUndefined(); })); it('query should add parameter abc=1', inject(function($httpBackend) { var promise; $httpBackend.expectGET('/test?abc=1').respond(200, {test: {abc: 'xyz'}}); expect(promise = Test.query({abc: '1'})).toBeDefined(); $httpBackend.flush(); })); it('query should add parameters abc=1 & xyz=2', inject(function($httpBackend) { var promise; $httpBackend.expectGET('/test?abc=1&xyz=2').respond(200, {test: {abc: 'xyz'}}); expect(promise = Test.query({abc: '1', xyz: 2})).toBeDefined(); $httpBackend.flush(); })); it('query with default params should add parameter abc=1', inject(function($httpBackend) { var promise, resource, defaultParamsConfig = {}; $httpBackend.expectGET('/test?abc=1').respond(200, {test: {abc: 'xyz'}}); angular.copy(config, defaultParamsConfig); defaultParamsConfig.defaultParams = {abc: '1'}; resource = factory(defaultParamsConfig); expect(promise = resource.query()).toBeDefined(); $httpBackend.flush(); })); it('get should return resource object when response is 200', inject(function($httpBackend) { var promise, result; $httpBackend.expectGET('/test/123').respond(200, {test: {id: 123, abc: 'xyz'}}); expect(promise = Test.get(123)).toBeDefined(); promise.then(function (response) { result = response; }); $httpBackend.flush(); expect(result).toBeInstanceOf(Test); expect(result).toEqualData({id: 123, abc: 'xyz'}); })); it('get should work with id as string as well', inject(function($httpBackend) { var promise, result; $httpBackend.expectGET('/test/123').respond(200, {test: {id: 123, abc: 'xyz'}}); expect(promise = Test.get('123')).toBeDefined(); promise.then(function (response) { result = response; }); $httpBackend.flush(); expect(result).toBeInstanceOf(Test); expect(result).toEqualData({id: 123, abc: 'xyz'}); })); it('get should call failure callback when 404', inject(function($httpBackend) { var promise, success = false, failure = false; $httpBackend.expectGET('/test/123').respond(404); expect(promise = Test.get(123)).toBeDefined(); promise.then(function () { success = true; }, function () { failure = true; }); $httpBackend.flush(); expect(success).toBe(false); expect(failure).toBe(true); })); it('get with default params should add parameter abc=1', inject(function($httpBackend) { var promise, resource, defaultParamsConfig = {}; $httpBackend.expectGET('/test/123?abc=1').respond(200, {test: {abc: 'xyz'}}); angular.copy(config, defaultParamsConfig); defaultParamsConfig.defaultParams = {abc: '1'}; resource = factory(defaultParamsConfig); expect(promise = resource.get(123)).toBeDefined(); $httpBackend.flush(); })); it('should be able to create new instance and save it', inject(function($httpBackend) { var data = new Test({abcDef: 'xyz'}); $httpBackend.expectPOST('/test', {test: {abc_def: 'xyz'}}).respond(200, {test: {id: 123, abc_def: 'xyz'}}); data.create(); $httpBackend.flush(); expect(data).toEqualData({id: 123, abcDef: 'xyz'}); })); it("should return a promise when calling save", inject(function($httpBackend) { var promise, data; data = new Test({abc_def: 'xyz'}); $httpBackend.expectPOST('/test', {test: {abc_def: 'xyz'}}).respond(200, {test: {id: 123, abc_def: 'xyz'}}); expect(promise = data.save()).toBeDefined(); $httpBackend.flush() })); it('should be able to create new instance and save it using save', inject(function($httpBackend) { var data = new Test({abcDef: 'xyz'}); $httpBackend.expectPOST('/test', {test: {abc_def: 'xyz'}}).respond(200, {test: {id: 123, abc_def: 'xyz'}}); data.save(); $httpBackend.flush(); expect(data).toEqualData({id: 123, abcDef: 'xyz'}); })); it('should be able to create new instance and update it', inject(function($httpBackend) { var data = new Test({abcDef: 'xyz'}); $httpBackend.expectPOST('/test', {test: {abc_def: 'xyz'}}).respond(200, {test: {id: 123, abc_def: 'xyz'}}); data.create(); $httpBackend.flush(1); expect(data).toEqualData({id: 123, abcDef: 'xyz'}); $httpBackend.expectPUT('/test/123', {test: {abc_def: 'xyz', id: 123, xyz: 'abc'}}).respond(200, {test: {id: 123, abc_def: 'xyz', xyz: 'abc', extra: 'test'}}); data.xyz = 'abc'; data.update(); $httpBackend.flush(); expect(data).toEqualData({id: 123, abcDef: 'xyz', xyz: 'abc', extra: 'test'}); })); it('should be able to create new instance and update it using save', inject(function($httpBackend) { var data = new Test({abcDef: 'xyz'}); $httpBackend.expectPOST('/test', {test: {abc_def: 'xyz'}}).respond(200, {test: {id: 123, abc_def: 'xyz'}}); data.save(); $httpBackend.flush(1); expect(data).toEqualData({id: 123, abcDef: 'xyz'}); $httpBackend.expectPUT('/test/123', {test: {abc_def: 'xyz', id: 123, xyz: 'abc'}}).respond(200, {test: {id: 123, abc_def: 'xyz', xyz: 'abc', extra: 'test'}}); data.xyz = 'abc'; data.save(); $httpBackend.flush(); expect(data).toEqualData({id: 123, abcDef: 'xyz', xyz: 'abc', extra: 'test'}); })); it('should be able to create new instance and update it using PATCH', inject(function($httpBackend) { var promise, Resource, data, defaultParamsConfig = {}; angular.copy(config, defaultParamsConfig); defaultParamsConfig.updateMethod = 'patch'; Resource = factory(defaultParamsConfig); data = new Resource({abcDef: 'xyz'}); $httpBackend.expectPOST('/test', {test: {abc_def: 'xyz'}}).respond(200, {test: {id: 123, abc_def: 'xyz'}}); data.create(); $httpBackend.flush(1); expect(data).toEqualData({id: 123, abcDef: 'xyz'}); $httpBackend.expectPATCH('/test/123', {test: {abc_def: 'xyz', id: 123, xyz: 'abc'}}).respond(200, {test: {id: 123, abc_def: 'xyz', xyz: 'abc', extra: 'test'}}); data.xyz = 'abc'; data.update(); $httpBackend.flush(); expect(data).toEqualData({id: 123, abcDef: 'xyz', xyz: 'abc', extra: 'test'}); })); it('should be able to create new instance and update it using save using PATCH', inject(function($httpBackend) { var promise, Resource, data, defaultParamsConfig = {}; angular.copy(config, defaultParamsConfig); defaultParamsConfig.updateMethod = 'patch'; Resource = factory(defaultParamsConfig); data = new Resource({abcDef: 'xyz'}); $httpBackend.expectPOST('/test', {test: {abc_def: 'xyz'}}).respond(200, {test: {id: 123, abc_def: 'xyz'}}); data.save(); $httpBackend.flush(1); expect(data).toEqualData({id: 123, abcDef: 'xyz'}); $httpBackend.expectPATCH('/test/123', {test: {abc_def: 'xyz', id: 123, xyz: 'abc'}}).respond(200, {test: {id: 123, abc_def: 'xyz', xyz: 'abc', extra: 'test'}}); data.xyz = 'abc'; data.save(); $httpBackend.flush(); expect(data).toEqualData({id: 123, abcDef: 'xyz', xyz: 'abc', extra: 'test'}); })); it('create with default params should add parameter abc=1', inject(function($httpBackend) { var promise, Resource, data, defaultParamsConfig = {}; $httpBackend.expectPOST('/test?abc=1', {test: {}}).respond(200, {test: {abc: 'xyz'}}); angular.copy(config, defaultParamsConfig); defaultParamsConfig.defaultParams = {abc: '1'}; Resource = factory(defaultParamsConfig); data = new Resource(); data.create(); $httpBackend.flush(); })); it('should be able to get resource and update it', inject(function($httpBackend) { var promise, result; $httpBackend.expectGET('/test/123').respond(200, {test: {id: 123, abc: 'xyz', xyz: 'abcd'}}); expect(promise = Test.get(123)).toBeDefined(); promise.then(function (response) { result = response; }); $httpBackend.flush(); expect(result).toBeInstanceOf(Test); expect(result).toEqualData({id: 123, abc: 'xyz', xyz: 'abcd'}); $httpBackend.expectPUT('/test/123', {test: {id: 123, abc: 'xyz', xyz: 'abc'}}).respond(200, {test: {id: 123, abc: 'xyz', xyz: 'abc', extra: 'test'}}); result.xyz = 'abc'; result.update(); $httpBackend.flush(); // abc was originally set on the object so it should still be there after the update expect(result).toEqualData({id: 123, abc: 'xyz', xyz: 'abc', extra: 'test'}); })); it('update should handle 204 response', inject(function($httpBackend) { var promise, result; $httpBackend.expectGET('/test/123').respond(200, {test: {id: 123, abc: 'xyz'}}); expect(promise = Test.get(123)).toBeDefined(); promise.then(function (response) { result = response; }); $httpBackend.flush(); expect(result).toBeInstanceOf(Test); expect(result).toEqualData({id: 123, abc: 'xyz'}); $httpBackend.expectPUT('/test/123', {test: {id: 123, abc: 'xyz', xyz: 'abc'}}).respond(204); result.xyz = 'abc'; result.update(); $httpBackend.flush(); expect(result).toEqualData({id: 123, abc: 'xyz', xyz: 'abc'}); })); it('should be able to delete instance returned from get', inject(function($httpBackend) { var promise, result; $httpBackend.expectGET('/test/123').respond(200, {test: {id: 123, abc: 'xyz'}}); expect(promise = Test.get(123)).toBeDefined(); promise.then(function (response) { result = response; }); $httpBackend.flush(); expect(result).toBeInstanceOf(Test); expect(result).toEqualData({id: 123, abc: 'xyz'}); $httpBackend.expectDELETE('/test/123').respond(204); result.remove(); $httpBackend.flush(); })); it('delete with default params should add parameter abc=1', inject(function($httpBackend) { var promise, Resource, data, defaultParamsConfig = {}; $httpBackend.expectDELETE('/test/123?abc=1').respond(204); angular.copy(config, defaultParamsConfig); defaultParamsConfig.defaultParams = {abc: '1'}; Resource = factory(defaultParamsConfig); data = new Resource(); data.id = 123; data.remove(); $httpBackend.flush(); })); it('should transform attributes on build', function() { var test = new Test({id: 123, abc_def: "T"}); expect(test).toEqualData({id: 123, abcDef: "T"}); }); it('should allow changing urls after first operation', function () { $httpBackend.expectGET('/test/123').respond(200, {test: {id: 123, abc: 'xyz'}}); Test.get(123); $httpBackend.flush(); $httpBackend.expectGET('/test2/123').respond(200, {test: {id: 123, abc: 'xyz'}}); Test.setUrl('/test2'); Test.get(123); $httpBackend.flush(); }); it('should support constructing with date properties', function () { var testDate = new Date(), test = new Test({id: 123, testDate: testDate}); expect(test.testDate).toBe(testDate); }); angular.forEach(['post', 'put', 'patch'], function (method) { it('should be able to ' + method + ' to arbitrary url', inject(function($httpBackend) { var promise, result = {}; promise = Test['$' + method]('/xyz', {id: 123, abc: 'xyz', xyz: 'abc'}); $httpBackend['expect' + angular.uppercase(method)]('/xyz', {test: {id: 123, abc: 'xyz', xyz: 'abc'}}).respond(200, {test: {id: 123, abc: 'xyz', xyz: 'abc', extra: 'test'}}); promise.then(function (response) { result = response; }); $httpBackend.flush(); // abc was originally set on the object so it should still be there after the update expect(result).toEqualData({id: 123, abc: 'xyz', xyz: 'abc', extra: 'test'}); })); it('should be able to ' + method + ' instance to arbitrary url', inject(function($httpBackend) { var test = new Test({id: 123, abc: 'xyz', xyz: 'abc'}); $httpBackend['expect' + angular.uppercase(method)]('/xyz', {test: {id: 123, abc: 'xyz', xyz: 'abc'}}).respond(200, {test: {id: 123, abc: 'xyz', xyz: 'abc', extra: 'test'}}); test['$' + method]('/xyz'); $httpBackend.flush(); // abc was originally set on the object so it should still be there after the update expect(test).toEqualData({id: 123, abc: 'xyz', xyz: 'abc', extra: 'test'}); })); }); it('should be able to $post an array of resources', function () { var data = [{id: 123, abc: 'xyz'}, {id: 124, abc: 'xyz'}]; $httpBackend['expectPOST']('/xyz', {tests: data} ).respond(200, {tests: data}); Test.$post('/xyz', data); $httpBackend.flush(); }); }); describe('plural', function() { var $httpBackend, $rootScope, factory, PluralTest, pluralConfig = { url: '/pluralTest', name: 'singular', pluralName: 'plural' }; beforeEach(inject(function (_$httpBackend_, _$rootScope_, railsResourceFactory) { $httpBackend = _$httpBackend_; $rootScope = _$rootScope_; factory = railsResourceFactory; PluralTest = railsResourceFactory(pluralConfig); })); afterEach(function() { $httpBackend.verifyNoOutstandingExpectation(); $httpBackend.verifyNoOutstandingRequest(); }); it('query should return array of resource objects when result is an array', inject(function($httpBackend) { var promise, result; $httpBackend.expectGET('/pluralTest').respond(200, {plural: [{abc: 'xyz'}, {xyz: 'abc'}]}); expect(promise = PluralTest.query()).toBeDefined(); promise.then(function (response) { result = response; }); $httpBackend.flush(); expect(angular.isArray(result)).toBe(true); angular.forEach(result, function (value) { expect(value).toBeInstanceOf(PluralTest); }); expect(result[0]).toEqualData({abc: 'xyz'}); expect(result[1]).toEqualData({xyz: 'abc'}); })); it('query should return empty array when result is empty array', inject(function($httpBackend) { var promise, result; $httpBackend.expectGET('/pluralTest').respond(200, {plural: []}); expect(promise = PluralTest.query()).toBeDefined(); promise.then(function (response) { result = response; }); $httpBackend.flush(); expect(angular.isArray(result)).toBe(true); expect(result.length).toBe(0); })); }); describe('subclassing', function() { var $httpBackend, $rootScope, Book, CarManual, // generated CoffeeScript Code __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; beforeEach(inject(function (_$httpBackend_, _$rootScope_, RailsResource) { $httpBackend = _$httpBackend_; $rootScope = _$rootScope_; // generated CoffeeScript Code Book = (function(_super) { __extends(Book, _super); // @configure url: '/books', name: 'book' Book.configure({ url: '/books', name: 'book' }); function Book() { Book.__super__.constructor.apply(this, arguments); this.subclass = true; } return Book; })(RailsResource); CarManual = (function(_super) { __extends(CarManual, _super); CarManual.configure({ url: '/car_manuals', name: 'car_manual' }); function CarManual() { CarManual.__super__.constructor.apply(this, arguments); this.subclass = true; } return CarManual; })(Book); })); afterEach(function() { $httpBackend.verifyNoOutstandingExpectation(); $httpBackend.verifyNoOutstandingRequest(); }); it('get should return resource instance of subclass', function() { var promise, result; $httpBackend.expectGET('/car_manuals/123').respond(200, {car_manual: {id: 123, abc: 'xyz'}}); expect(promise = CarManual.get(123)).toBeDefined(); promise.then(function (response) { result = response; }); $httpBackend.flush(); expect(result).toBeInstanceOf(CarManual); expect(result).toEqualData({id: 123, abc: 'xyz', subclass: true}); }); it('should have configuration per-class', function() { var promise, result; $httpBackend.expectGET('/books/123').respond(200, {book: {id: 123, abc: 'xyz'}}); expect(promise = Book.get(123)).toBeDefined(); promise.then(function (response) { result = response; }); $httpBackend.flush(); expect(result).toBeInstanceOf(Book); expect(result).toEqualData({id: 123, abc: 'xyz', subclass: true}); }); it('should allow constructing subclasses with data', function () { var carManual = new CarManual({id: 1, name: 'Honda CR-V'}); expect(carManual.id).toBe(1); expect(carManual.name).toBe('Honda CR-V'); }); }); });