UNPKG

ractive

Version:

Next-generation DOM manipulation

482 lines (362 loc) 12.1 kB
// EVENT TESTS // =========== // // TODO: add moar tests define([ 'ractive' ], function ( Ractive ) { return function () { var fixture = document.getElementById( 'qunit-fixture' ); module( 'Events' ); test( 'on-click="someEvent" fires an event when user clicks the element', function ( t ) { var ractive; expect( 2 ); ractive = new Ractive({ el: fixture, template: '<span id="test" on-click="someEvent">click me</span>' }); ractive.on( 'someEvent', function ( event ) { t.ok( true ); t.equal( event.original.type, 'click' ); }); simulant.fire( ractive.nodes.test, 'click' ); }); test( 'Standard events have correct properties: node, original, keypath, context, index', function ( t ) { var ractive, fakeEvent; expect( 5 ); ractive = new Ractive({ el: fixture, template: '<span id="test" on-click="someEvent">click me</span>' }); ractive.on( 'someEvent', function ( event ) { t.equal( event.node, ractive.nodes.test ); t.ok( event.original ); t.equal( event.keypath, '' ); t.equal( event.context, ractive.data ); t.equal( event.index, undefined ); }); fakeEvent = simulant( 'click' ); simulant.fire( ractive.nodes.test, fakeEvent ); }); test( 'event.keypath is set to the innermost context', function ( t ) { var ractive; expect( 2 ); ractive = new Ractive({ el: fixture, template: '{{#foo}}<span id="test" on-click="someEvent">click me</span>{{/foo}}', data: { foo: { bar: 'test' } } }); ractive.on( 'someEvent', function ( event ) { t.equal( event.keypath, 'foo' ); t.equal( event.context.bar, 'test' ); }); simulant.fire( ractive.nodes.test, 'click' ); }); test( 'event.index stores current indices against their references', function ( t ) { var ractive; expect( 4 ); ractive = new Ractive({ el: fixture, template: '<ul>{{#array:i}}<li id="item_{{i}}" on-click="someEvent">{{i}}: {{.}}</li>{{/array}}</ul>', data: { array: [ 'a', 'b', 'c', 'd', 'e' ] } }); ractive.on( 'someEvent', function ( event ) { t.equal( event.node.innerHTML, '2: c' ); t.equal( event.keypath, 'array.2' ); t.equal( event.context, 'c' ); t.deepEqual( event.index, { i: 2 }) }); simulant.fire( ractive.nodes.item_2, 'click' ); }); test( 'event.index reports nested indices correctly', function ( t ) { var ractive; expect( 2 ); ractive = new Ractive({ el: fixture, template: '{{#foo:x}}{{#bar:y}}{{#baz:z}}<span id="test_{{x}}{{y}}{{z}}" on-click="someEvent">{{x}}{{y}}{{z}}</span>{{/baz}}{{/bar}}{{/foo}}', data: { foo: [ { bar: [ { baz: [ 1, 2, 3 ] } ] } ] } }); t.equal( ractive.nodes.test_001.innerHTML, '001' ); ractive.on( 'someEvent', function ( event ) { t.deepEqual( event.index, { x: 0, y: 0, z: 1 }) }); simulant.fire( ractive.nodes.test_001, 'click' ); }); test( 'proxy events can have dynamic names', function ( t ) { var ractive, last; expect( 2 ); ractive = new Ractive({ el: fixture, template: '<span id="test" on-click="do_{{something}}">click me</span>', data: { something: 'foo' } }); ractive.on({ do_foo: function ( event ) { last = 'foo'; }, do_bar: function ( event ) { last = 'bar'; } }); simulant.fire( ractive.nodes.test, 'click' ); t.equal( last, 'foo' ); ractive.set( 'something', 'bar' ); simulant.fire( ractive.nodes.test, 'click' ); t.equal( last, 'bar' ); }); test( 'proxy event parameters are correctly parsed as JSON, or treated as a string', function ( t ) { var ractive, last; expect( 3 ); ractive = new Ractive({ el: fixture, template: '<span id="foo" on-click="log:one">click me</span><span id="bar" on-click=\'log:{"bar":true}\'>click me</span><span id="baz" on-click="log:[1,2,3]">click me</span>' }); ractive.on({ log: function ( event, params ) { last = params; } }); simulant.fire( ractive.nodes.foo, 'click' ); t.equal( last, 'one' ); simulant.fire( ractive.nodes.bar, 'click' ); t.deepEqual( last, { bar: true } ); simulant.fire( ractive.nodes.baz, 'click' ); t.deepEqual( last, [ 1, 2, 3 ] ); }); test( 'proxy events can have dynamic arguments', function ( t ) { var ractive; ractive = new Ractive({ el: fixture, template: '<span id="foo" on-click="foo:{{foo}}">click me</span>', data: { foo: 'bar' } }); expect( 1 ); ractive.on({ foo: function ( event, foo ) { t.equal( foo, 'bar' ); } }); simulant.fire( ractive.nodes.foo, 'click' ); }); test( 'proxy events can have multiple arguments', function ( t ) { var ractive; ractive = new Ractive({ el: fixture, template: '<span id="foo" on-click="one:1,2,3">click me</span><span id="bar" on-click="two:{a:1},{b:2}">click me</span><span id="baz" on-click="three:{c:{{c}}},{d:\'{{d}}\'}">click me</span>', data: { c: 3, d: 'four' } }); expect( 7 ); ractive.on({ one: function ( event, one, two, three ) { t.equal( one, 1 ); t.equal( two, 2 ); t.equal( three, 3 ); }, two: function ( event, one, two ) { t.equal( one.a, 1 ); t.equal( two.b, 2 ); }, three: function ( event, three, four ) { t.equal( three.c, 3 ); t.equal( four.d, 'four' ); } }); simulant.fire( ractive.nodes.foo, 'click' ); simulant.fire( ractive.nodes.bar, 'click' ); simulant.fire( ractive.nodes.baz, 'click' ); }); test( 'Splicing arrays correctly modifies proxy events', function ( t ) { var ractive; expect( 4 ); ractive = new Ractive({ el: fixture, template: '{{#buttons:i}}<button id="button_{{i}}" on-click="remove:{{i}}">click me</button>{{/buttons}}', data: { buttons: new Array(5) } }); ractive.on( 'remove', function ( event, num ) { this.get( 'buttons' ).splice( num, 1 ); }); t.equal( ractive.findAll( 'button' ).length, 5 ); simulant.fire( ractive.nodes.button_2, 'click' ); t.equal( ractive.findAll( 'button' ).length, 4 ); simulant.fire( ractive.nodes.button_2, 'click' ); t.equal( ractive.findAll( 'button' ).length, 3 ); simulant.fire( ractive.nodes.button_2, 'click' ); t.equal( ractive.findAll( 'button' ).length, 2 ); }); test( 'Splicing arrays correctly modifies two-way bindings', function ( t ) { var ractive, items; expect( 25 ); items = [ { description: 'one' }, { description: 'two', done: true }, { description: 'three' } ]; ractive = new Ractive({ el: fixture, template: '<ul>{{#items:i}}<li><input id="input_{{i}}" type="checkbox" checked="{{.done}}"> {{description}}</li>{{/items}}</ul>', data: { items: items } }); // 1-3 t.equal( ractive.nodes.input_0.checked, false ); t.equal( ractive.nodes.input_1.checked, true ); t.equal( ractive.nodes.input_2.checked, false ); // 4-6 t.equal( !!ractive.get( 'items.0.done' ), false ); t.equal( !!ractive.get( 'items.1.done' ), true ); t.equal( !!ractive.get( 'items.2.done' ), false ); simulant.fire( ractive.nodes.input_0, 'click' ); // 7-9 t.equal( ractive.nodes.input_0.checked, true ); t.equal( ractive.nodes.input_1.checked, true ); t.equal( ractive.nodes.input_2.checked, false ); // 10-12 t.equal( !!ractive.get( 'items.0.done' ), true ); t.equal( !!ractive.get( 'items.1.done' ), true ); t.equal( !!ractive.get( 'items.2.done' ), false ); items.shift(); // 13-14 t.equal( ractive.nodes.input_0.checked, true ); t.equal( ractive.nodes.input_1.checked, false ); // 15-16 t.equal( !!ractive.get( 'items.0.done' ), true ); t.equal( !!ractive.get( 'items.1.done' ), false ); simulant.fire( ractive.nodes.input_0, 'click' ); // 17-18 t.equal( ractive.nodes.input_0.checked, false ); t.equal( ractive.nodes.input_1.checked, false ); // 19-20 t.equal( !!ractive.get( 'items.0.done' ), false ); t.equal( !!ractive.get( 'items.1.done' ), false ); simulant.fire( ractive.nodes.input_1, 'click' ); // 21-22 t.equal( ractive.nodes.input_0.checked, false ); t.equal( ractive.nodes.input_1.checked, true ); // 23-24 t.equal( !!ractive.get( 'items.0.done' ), false ); t.equal( !!ractive.get( 'items.1.done' ), true ); // 25 t.equal( ractive.findAll( 'input' ).length, 2 ); }); test( 'Calling ractive.off() without a keypath removes all handlers', function ( t ) { var ractive = new Ractive({ el: fixture, template: 'doesn\'t matter' }); expect( 0 ); ractive.on({ foo: function () { t.ok( false ); }, bar: function () { t.ok( false ); }, baz: function () { t.ok( false ); } }); ractive.off(); ractive.fire( 'foo' ); ractive.fire( 'bar' ); ractive.fire( 'baz' ); }); test( 'Changes triggered by two-way bindings propagate properly (#460)', function ( t ) { var changes, ractive = new Ractive({ el: fixture, template: '{{#items}}<label><input type="checkbox" checked="{{completed}}"> {{description}}</label>{{/items}}<p class="result">{{ items.filter( completed ).length }}</p>{{# items.filter( completed ).length }}<p class="conditional">foo</p>{{/ items.filter( completed ).length }}', data: { items: [ { completed: true, description: 'fix this bug' }, { completed: false, description: 'fix other bugs' }, { completed: false, description: 'housework' } ], completed: function ( item ) { return !!item.completed; } } }); ractive.on( 'change', function ( c ) { changes = c; }); t.htmlEqual( ractive.find( '.result' ).innerHTML, '1' ); simulant.fire( ractive.findAll( 'input' )[1], 'click' ); t.htmlEqual( ractive.find( '.result' ).innerHTML, '2' ); t.equal( changes[ 'items.1.completed' ], true ); simulant.fire( ractive.findAll( 'input' )[0], 'click' ); simulant.fire( ractive.findAll( 'input' )[1], 'click' ); t.htmlEqual( ractive.find( '.result' ).innerHTML, '0' ); }); test( 'Multiple events can share the same directive', function ( t ) { var ractive, count = 0; ractive = new Ractive({ el: fixture, template: '<div on-click-mouseover="foo"></div>' }); ractive.on( 'foo', function () { count += 1; }); simulant.fire( ractive.find( 'div' ), 'click' ); t.equal( count, 1 ); simulant.fire( ractive.find( 'div' ), 'mouseover' ); t.equal( count, 2 ); }); test( 'Superfluous whitespace is ignored', function ( t ) { var ractive, fooCount = 0, barCount = 0; ractive = new Ractive({ el: fixture, template: '<div class="one" on-click=" foo "></div><div class="two" on-click="{{#bar}} bar {{/}}"></div>' }); ractive.on({ foo: function () { fooCount += 1; }, bar: function () { barCount += 1; } }); simulant.fire( ractive.find( '.one' ), 'click' ); t.equal( fooCount, 1 ); simulant.fire( ractive.find( '.two' ), 'click' ); t.equal( barCount, 0 ); ractive.set( 'bar', true ); simulant.fire( ractive.find( '.two' ), 'click' ); t.equal( barCount, 1 ); }); test( 'Multiple space-separated events can be handled with a single callback (#731)', function ( t ) { var ractive, count = 0; ractive = new Ractive({}); ractive.on( ' foo bar baz', () => count += 1 ); ractive.fire( 'foo' ); t.equal( count, 1 ); ractive.fire( 'bar' ); t.equal( count, 2 ); ractive.fire( 'baz' ); t.equal( count, 3 ); ractive.off( ' bar foo ' ); ractive.fire( 'foo' ); t.equal( count, 3 ); ractive.fire( 'bar' ); t.equal( count, 3 ); ractive.fire( 'baz' ); t.equal( count, 4 ); }); test( 'ractive.off() is chainable (#677)', t => { var ractive, returnedValue; ractive = new Ractive(); returnedValue = ractive.off('foo'); t.equal( returnedValue, ractive ); }); }; });