mix.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /**
  2. * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. 'use strict';
  6. import mix from '/ckeditor5/utils/mix.js';
  7. describe( 'utils', () => {
  8. describe( 'mix', () => {
  9. const MixinA = {
  10. a() {
  11. return 'a';
  12. }
  13. };
  14. const MixinB = {
  15. b() {
  16. return 'b';
  17. }
  18. };
  19. it( 'mixes 2nd+ argument\'s properties into the first class', () => {
  20. class Foo {}
  21. mix( Foo, MixinA, MixinB );
  22. expect( Foo ).to.not.have.property( 'a' );
  23. expect( Foo ).to.not.have.property( 'b' );
  24. const foo = new Foo();
  25. expect( foo.a() ).to.equal( 'a' );
  26. expect( foo.b() ).to.equal( 'b' );
  27. } );
  28. it( 'does not break the instanceof operator', () => {
  29. class Foo {}
  30. mix( Foo, MixinA );
  31. let foo = new Foo();
  32. expect( foo ).to.be.instanceof( Foo );
  33. } );
  34. it( 'defines properties with the same descriptors as native classes', () => {
  35. class Foo {
  36. foo() {}
  37. }
  38. mix( Foo, MixinA );
  39. const actualDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, 'a' );
  40. const expectedDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, 'foo' );
  41. expect( actualDescriptor ).to.have.property( 'writable', expectedDescriptor.writable );
  42. expect( actualDescriptor ).to.have.property( 'enumerable', expectedDescriptor.enumerable );
  43. expect( actualDescriptor ).to.have.property( 'configurable', expectedDescriptor.configurable );
  44. } );
  45. it( 'copies setters and getters (with descriptors as of native classes)', () => {
  46. class Foo {
  47. set foo( v ) {
  48. this._foo = v;
  49. }
  50. get foo() {}
  51. }
  52. const Mixin = {
  53. set a( v ) {
  54. this._a = v;
  55. },
  56. get a() {
  57. return this._a;
  58. }
  59. };
  60. mix( Foo, Mixin );
  61. const actualDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, 'a' );
  62. const expectedDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, 'foo' );
  63. expect( actualDescriptor ).to.have.property( 'enumerable', expectedDescriptor.enumerable );
  64. expect( actualDescriptor ).to.have.property( 'configurable', expectedDescriptor.configurable );
  65. const foo = new Foo();
  66. foo.a = 1;
  67. expect( foo._a ).to.equal( 1 );
  68. foo._a = 2;
  69. expect( foo.a ).to.equal( 2 );
  70. } );
  71. it( 'copies symbols (with descriptors as of native classes)', () => {
  72. const symbolA = Symbol( 'a' );
  73. const symbolFoo = Symbol( 'foo' );
  74. // https://github.com/jscs-dev/node-jscs/issues/2078
  75. // jscs:disable disallowSpacesInFunction
  76. class Foo {
  77. [ symbolFoo ]() {
  78. return 'foo';
  79. }
  80. }
  81. const Mixin = {
  82. [ symbolA ]() {
  83. return 'a';
  84. }
  85. };
  86. // jscs:enable disallowSpacesInFunction
  87. mix( Foo, Mixin );
  88. const actualDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, symbolA );
  89. const expectedDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, symbolFoo );
  90. expect( actualDescriptor ).to.have.property( 'writable', expectedDescriptor.writable );
  91. expect( actualDescriptor ).to.have.property( 'enumerable', expectedDescriptor.enumerable );
  92. expect( actualDescriptor ).to.have.property( 'configurable', expectedDescriptor.configurable );
  93. const foo = new Foo();
  94. expect( foo[ symbolA ]() ).to.equal( 'a' );
  95. } );
  96. it( 'does not copy already existing properties', () => {
  97. class Foo {
  98. a() {
  99. return 'foo';
  100. }
  101. }
  102. mix( Foo, MixinA, MixinB );
  103. const foo = new Foo();
  104. expect( foo.a() ).to.equal( 'foo' );
  105. expect( foo.b() ).to.equal( 'b' );
  106. } );
  107. it( 'does not copy already existing properties - properties deep in the proto chain', () => {
  108. class Foo {
  109. a() {
  110. return 'foo';
  111. }
  112. }
  113. class Bar extends Foo {}
  114. mix( Bar, MixinA, MixinB );
  115. const bar = new Bar();
  116. expect( bar.a() ).to.equal( 'foo' );
  117. expect( bar.b() ).to.equal( 'b' );
  118. } );
  119. } );
  120. } );