effects_test.html 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  2. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  3. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  4. <head>
  5. <title>script.aculo.us Unit test file</title>
  6. <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  7. <script src="../../lib/prototype.js" type="text/javascript"></script>
  8. <script src="../../src/scriptaculous.js" type="text/javascript"></script>
  9. <script src="../../src/unittest.js" type="text/javascript"></script>
  10. <link rel="stylesheet" href="../test.css" type="text/css" />
  11. <style type="text/css" media="screen">
  12. #rotfl {
  13. color: red;
  14. font-family: serif;
  15. font-style: italic;
  16. font-size: 40px;
  17. background: #fed;
  18. padding: 1em;
  19. width: 400px;
  20. }
  21. .final {
  22. color: #fff;
  23. font-style: italic;
  24. background: #000;
  25. opacity: 0.5;
  26. }
  27. body div.final {
  28. font-size: 20px;
  29. }
  30. </style>
  31. </head>
  32. <body>
  33. <h1>script.aculo.us Unit test file</h1>
  34. <p>
  35. Tests for effects.js
  36. </p>
  37. <!-- generated elements go in here -->
  38. <div id="sandbox"></div>
  39. <!-- Log output -->
  40. <div id="testlog"> </div>
  41. <div class="morphing blub" style="font-size:25px;color:#f00">Well</div>
  42. <div class="morphing">You know</div>
  43. <div id="blah" style="border:1px solid black;width:100px">Whoo-hoo!</div>
  44. <div id="error_message">ERROR MESSAGE</div>
  45. <div id="error_message_2">SECOND ERROR MESSAGE</div>
  46. <div id="error_message_3" style="border:1px solid red; width:100px; color: #f00">THIRD ERROR MESSAGE</div>
  47. <ul class="error-list" id="error_test_ul">
  48. <li>Lorem ipsum dolor sit amet, consectetur adipisicing elit,</li>
  49. <li>sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</li>
  50. <li>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris</li>
  51. <li>nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in</li>
  52. <li>reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</li>
  53. </ul>
  54. <div id="rotfl">ROTFL</div>
  55. <div id="tween">foo!</div>
  56. <!-- Tests follow -->
  57. <script type="text/javascript" language="javascript" charset="utf-8">
  58. // <![CDATA[
  59. var TAGS =
  60. ['div','span','ol','ul','table','p','h1','h2','h3','h4','h5','h6'];
  61. var COMBINED_EFFECTS =
  62. ['Fade','Appear','BlindUp','BlindDown','Puff','SwitchOff','DropOut','Shake',
  63. 'SlideUp','SlideDown','Pulsate','Squish','Fold','Grow','Shrink'];
  64. var COMBINED_RJS_EFFECTS = $w('fade appear blind_up blind_down puff switch_off '+
  65. 'drop_out shake slide_up slide_down pulsate squish fold grow shrink');
  66. var tmp, tmp2;
  67. new Test.Unit.Runner({
  68. setup: function() { with (this) {
  69. $('sandbox').innerHTML = "";
  70. }},
  71. teardown: function() { with(this) {
  72. // remove all queued effects
  73. Effect.Queue.each(function(e) { e.cancel() });
  74. }},
  75. testExceptionOnNonExistingElement: function() { with(this) {
  76. assertRaise('ElementDoesNotExistError',
  77. function(){new Effect.Opacity('nothing-to-see-here')});
  78. assertRaise('ElementDoesNotExistError',
  79. function(){new Effect.Move('nothing-to-see-here')});
  80. assertRaise('ElementDoesNotExistError',
  81. function(){new Effect.Scale('nothing-to-see-here')});
  82. assertRaise('ElementDoesNotExistError',
  83. function(){new Effect.Highlight('nothing-to-see-here')});
  84. }},
  85. testCallbacks: function() { with(this) {
  86. tmp = tmp2 = 0;
  87. var e1 = new Effect.Opacity('sandbox',{from:1.0,to:0.5,duration:0.5,
  88. beforeStart: function() { tmp++ },
  89. beforeStartInternal: function() { tmp++ },
  90. beforeSetup: function() { tmp++ },
  91. beforeSetupInternal: function() { tmp++ },
  92. afterSetup: function() { tmp++ },
  93. afterSetupInternal: function() { tmp++ },
  94. beforeUpdate: function() { tmp2++ },
  95. beforeUpdateInternal: function() { tmp2++ },
  96. beforeFinish: function() { tmp++ },
  97. beforeFinishInternal: function() { tmp++ },
  98. afterFinish: function() { tmp++ },
  99. afterFinishInternal: function() { tmp++ }
  100. });
  101. wait(1000, function() {
  102. assertEqual(10, tmp);
  103. assert(tmp2 > 0);
  104. });
  105. }},
  106. testEvent: function() { with(this) {
  107. tmp = 0;
  108. new Effect.Event({ afterFinish:function(){ tmp++ }, position:'end'});
  109. wait(100, function() {
  110. assertEqual(1, tmp);
  111. });
  112. }},
  113. testTransition: function() { with(this) {
  114. // false implies linear
  115. var e = new Effect.Opacity('sandbox',{transition:false,from:0.0,to:0.25,duration:0.5});
  116. assert(e.options.transition == Effect.Transitions.linear);
  117. wait(1000, function() {
  118. assertEqual(0.25, $('sandbox').getStyle('opacity'));
  119. // default to sinoidal
  120. var e = new Effect.Opacity('sandbox',{from:0.0,to:0.25,duration:0.5});
  121. assert(e.options.transition == Effect.Transitions.sinoidal);
  122. wait(1000, function() {
  123. assertEqual(0.25, $('sandbox').getStyle('opacity'));
  124. var transitions = [
  125. { transition: Effect.Transitions.linear, expected: 1 },
  126. { transition: Effect.Transitions.sinoidal, expected: 1 },
  127. { transition: Effect.Transitions.reverse, expected: 0 },
  128. { transition: Effect.Transitions.flicker, expected: 1 },
  129. { transition: Effect.Transitions.wobble, expected: 1 },
  130. { transition: Effect.Transitions.pulse, expected: 1 },
  131. { transition: Effect.Transitions.none, expected: 0 }
  132. ];
  133. transitions.each(function(t){
  134. var e = new Effect.Opacity('sandbox',{sync:true, from:0, to: 1, transition:t.transition});
  135. assert(e.options.transition == t.transition);
  136. e.render(1.0);
  137. assertEqual(t.expected, e.position, t.transition);
  138. });
  139. });
  140. });
  141. }},
  142. testInspect: function() { with(this) {
  143. var e1 = new Effect.Opacity('sandbox',{from:1.0,to:0.5,duration:0.5});
  144. info( e1.inspect() );
  145. assertEqual(0, e1.inspect().indexOf('#<Effect:'));
  146. assert(e1.inspect().indexOf('idle')>0);
  147. wait(1000, function() {
  148. assert(e1.inspect().indexOf('finished')>0);
  149. });
  150. }},
  151. testDefaultOptions: function() { with(this) {
  152. var oldDefaultOptions = Object.extend({},Effect.DefaultOptions);
  153. assertEqual(1.0, Effect.DefaultOptions.duration);
  154. Effect.DefaultOptions.duration = 0.5;
  155. var e1 = new Effect.Opacity('sandbox');
  156. assertEqual(0.5, e1.options.duration);
  157. wait(750, function() {
  158. assertEqual('finished', e1.state);
  159. Effect.DefaultOptions = oldDefaultOptions;
  160. });
  161. }},
  162. testEffectsQueue: function() { with(this) {
  163. var e1 = new Effect.Highlight('sandbox');
  164. var e2 = new Effect.Appear('sandbox');
  165. assertEqual(2, Effect.Queue.effects.length);
  166. tmp = 0;
  167. Effect.Queue.each(function(e) { tmp++ });
  168. assertEqual(2, tmp);
  169. // the internal interval timer should be active
  170. assertNotNull(Effect.Queue.interval);
  171. e1.cancel();
  172. e2.cancel();
  173. assertEqual(0, Effect.Queue.effects.length);
  174. // should be inactive after all effects are removed from queue
  175. assertNull(Effect.Queue.interval);
  176. // should be in e3,e1,e2 order
  177. var e1 = new Effect.Highlight('sandbox');
  178. var e2 = new Effect.Appear('sandbox',{queue:'end'});
  179. var e3 = new Effect.Fade('sandbox',{queue:'front'});
  180. assert(e2.startOn > e1.startOn);
  181. assert(e3.startOn < e1.startOn);
  182. assert(e3.startOn < e2.startOn);
  183. assertEqual(3, Effect.Queue.effects.length);
  184. Effect.Queue.each(function(e) { e.cancel() });
  185. assertEqual(0, Effect.Queue.effects.length);
  186. }},
  187. testScopedEffectsQueue: function() { with(this) {
  188. var e1 = new Effect.Highlight('sandbox', {queue: {scope:'myscope'} } );
  189. var e2 = new Effect.Appear('sandbox', {queue: {scope:'myscope'} } );
  190. var e3 = new Effect.Highlight('sandbox', {queue: {scope:'secondscope'} } );
  191. var e4 = new Effect.Appear('sandbox');
  192. assertEqual(2, Effect.Queues.get('myscope').effects.length);
  193. assertEqual(1, Effect.Queues.get('secondscope').effects.length);
  194. assertEqual(1, Effect.Queues.get('global').effects.length);
  195. assertEqual(Effect.Queue.effects.length, Effect.Queues.get('global').effects.length);
  196. var tmp = 0;
  197. Effect.Queues.get('myscope').effects.each(function(e) { tmp++ });
  198. assertEqual(2, tmp);
  199. // the internal interval timer should be active
  200. assertNotNull(Effect.Queues.get('myscope').interval);
  201. assertNotNull(Effect.Queues.get('secondscope').interval);
  202. assertNotNull(Effect.Queues.get('global').interval);
  203. e1.cancel(); e2.cancel(); e3.cancel(); e4.cancel();
  204. assertEqual(0, Effect.Queues.get('myscope').effects.length);
  205. assertEqual(0, Effect.Queues.get('secondscope').effects.length);
  206. assertEqual(0, Effect.Queues.get('global').effects.length);
  207. // should be inactive after all effects are removed from queues
  208. assertNull(Effect.Queues.get('myscope').interval);
  209. assertNull(Effect.Queues.get('secondscope').interval);
  210. assertNull(Effect.Queues.get('global').interval);
  211. // should be in e3 and e4 together and then e1,e2 order
  212. var e1 = new Effect.Highlight('sandbox', {queue: {scope:'myscope'} } );
  213. var e2 = new Effect.Appear('sandbox', {queue: {position: 'end', scope:'myscope'} } );
  214. var e3 = new Effect.Fade('sandbox', {queue: {position: 'front', scope:'myscope'} } );
  215. var e4 = new Effect.Appear('sandbox');
  216. assert(e2.startOn > e1.startOn);
  217. assert(e3.startOn < e1.startOn);
  218. assert(e3.startOn < e2.startOn);
  219. assert(e3.startOn = e4.startOn);
  220. assertEqual(3, Effect.Queues.get('myscope').effects.length);
  221. Effect.Queues.get('myscope').each(function(e) { e.cancel() });
  222. assertEqual(0, Effect.Queues.get('myscope').effects.length);
  223. Effect.Queues.get('global').each(function(e) { e.cancel() });
  224. assertEqual(0, Effect.Queues.get('global').effects.length);
  225. // should only allow the first two effects and ignore the third
  226. var e1 = new Effect.Highlight('sandbox', {queue: {scope:'myscope', limit: 2} } );
  227. var e2 = new Effect.Appear('sandbox', {queue: {position: 'end', scope:'myscope', limit: 2} } );
  228. var e3 = new Effect.Fade('sandbox', {queue: {position: 'front', scope:'myscope', limit: 2} } );
  229. assertEqual(2, Effect.Queues.get('myscope').effects.length);
  230. }},
  231. testEffectMultiple: function() { with(this) {
  232. $('sandbox').appendChild(Builder.node('div',{id:'test_1'}));
  233. $('sandbox').appendChild(Builder.node('div',{id:'test_2'},[Builder.node('div',{id:'test_2a'})]));
  234. $('sandbox').appendChild(Builder.node('div',{id:'test_3'}));
  235. // only direct child elements
  236. Effect.multiple('sandbox',Effect.Fade);
  237. assertEqual(3, Effect.Queue.effects.length);
  238. Effect.Queue.each(function(e) { e.cancel() });
  239. assertEqual(0, Effect.Queue.effects.length);
  240. // call with array
  241. Effect.multiple(['test_1','test_3'],Effect.Puff);
  242. assertEqual(2, Effect.Queue.effects.length);
  243. }},
  244. testEffectTagifyText: function() { with(this) {
  245. $('sandbox').innerHTML = "Blah<strong>bleb</strong> Blub";
  246. assertEqual(3, $('sandbox').childNodes.length);
  247. Effect.tagifyText('sandbox');
  248. assertEqual(10, $('sandbox').childNodes.length);
  249. Effect.multiple('sandbox', Effect.Fade);
  250. assertEqual(10, Effect.Queue.effects.length);
  251. }},
  252. testEffectParallel: function() { with(this) {
  253. assert( new Effect.Parallel() );
  254. assert( new Effect.Parallel([]) );
  255. assert( new Effect.Parallel([],{}) );
  256. assert( new Effect.Parallel([
  257. new Effect.Event({sync:true})
  258. ],{ duration: 2}) );
  259. }},
  260. testEffectTween: function() { with(this) {
  261. // basic initialization
  262. assert(new Effect.Tween(null,0,0,function(){}));
  263. assert(new Effect.Tween(null,0,0,{duration:0.1},function(){}));
  264. // fun with objects
  265. var object = {
  266. blech: 2,
  267. foo: function(p){
  268. this.bar = p;
  269. }
  270. };
  271. assert(new Effect.Tween(object,0,1,{transition:Effect.Transitions.reverse},'blech'));
  272. assert(new Effect.Tween(object,0,1,'foo'));
  273. // fun with elements
  274. assert(new Effect.Tween('tween',50,1,'update'));
  275. wait(1500, function(){
  276. assertEqual(0, object.blech);
  277. assertEqual(1, object.bar);
  278. assertEqual('1', $('tween').innerHTML);
  279. });
  280. }},
  281. // test if all combined effects correctly initialize themselves
  282. testCombinedEffectsInitialize: function() { with(this) {
  283. COMBINED_EFFECTS.each(function(fx,idx){
  284. info('Effect.'+fx);
  285. $('sandbox').innerHTML = "";
  286. $('sandbox').appendChild(
  287. Builder.node('div',{id:'test_element'},
  288. Builder.node('span','test'))); //some effects require a child element
  289. // should work with new Effect.Blah syntax
  290. var effect = new Effect[fx]('test_element');
  291. assertEqual(0, effect.currentFrame);
  292. // and without the 'new'
  293. var effect = Effect[fx]('test_element');
  294. assertEqual(0, effect.currentFrame);
  295. // visualEffect
  296. assert($('test_element') == $('test_element').visualEffect(COMBINED_RJS_EFFECTS[idx]));
  297. // direct element extension
  298. var method = COMBINED_EFFECTS[idx].charAt(0).toLowerCase() + COMBINED_EFFECTS[idx].substring(1)
  299. assert($('test_element') == $('test_element')[method]());
  300. // options parsing (shake, squish and grow are special here)
  301. if(!['Shake','Squish','Grow'].include(fx)) {
  302. var effect = Effect[fx]('test_element',{duration:2.0});
  303. assertEqual(2.0, effect.options.duration, fx);
  304. }
  305. });
  306. }},
  307. testSynchronizedEffects: function() { with(this) {
  308. var e1 = new Effect.Fade('sandbox',{sync:true});
  309. wait(250, function() {
  310. // effect should still be at frame 0
  311. assertEqual(0, e1.currentFrame);
  312. assertEqual('idle', e1.state);
  313. e1.render(0.01);
  314. // no frame count for sync effects
  315. assertEqual(0, e1.currentFrame);
  316. assertEqual('running', e1.state);
  317. });
  318. }},
  319. testEffectPosition: function() { with(this) {
  320. var testeffect = new Effect.Opacity('sandbox',{
  321. afterSetup: function(effect) { effect.frames = 0; },
  322. afterUpdate: function(effect) { effect.frames++; $('sandbox').update(effect.position); },
  323. duration: 0.5, from: 1.0, to: 0.5
  324. });
  325. assertNull(testeffect.position);
  326. assertEqual('idle', testeffect.state);
  327. wait(1000, function() {
  328. info('Rendered ' + testeffect.frames + ' frames in .5 seconds ' +
  329. '(~' + (testeffect.frames/0.5) + 'fps of a possible 60fps, ' +
  330. 'note that this can exceed 60fps because of additional last frame rendering)');
  331. assertEqual('0.5', $('sandbox').innerHTML);
  332. assertEqual(0.5, testeffect.position);
  333. assertEqual('finished', testeffect.state);
  334. });
  335. }},
  336. testRenderPerformance: function() { with(this) {
  337. info('The render() method is generated on a per-effect basis')
  338. var e = new Effect.Opacity('sandbox',{sync:true});
  339. benchmark(function(){
  340. e.render(0.5);
  341. },1000, 'Without events');
  342. var e = new Effect.Opacity('sandbox',{sync:true,afterUpdate:function(){return}});
  343. benchmark(function(){
  344. e.render(0.5);
  345. },1000, 'With afterUpdate event');
  346. }},
  347. testElementMorph: function() { with(this) {
  348. $('error_test_ul').morph('font-size:40px', {duration: 0.5}).setStyle({marginRight:'17px'});
  349. $('error_message_2').morph({
  350. fontSize: '20px',
  351. color: '#f00',
  352. backgroundColor: '#ffffff'
  353. },
  354. {
  355. duration:0.5
  356. });
  357. $('error_message_3').morph('final', {duration:0.5});
  358. wait(1000,function(){
  359. assertEqual('17px', $('error_test_ul').getStyle('margin-right'));
  360. assertEqual('40px', $('error_test_ul').getStyle('font-size'));
  361. assertEqual('#ffffff', $('error_message_2').getStyle('background-color').parseColor());
  362. assertEqual('20px', $('error_message_2').getStyle('font-size'));
  363. assertEqual('italic', $('error_message_3').getStyle('font-style'));
  364. assertEqual('20px', $('error_message_3').getStyle('font-size'));
  365. assertEqual(.5, $('error_message_3').getStyle('opacity'));
  366. assertEqual('', $('error_message_3').style.fontSize);
  367. });
  368. }},
  369. testElementMorphChaining: function() { with(this) {
  370. $('error_message').morph('font-size:17px').morph('opacity:0',{delay:2});
  371. wait(3100,function(){ // 2000ms delay + 1000ms default duration
  372. assertEqual(0, $('error_message').getStyle('opacity'));
  373. });
  374. }},
  375. testTransformBySelector: function() { with(this) {
  376. new Effect.Transform([
  377. { 'ul.error-list li': 'font-size:20px;text-indent:40pt' }
  378. ],{ duration: 0.5 }).play();
  379. wait(700,function(){
  380. var idx = 0;
  381. $A($('error_test_ul').cleanWhitespace().childNodes).each(function(node){
  382. assertEqual('20px', $(node).getStyle('font-size'));
  383. assertEqual('40pt', $(node).getStyle('text-indent'));
  384. idx++;
  385. });
  386. assertEqual(5, idx);
  387. });
  388. }},
  389. testTransformUsesCSSClassPresets: function() { with(this) {
  390. assertEqual('40px', $('rotfl').getStyle('font-size'));
  391. // Render the effect at half-way through, font-size should be
  392. // exactly half-way between original and target
  393. new Effect.Transform([
  394. { 'rotfl': 'font-size:20px;text-indent:40pt;background-color:#888' }
  395. ],{ sync:true }).play().render(0.5);
  396. wait(1100,function(){
  397. // should be 30px = 40px + (20px-40px)/2
  398. assertEqual('30px', $('rotfl').getStyle('font-size'));
  399. });
  400. }},
  401. testTransformMultiple: function() { with(this) {
  402. var transformation = new Effect.Transform([
  403. { 'div.morphing': 'font-size:20px;padding-left:40em;opacity:0.5' },
  404. { 'blah' :
  405. 'width:480px;border-width:10px;border-right-width:20px;' +
  406. 'margin:20px;margin-bottom:-20px;font-size:30px;' +
  407. 'background:#954' }
  408. ],{ duration: 0.5 });
  409. var generatedEffect = transformation.play();
  410. assertEqual(3, generatedEffect.effects.length);
  411. wait(700, function(){
  412. // have a look at the generated color transforms for the 3rd found element
  413. // which is the "blah" div
  414. assertEqual('blah', generatedEffect.effects[2].element.id);
  415. assertEnumEqual([255,255,255],
  416. generatedEffect.effects[2].transforms.detect( function(transform){
  417. return (transform.style == 'backgroundColor')
  418. }).originalValue);
  419. assertEnumEqual([153,85,68],
  420. generatedEffect.effects[2].transforms.detect( function(transform){
  421. return (transform.style == 'backgroundColor')
  422. }).targetValue);
  423. assertEqual('20px', $$('div.morphing').first().getStyle('font-size'));
  424. assertEqual('20px', $$('div.morphing').last().getStyle('font-size'));
  425. assertEqual('30px', $('blah').getStyle('font-size'));
  426. // border-width/border-right-width should be set independently
  427. assertEqual('10px', $('blah').getStyle('border-top-width'));
  428. assertEqual('10px', $('blah').getStyle('border-bottom-width'));
  429. assertEqual('10px', $('blah').getStyle('border-left-width'));
  430. assertEqual('20px', $('blah').getStyle('border-right-width'));
  431. // colors should assume transition from
  432. // #ffffff (white) if original was transparent
  433. // we now should have arrived at the given color
  434. assertEqual('#995544', $('blah').getStyle('background-color').parseColor());
  435. // play again = should have same values
  436. transformation.play();
  437. wait(700, function(){
  438. assertEqual('20px', $$('div.morphing').first().getStyle('font-size'));
  439. assertEqual('20px', $$('div.morphing').last().getStyle('font-size'));
  440. assertEqual('30px', $('blah').getStyle('font-size'));
  441. $('blah').setStyle({fontSize:'100px'});
  442. assertEqual('100px', $('blah').getStyle('font-size'));
  443. transformation.play();
  444. wait(700, function(){
  445. assertEqual('30px', $('blah').getStyle('font-size'));
  446. new Effect.Transform([
  447. { 'blah': 'color: #80d980; background: #208020' }
  448. ],{ duration: 1.1 }).play();
  449. wait(1500, function(){
  450. assertEqual('#80d980', $('blah').getStyle('color').parseColor());
  451. assertEqual('#208020', $('blah').getStyle('background-color').parseColor());
  452. });
  453. });
  454. });
  455. });
  456. }}
  457. });
  458. // ]]>
  459. </script>
  460. </body>
  461. </html>