8
0

model.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /**
  2. * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. 'use strict';
  6. const modules = bender.amd.require( 'model', 'eventinfo', 'ckeditorerror' );
  7. let Car, car;
  8. describe( 'Model', () => {
  9. beforeEach( 'Create a test model instance', () => {
  10. const Model = modules.model;
  11. Car = class extends Model {};
  12. car = new Car( {
  13. color: 'red',
  14. year: 2015
  15. } );
  16. } );
  17. //////////
  18. it( 'should set _attributes on creation', () => {
  19. expect( car._attributes ).to.deep.equal( {
  20. color: 'red',
  21. year: 2015
  22. } );
  23. } );
  24. it( 'should get correctly after set', () => {
  25. car.color = 'blue';
  26. expect( car.color ).to.equal( 'blue' );
  27. expect( car._attributes.color ).to.equal( 'blue' );
  28. } );
  29. it( 'should get correctly after setting _attributes', () => {
  30. car._attributes.color = 'blue';
  31. expect( car.color ).to.equal( 'blue' );
  32. } );
  33. it( 'should add properties on creation', () => {
  34. let car = new Car( null, {
  35. prop: 1
  36. } );
  37. expect( car ).to.have.property( 'prop' ).to.equal( 1 );
  38. } );
  39. //////////
  40. describe( 'set', () => {
  41. it( 'should work when passing an object', () => {
  42. car.set( {
  43. color: 'blue', // Override
  44. wheels: 4,
  45. seats: 5
  46. } );
  47. expect( car._attributes ).to.deep.equal( {
  48. color: 'blue',
  49. year: 2015,
  50. wheels: 4,
  51. seats: 5
  52. } );
  53. } );
  54. it( 'should work when passing a key/value pair', () => {
  55. car.set( 'color', 'blue' );
  56. car.set( 'wheels', 4 );
  57. expect( car._attributes ).to.deep.equal( {
  58. color: 'blue',
  59. year: 2015,
  60. wheels: 4
  61. } );
  62. } );
  63. it( 'should fire the "change" event', () => {
  64. const EventInfo = modules.eventinfo;
  65. let spy = sinon.spy();
  66. let spyColor = sinon.spy();
  67. let spyYear = sinon.spy();
  68. let spyWheels = sinon.spy();
  69. car.on( 'change', spy );
  70. car.on( 'change:color', spyColor );
  71. car.on( 'change:year', spyYear );
  72. car.on( 'change:wheels', spyWheels );
  73. // Set property in all possible ways.
  74. car.color = 'blue';
  75. car.set( { year: 2003 } );
  76. car.set( 'wheels', 4 );
  77. // Check number of calls.
  78. sinon.assert.calledThrice( spy );
  79. sinon.assert.calledOnce( spyColor );
  80. sinon.assert.calledOnce( spyYear );
  81. sinon.assert.calledOnce( spyWheels );
  82. // Check context.
  83. sinon.assert.alwaysCalledOn( spy, car );
  84. sinon.assert.calledOn( spyColor, car );
  85. sinon.assert.calledOn( spyYear, car );
  86. sinon.assert.calledOn( spyWheels, car );
  87. // Check params.
  88. sinon.assert.calledWithExactly( spy, sinon.match.instanceOf( EventInfo ), 'color', 'blue', 'red' );
  89. sinon.assert.calledWithExactly( spy, sinon.match.instanceOf( EventInfo ), 'year', 2003, 2015 );
  90. sinon.assert.calledWithExactly( spy, sinon.match.instanceOf( EventInfo ), 'wheels', 4, sinon.match.typeOf( 'undefined' ) );
  91. sinon.assert.calledWithExactly( spyColor, sinon.match.instanceOf( EventInfo ), 'blue', 'red' );
  92. sinon.assert.calledWithExactly( spyYear, sinon.match.instanceOf( EventInfo ), 2003, 2015 );
  93. sinon.assert.calledWithExactly( spyWheels, sinon.match.instanceOf( EventInfo ), 4, sinon.match.typeOf( 'undefined' ) );
  94. } );
  95. it( 'should not fire the "change" event for the same attribute value', () => {
  96. let spy = sinon.spy();
  97. let spyColor = sinon.spy();
  98. car.on( 'change', spy );
  99. car.on( 'change:color', spyColor );
  100. // Set the "color" property in all possible ways.
  101. car.color = 'red';
  102. car.set( 'color', 'red' );
  103. car.set( { color: 'red' } );
  104. sinon.assert.notCalled( spy );
  105. sinon.assert.notCalled( spyColor );
  106. } );
  107. it( 'should throw when overriding already existing property', () => {
  108. const CKEditorError = modules.ckeditorerror;
  109. car.normalProperty = 1;
  110. expect( () => {
  111. car.set( 'normalProperty', 2 );
  112. } ).to.throw( CKEditorError, /^model-set-cannot-override/ );
  113. expect( car ).to.have.property( 'normalProperty', 1 );
  114. } );
  115. it( 'should throw when overriding already existing property (in the prototype)', () => {
  116. const CKEditorError = modules.ckeditorerror;
  117. const Model = modules.model;
  118. class Car extends Model {
  119. method() {}
  120. }
  121. car = new Car();
  122. expect( () => {
  123. car.set( 'method', 2 );
  124. } ).to.throw( CKEditorError, /^model-set-cannot-override/ );
  125. expect( car.method ).to.be.a( 'function' );
  126. } );
  127. } );
  128. describe( 'extend', () => {
  129. it( 'should create new Model based classes', () => {
  130. const Model = modules.model;
  131. class Truck extends Car {}
  132. let truck = new Truck();
  133. expect( truck ).to.be.an.instanceof( Car );
  134. expect( truck ).to.be.an.instanceof( Model );
  135. } );
  136. } );
  137. } );