ractive
Version:
Next-generation DOM manipulation
452 lines (345 loc) • 9.55 kB
JavaScript
define([ 'ractive' ], function ( Ractive ) {
'use strict';
return function () {
var fixture = document.getElementById( 'qunit-fixture' );
module( 'ractive.observe()' );
test( 'Observers fire before the DOM updates', function ( t ) {
var ractive = new Ractive({
el: fixture,
template: '{{#foo}}{{bar}}{{/foo}}',
data: { bar: 'yeah' }
});
expect( 1 );
ractive.observe( 'foo', function ( foo ) {
t.equal( fixture.innerHTML, '' );
}, { init: false });
ractive.set( 'foo', true );
});
test( 'Observers with { defer: true } fire after the DOM updates', function ( t ) {
var ractive = new Ractive({
el: fixture,
template: '{{#foo}}{{bar}}{{/foo}}',
data: { bar: 'yeah' }
});
expect( 1 );
ractive.observe( 'foo', function ( foo ) {
t.equal( fixture.innerHTML, 'yeah' );
}, { init: false, defer: true });
ractive.set( 'foo', true );
});
test( 'Observer can be created without an options argument', function ( t ) {
var ractive = new Ractive({
el: fixture,
template: '{{foo}}',
data: { foo: 'bar' }
});
expect( 1 );
ractive.observe( 'foo', function ( foo ) {
t.equal( foo, 'bar' );
});
});
test( 'Observers fire on init when no matching data', function ( t ) {
var ractive = new Ractive({
el: fixture,
template: '{{foo}}',
data: {}
});
expect( 2 );
ractive.observe( 'foo', function ( foo, old, keypath ) {
t.ok( !foo );
t.equal( keypath, 'foo' );
});
});
test( 'Pattern observers do NOT fire on init when no matching data', function ( t ) {
var ractive = new Ractive({
el: fixture,
template: '{{foo}}',
data: {}
});
expect( 0 );
ractive.observe( '*', function () {
t.ok( true );
});
});
test( 'Uninitialised observers do not fire if their keypath is set to the same value', function ( t ) {
var ractive = new Ractive({
el: fixture,
template: '{{foo}}',
data: { foo: 'bar' }
});
expect( 0 );
ractive.observe( 'foo', function ( foo ) {
t.ok( 0 );
}, { init: false });
ractive.set( 'foo', 'bar' );
});
test( 'Pattern observers fire on changes to keypaths that match their pattern', function ( t ) {
var ractive, expected;
ractive = new Ractive({
el: fixture,
template: 'blah',
data: { foo: { bar: { baz: 1 } } }
});
expect( 4 );
expected = 1;
ractive.observe( 'foo.bar.*', function ( n, o, keypath ) {
t.equal( n, expected );
t.equal( keypath, 'foo.bar.baz' );
});
expected = 2;
ractive.set( 'foo.bar.baz', expected );
});
test( 'Pattern observers fire on changes to keypaths downstream of their pattern', function ( t ) {
var ractive, expected;
ractive = new Ractive({
el: fixture,
template: 'blah',
data: { foo: { bar: { baz: 1 } } }
});
expect( 4 );
expected = { baz: 1 };
ractive.observe( 'foo.*', function ( n, o, keypath ) {
t.deepEqual( n, expected );
t.equal( keypath, 'foo.bar' );
});
expected = { baz: 2 };
ractive.set( 'foo.bar.baz', 2 );
});
test( 'Pattern observers fire on changes to keypaths upstream of their pattern', function ( t ) {
var ractive, expected;
ractive = new Ractive({
el: fixture,
template: 'blah',
data: { foo: { bar: { baz: 1 } } }
});
expect( 4 );
expected = 1;
ractive.observe( 'foo.*.baz', function ( n, o, keypath ) {
t.deepEqual( n, expected );
t.equal( keypath, 'foo.bar.baz' );
});
expected = 2;
ractive.set( 'foo', { bar: { baz: 2 } });
});
test( 'Pattern observers can have multiple wildcards', function ( t ) {
var ractive, expected;
ractive = new Ractive({
el: fixture,
template: 'blah',
data: { foo: { bar: { baz: 1 } } }
});
expect( 4 );
expected = 1;
ractive.observe( 'foo.*.*', function ( n, o, keypath ) {
t.deepEqual( n, expected );
t.equal( keypath, 'foo.bar.baz' );
});
expected = 2;
ractive.set( 'foo.bar', { baz: 2 });
});
test( 'The first key in a pattern observer\'s pattern can be a wildcard', function ( t ) {
var ractive, expected;
ractive = new Ractive({
el: fixture,
template: 'blah',
data: { gup: { foo: { bar: { baz: 1 } } } }
});
expect( 4 );
expected = 1;
ractive.observe( 'gup.*.bar.baz', function ( n, o, keypath ) {
t.deepEqual( n, expected );
t.equal( keypath, 'gup.foo.bar.baz' );
});
expected = 2;
ractive.set( 'gup.foo.bar', { baz: 2 });
});
test( 'Observers can observe multiple keypaths, separated by a space', function ( t ) {
var ractive, results;
ractive = new Ractive({
el: fixture,
template: 'irrelevant'
});
results = {};
ractive.observe( 'foo bar baz', function ( n, o, k ) {
results[ k ] = n;
});
ractive.observe({
'a b': function ( n, o, k ) {
results[ k ] = n;
}
})
ractive.set( 'foo', 'one' );
ractive.set({
bar: 'two',
baz: 'three'
});
ractive.set( 'a', 1 );
ractive.set( 'b', 2 );
t.deepEqual( results, { foo: 'one', bar: 'two', baz: 'three', a: 1, b: 2 });
});
test( 'Pattern observers fire when ractive.update() is called without parameters', function ( t ) {
var ractive = new Ractive({
el: fixture,
template: 'whatever',
data: { items: [ 'a', 'b', 'c' ] }
});
expect( 2 );
ractive.observe( 'items.*', function ( n, o, k ) {
t.equal( k, 'items.1' );
t.equal( n, 'd' );
}, { init: false });
ractive.get( 'items' )[1] = 'd';
ractive.update();
});
test( 'Pattern observers can start with wildcards (#629)', function ( t ) {
var ractive, values;
ractive = new Ractive({
data: {
foo: { number: 0 },
bar: { number: 1 },
baz: { number: 2 }
}
});
values = {};
ractive.observe( '*.number', function ( n, o, k ) {
values[ k ] = n;
});
t.deepEqual( values, {
'foo.number': 0,
'bar.number': 1,
'baz.number': 2
});
ractive.set( 'foo.number', 3 );
t.deepEqual( values, {
'foo.number': 3,
'bar.number': 1,
'baz.number': 2
});
});
test( 'Pattern observers on arrays fire correctly after mutations', function ( t ) {
var ractive, lastKeypath, lastValue, observedLengthChange;
ractive = new Ractive({
data: {
items: [ 'a', 'b', 'c' ]
}
});
ractive.observe( 'items.*', function ( n, o, k ) {
lastKeypath = k;
lastValue = n;
if ( k === 'items.length' ) {
observedLengthChange = true;
}
}, { init: false });
ractive.get( 'items' ).push( 'd' );
t.equal( lastKeypath, 'items.3' );
t.equal( lastValue, 'd' );
ractive.get( 'items' ).pop();
t.equal( lastKeypath, 'items.3' );
t.equal( lastValue, undefined );
t.ok( !observedLengthChange );
ractive.set( 'items.length', 4 );
t.ok( observedLengthChange );
});
test( 'Pattern observers receive additional arguments corresponding to the wildcards', function ( t ) {
var ractive, lastIndex, lastA, lastB;
ractive = new Ractive({
data: {
array: [ 'a', 'b', 'c' ],
object: {
foo: {
one: 1,
two: 2
},
bar: {
three: 3,
four: 4
}
}
}
});
ractive.observe({
'array.*': function ( n, o, k, index ) {
lastIndex = index;
},
'object.*.*': function ( n, o, k, a, b ) {
lastA = a;
lastB = b;
}
}, { init: false });
ractive.get( 'array' ).push( 'd' );
t.equal( lastIndex, 3 );
ractive.set( 'object.foo.five', 5 );
t.equal( lastA, 'foo' );
t.equal( lastB, 'five' );
});
test( 'Pattern observers work with an empty array (#760)', function ( t ) {
var ractive = new Ractive({});
ractive.observe( 'foo.*.bar', function ( n, o, k ) {});
t.ok( true );
});
test( 'Pattern observers work with an property of array (#760) varient', function ( t ) {
var ractive = new Ractive({ data: { foo: [] } } ),
bar = { bar: 1 };
expect(2);
ractive.observe('foo.*.bar', function( n, o, k ) {
t.equal( n, 1 );
t.equal( k, 'foo.0.bar' );
});
ractive.get( 'foo' ).push( bar );
});
asyncTest( 'Promises from set() operations inside observers resolve (#765)', function ( t ) {
var ractive = new Ractive({
el: fixture,
template: '{{foo}}',
data: {
bar: 1
}
});
expect( 1 );
ractive.observe( 'bar', function ( bar ) {
ractive.set( 'foo', 'works' ).then( function () {
t.ok( true );
QUnit.start();
});
}, { init: false });
ractive.set( 'bar', true );
});
test( 'set() operations inside observers affect the DOM immediately (related to #765)', function ( t ) {
var ractive = new Ractive({
el: fixture,
template: '{{foo}}',
data: {
bar: 1
}
});
expect( 1 );
ractive.observe( 'bar', function ( bar ) {
ractive.set( 'foo', 'works' );
t.htmlEqual( fixture.innerHTML, 'works' );
}, { init: false });
ractive.set( 'bar', true );
});
test( 'Errors inside observers are not caught', function ( t ) {
var ractive = new Ractive({
data: {
bar: [ 1, 2, 3 ]
}
});
expect( 2 );
try {
ractive.observe( 'foo', function () {
throw new Error( 'test' );
});
} catch ( err ) {
t.equal( err.message, 'test' );
}
try {
ractive.observe( 'bar.*', function () {
throw new Error( 'test' );
});
} catch ( err ) {
t.equal( err.message, 'test' );
}
});
};
});