示例#1
0
testHelpers.dev.devOnlyTest("should warn when two routes have same map properties - including defaults", function () {
	var teardown = testHelpers.dev.willWarn(/two routes were registered with matching keys/);

	canRoute.register("foo/{page}/{subpage}");
	canRoute.register("{page}/{subpage}");

	equal(teardown(), 1);
});
示例#2
0
testHelpers.dev.devOnlyTest("should not warn when two routes have same map properties - but different defaults(#36)", function () {
	var teardown = testHelpers.dev.willWarn(/two routes were registered with matching keys/);

	canRoute.register("login", { "page": "auth", "subpage": "login" });
	canRoute.register("signup", { "page": "auth", "subpage": "signup" });

	equal(teardown(), 0);
});
示例#3
0
文件: unit.js 项目: donejs/autorender
QUnit.test("Warn if no routes", function(assert){
	var render = this.render;
	var doc = makeDoc();
	var context = makeContextForDocument(render, doc);
	var request = new Request("/");

	// because canRoute is global and we are running tests before that have a route initialized
	// we have clear the routes manually
	canRoute.routes = {};

	var teardown = canTestHelpers.dev.willWarn(/receive route definitions/);

	render.call(context, request);
	assert.equal(teardown(), 1, "Received a warning in console");
});
示例#4
0
文件: unit.js 项目: donejs/autorender
QUnit.test("Does not warn", function(assert){
	var done = assert.async();
	var teardown = canTestHelpers.dev.willWarn(/Unable to find key/);

	testHelpers.load("test/basics/index.stache!done-autorender")
	.then(function(autorender){
		var doc = makeDoc();
		var context = makeContextForDocument(autorender, doc);
		return context.connectViewModelAndAttach();
	})
	.then(function(){
		assert.equal(teardown(), 0, "No warnings for undefined keys");
	})
	.then(done, function(err){
		QUnit.ok(false, err);
		done();
	});
});
	canTestHelpers.dev.devOnlyTest("warning displayed when using @", function(){
		expect(3);
		var teardown = canTestHelpers.dev.willWarn("myTemplate.stache:1: functions are no longer called by default so @ is unnecessary in '@scope.vars.refKey'.");

		MockComponent.extend({
			tag : 'foo-bar',
			viewModel : {
				method : function() {
					ok(true, "foo called");
					return 5;
				}
			}
		});

		var template = stache("myTemplate.stache",
			"<foo-bar method:to='@scope.vars.refKey'></foo-bar>{{scope.vars.refKey()}}");

		var frag = template({});
		equal( frag.lastChild.nodeValue, "5");
		equal(teardown(), 2, "warnings displayed for read and write");

	});
示例#6
0
testHelpers.dev.devOnlyTest("should not be display warning for matching keys when the routes do not match (#99)", function () {
	var expectedWarningText = 'two routes were registered with matching keys:\n' +
		'\t(1) route.register("login", {"page":"auth"})\n' +
		'\t(2) route.register("signup", {"page":"auth"})\n' +
		'(1) will always be chosen since it was registered first';

	var teardown = testHelpers.dev.willWarn(expectedWarningText);

	//should warn
	canRoute.register("login", { "page":"auth" });
	canRoute.register("signup", { "page":"auth" });

	//should not warn
	canRoute.register("login2/", { "page":"auth2" });
	canRoute.register("login2", { "page":"auth2" });

	//should not warn
	canRoute.register("login3", { "page":"auth3" });
	canRoute.register("login3", { "page":"auth3" });

	equal(teardown(), 1);
});
	canTestHelpers.dev.devOnlyTest("Warning happens when changing the map that a to-parent binding points to.", function() {
		var tagName = "merge-warn-test";

		// Delete previous tags, to avoid warnings from can-view-callbacks.
		delete viewCallbacks._tags[tagName];

		expect(2);

		var step1 = { "baz": "quux" };
		var overwrite = { "plonk": "waldo" };

		var teardown = canTestHelpers.dev.willWarn('can-stache-key: Merging data into "bar" because its parent is non-observable');

		var viewModel;
		MockComponent.extend({
			tag: tagName,
			viewModel: function() {
				return viewModel = new SimpleMap({
					"foo": new SimpleMap({})
				});

			}
		});

		var template = stache("<merge-warn-test foo:bind='bar'/>");

		var data = {
			bar: new SimpleMap(step1)
		};

		this.fixture.appendChild(template(data));

		viewModel.set("foo", overwrite);
		deepEqual(data.bar.get(), { "plonk": "waldo" }, "sanity check: parent binding set (default map -> default map)");

		QUnit.equal(teardown(), 1, "warning shown");
	});
testHelpers.makeTests("can-stache-bindings - colon - ViewModel", function(name, doc, enableMO){

	QUnit.test("on:el:click works inside {{#if}} on element with a viewModel (#279)", function() {
		var map = new SimpleMap({
		});

		var MySimpleMap = SimpleMap.extend({
			show: true,
			method: function(){
				ok(true, "method called");
			}
		});
		var parent = new MySimpleMap();

		MockComponent.extend({
			tag: "view-model-able",
			viewModel: map
		});

		var template = stache("<view-model-able {{#if show}} on:el:click='method()' {{/if}} />");

		var frag = template(parent);
		var el = frag.firstChild;
		domEvents.dispatch(el, "click");
	});

	QUnit.test("vm:prop:to/:from/:bind work (#280)", function() {
		var vm1 = new SimpleMap({ value: 'vm1' });
		var vm2 = new SimpleMap({ value: 'vm2' });
		var vm3 = new SimpleMap({ value: 'vm3' });

		MockComponent.extend({
			tag: "comp-1",
			viewModel: vm1
		});
		MockComponent.extend({
			tag: "comp-2",
			viewModel: vm2
		});
		MockComponent.extend({
			tag: "comp-3",
			viewModel: vm3
		});

		var template = stache(
			"<comp-1 vm:value:to='scope1'/>" +
				"<comp-2 vm:value:from='scope2'/>" +
				"<comp-3 vm:value:bind='scope3'/>"
		);

		var scope = new SimpleMap({
			scope1: 'scope1',
			scope2: 'scope2',
			scope3: 'scope3'
		});
		template(scope);

		// vm:value:to
		equal(scope.attr('scope1'), 'vm1', 'vm:value:to - scope value set from vm');

		vm1.attr('value', 'vm4');
		equal(scope.attr('scope1'), 'vm4', 'vm:value:to - scope updated when vm changes');

		scope.attr('scope1', 'scope4');
		equal(vm1.attr('value'), 'vm4', 'vm:value:to - vm not updated when scope changes');

		// vm:value:from
		equal(vm2.attr('value'), 'scope2', 'vm:value:from - vm value set from scope');

		scope.attr('scope2', 'scope5');
		equal(vm2.attr('value'), 'scope5', 'vm:value:from - vm updated when scope changes');

		vm2.attr('value', 'vm5');
		equal(scope.attr('scope2'), 'scope5', 'vm:value:from - scope not updated when vm changes');

		// vm:value:bind
		equal(vm3.attr('value'), 'scope3', 'vm:value:bind - vm value set from scope');

		scope.attr('scope3', 'scope6');
		equal(vm3.attr('value'), 'scope6', 'vm:value:bind - vm updated when scope changes');

		vm3.attr('value', 'vm6');
		equal(scope.attr('scope3'), 'vm6', 'vm:value:bind - scope updated when vm changes');
	});

	canTestHelpers.dev.devOnlyTest("Warning happens when changing the map that a to-parent binding points to.", function() {
		var tagName = "merge-warn-test";

		// Delete previous tags, to avoid warnings from can-view-callbacks.
		delete viewCallbacks._tags[tagName];

		expect(2);

		var step1 = { "baz": "quux" };
		var overwrite = { "plonk": "waldo" };

		var teardown = canTestHelpers.dev.willWarn('can-stache-key: Merging data into "bar" because its parent is non-observable');

		var viewModel;
		MockComponent.extend({
			tag: tagName,
			viewModel: function() {
				return viewModel = new SimpleMap({
					"foo": new SimpleMap({})
				});

			}
		});

		var template = stache("<merge-warn-test foo:bind='bar'/>");

		var data = {
			bar: new SimpleMap(step1)
		};

		this.fixture.appendChild(template(data));

		viewModel.set("foo", overwrite);
		deepEqual(data.bar.get(), { "plonk": "waldo" }, "sanity check: parent binding set (default map -> default map)");

		QUnit.equal(teardown(), 1, "warning shown");
	});

	QUnit.test("changing a scope property calls registered stache helper's returned function", function(){
		expect(1);
		stop();
		var scope = new SimpleMap({
			test: "testval"
		});
		MockComponent.extend({
			tag: "test-component",
			viewModel: scope,
			template: stache('<span>Hello world</span>')

		});

		stache.registerHelper("propChangeEventStacheHelper", function(){
			return function(){
				start();
				ok(true, "helper's returned function called");
			};
		});

		var template = stache('<test-component on:test="propChangeEventStacheHelper()" />');

		template({});

		scope.set('test', 'changed');

	});

	test("one-way pass computes to components with ~", function(assert) {
		expect(6);
		MockComponent.extend({
			tag: "foo-bar"
		});

		var baseVm = new SimpleMap({foo : "bar"});

		this.fixture.appendChild(stache("<foo-bar compute:from=\"~foo\"></foo-bar>")(baseVm));

		var vm = canViewModel(this.fixture.firstChild);
		ok(vm.get("compute")[canSymbol.for('can.getValue')], "observable returned");
		equal(vm.get("compute")(), "bar", "Compute has correct value");

		canReflect.onValue(vm.get("compute"), function() {
			// NB: This gets called twice below, once by
			//  the parent and once directly.
			ok(true, "Change handler called");
		});

		baseVm.set("foo", "quux");
		equal(vm.get("compute")(), "quux", "Compute updates");

		vm.get("compute")("xyzzy");
		equal(baseVm.get("foo"), "xyzzy", "Compute does update the other direction");
	});


	test("Child bindings updated before parent (#2252)", function(){
		var template = stache("{{#eq page 'view'}}<child-binder page:from='page' title:from='title'/>{{/eq}}");
		MockComponent.extend({
			tag: 'child-binder',
			template: stache('<span/>'),
			viewModel: function(props){
				var map = new SimpleMap(props);
				canReflect.assignSymbols(map,{
					"can.setKeyValue": function(key, value){
						if(key === "page"){
							equal(value, "view", "value should not be edit");
						} else {
							QUnit.equal(key, "title", "title was set, we are trapping right");
						}

						this.set(key, value);
					}
				});
				return map;
			}
		});

		var data = new SimpleMap({
			page : 'view'
		});
		template(data);

		data.set('title', 'foo');

		queues.batch.start();
		data.set('page', 'edit');
		queues.batch.stop();
	});

	test("backtrack path in to-parent bindings (#2132)", function(){
		MockComponent.extend({
			tag: "parent-export",
			viewModel: {
				value: "VALUE"
			}
		});

		var template = stache("{{#innerMap}}<parent-export value:to='../parentValue'/>{{/innerMap}}");

		var data = new SimpleMap({
			innerMap: new SimpleMap({})
		});

		template(data);

		equal(data.get("parentValue"), "VALUE", "set on correct context");
		equal(data.get("innerMap").get("parentValue"), undefined, "nothing on innerMap");

	});

	test("function reference to child binding (#2116)", function(){
		expect(2);
		var template = stache('<foo-bar vm:child:from="parent"></foo-bar>');
		MockComponent.extend({
			tag : 'foo-bar',
			viewModel: { }
		});

		var VM = SimpleMap.extend({ });
		var vm = new VM({});
		var frag = template(vm);

		vm.attr("parent", function(){ ok(false, "should not be called"); });
		equal( typeof canViewModel(frag.firstChild).attr("child"), "function", "to child binding");

		template = stache('<foo-bar vm:method:to="vmMethod"></foo-bar>');
		vm = new VM({});
		frag = template(vm);

		canViewModel(frag.firstChild).attr("method",function(){
			ok(false, "method should not be called");
		});
		equal(typeof vm.get("vmMethod"), "function", "parent export function");
	});


	test("setter only gets called once (#2117)", function(){
		expect(1);
		var VM = SimpleMap.extend({
			attr: function(prop, val){
				if(prop === "bar") {
					equal(val, "BAR");
				}
				return SimpleMap.prototype.attr.apply(this, arguments);
			}
		});

		MockComponent.extend({
			tag : 'foo-bar',
			viewModel : VM
		});

		var template = stache('<foo-bar vm:bar:from="bar"/>');

		template(new SimpleMap({bar: "BAR"}));

	});


	test("function reference to child (#2116)", function(){
		expect(2);
		var template = stache('<foo-bar vm:child:from="parent"></foo-bar>');
		MockComponent.extend({
			tag : 'foo-bar',
			viewModel : {
				method: function(){
					ok(false, "should not be called");
				}
			}
		});

		var VM = SimpleMap.extend({
			parent : function() {
				ok(false, "should not be called");
			}
		});

		var vm = new VM({});
		var frag = template(vm);

		equal( typeof canViewModel(frag.firstChild).attr("child"), "function", "to child binding");


		template = stache('<foo-bar vm:method:to="vmMethod"></foo-bar>');
		vm = new VM({});
		template(vm);

		ok(typeof vm.attr("vmMethod") === "function", "parent export function");
	});

	test("exporting methods (#2051)", function(){
		expect(2);


		MockComponent.extend({
			tag : 'foo-bar',
			viewModel : {
				method : function() {
					ok(true, "foo called");
					return 5;
				}
			}
		});

		var template = stache("<foo-bar method:to='scope.vars.refKey'></foo-bar>{{scope.vars.refKey()}}");

		var frag = template({});
		equal( frag.lastChild.nodeValue, "5");

	});

	test('one way - child to parent - importing viewModel hyphenatedProp:to="test"', function(){
		MockComponent.extend({
			tag: 'import-prop-scope',
			template: stache('Hello {{userName}}'),
			viewModel: {
				userName: '******',
				age: 7,
				updateName: function(){
					this.set('userName', 'Justin');
				}
			}
		});

		MockComponent.extend({
			tag: 'import-prop-parent',
			template: stache('<import-prop-scope vm:userName:to="test" vm:this:to="childComponent"></import-prop-scope>' +
				'<div>Imported: {{test}}</div>')
		});

		var template = stache('<import-prop-parent></import-prop-parent>');
		var frag = template({});
		var importPropParent = frag.firstChild;
		var importPropScope = importPropParent.getElementsByTagName("import-prop-scope")[0];

		canViewModel(importPropScope).updateName();

		var importPropParentViewModel = canViewModel(importPropParent);

		equal(importPropParentViewModel.get("test"), "Justin", "got hyphenated prop");

		equal(importPropParentViewModel.get("childComponent"), canViewModel(importPropScope), "got view model");

	});

	test('one way - child to parent - importing viewModel prop:to="test"', function() {
		MockComponent.extend({
			tag: 'import-prop-scope',
			template: stache('Hello {{name}}'),
			viewModel: {
				name: 'David',
				age: 7
			}
		});

		MockComponent.extend({
			tag: 'import-prop-parent',
			template: stache('<import-prop-scope vm:name:to="test"></import-prop-scope>' +
				'<div>Imported: {{test}}</div>')
		});

		var template = stache('<import-prop-parent></import-prop-parent>');
		var frag = template({});

		equal(frag.childNodes.item(0).childNodes.item(1).innerHTML,
			'Imported: David',  '{name} component scope imported into variable');
	});

	test('one-way - child to parent - viewModel', function(){
		MockComponent.extend({
			tag: "view-model-able",
			viewModel: function(){
				return new SimpleMap({viewModelProp: "Mercury"});
			}
		});

		var template = stache("<view-model-able vm:viewModelProp:to='scopeProp'/>");

		var map = new SimpleMap({scopeProp: "Venus"});

		var frag = template(map);
		var viewModel = canViewModel(frag.firstChild);

		equal( viewModel.get("viewModelProp"), "Mercury", "initial value kept" );
		equal( map.get("scopeProp"), "Mercury", "initial value set on parent" );

		viewModel.set("viewModelProp", "Earth");
		equal(map.get("scopeProp"), "Earth", "binding from child to parent");

		map.set("scopeProp", "Mars");
		equal( viewModel.get("viewModelProp"), "Earth", "no binding from parent to child" );
	});

	test('one-way - child to parent - viewModel - with converters', function(){
		MockComponent.extend({
			tag: "view-model-able",
			viewModel: function(){
				return new SimpleMap({viewModelProp: "Mercury"});
			}
		});

		stache.addConverter("upper-case", {
			get: function( fooCompute ) {
				return (""+canReflect.getValue(fooCompute)).toUpperCase();
			},
			set: function( newVal, fooCompute ) {
				canReflect.setValue(fooCompute, (""+newVal).toUpperCase() );
			}
		});

		var template = stache("<view-model-able vm:viewModelProp:to='upper-case(scopeProp)'/>");

		var map = new SimpleMap({scopeProp: "Venus"});

		var frag = template(map);
		var viewModel = canViewModel(frag.firstChild);

		equal( viewModel.get("viewModelProp"), "Mercury", "initial value kept" );
		equal( map.get("scopeProp"), "MERCURY", "initial value set on parent, but upper cased" );

		viewModel.set("viewModelProp", "Earth");
		equal(map.get("scopeProp"), "EARTH", "binding from child to parent updated");

		map.set("scopeProp", "Mars");
		equal( viewModel.get("viewModelProp"), "Earth", "no binding from parent to child" );
	});

	test('one-way - parent to child - viewModel', function(){


		var template = stache("<div vm:viewModelProp:from='scopeProp'/>");


		var map = new SimpleMap({scopeProp: "Venus"});

		var frag = template(map);
		var viewModel = canViewModel(frag.firstChild);

		equal( viewModel.attr("viewModelProp"), "Venus", "initial value set" );

		viewModel.attr("viewModelProp", "Earth");
		equal(map.attr("scopeProp"), "Venus", "no binding from child to parent");

		map.attr("scopeProp", "Mars");
		equal( viewModel.attr("viewModelProp"), "Mars", "binding from parent to child" );
	});


	test('two-way - reference - child:bind="scope.vars.ref" (#1700)', function(){
		var data = new SimpleMap({person: new SimpleMap({name: new SimpleMap({})}) });
		MockComponent.extend({
			tag: 'reference-export',
			viewModel: function(){
				return new SimpleMap({tag: 'reference-export'});
			}
		});
		MockComponent.extend({
			tag: 'ref-import',
			viewModel: function(){
				return new SimpleMap({tag: 'ref-import'});
			}
		});

		var template = stache("<reference-export name:bind='scope.vars.refName'/>"+
			"<ref-import name:bind='scope.vars.refName'/> {{helperToGetScope()}}");

		var scope;
		var frag = template(data,{
			helperToGetScope: function(options){
				scope = options.scope;
			}
		});

		var refExport = canViewModel(frag.firstChild);
		var refImport = canViewModel(frag.firstChild.nextSibling);

		refExport.set("name", "v1");

		equal( scope.peek("scope.vars.refName"), "v1", "reference scope updated");

		equal(refImport.get("name"), "v1", "updated ref-import");

		refImport.set("name", "v2");

		equal(refExport.get("name"), "v2", "updated ref-export");

		equal( scope.peek("scope.vars.refName"), "v2", "actually put in refs scope");

	});

	test('one-way - DOM - parent value undefined (#189)', function() {
		/* WHAT: We are testing whether, given the parent's passed property is
		   undefined, the child template's value is always set to undefined
		   or if the child template is free to update its value.
		 **The child should be free to update its value.**
		 */
		/* HOW: We test a <toggle-button>, in this case the parent prop is undefined
		   so we should be able to toggle true/false on each click.
		   */
		MockComponent.extend({
			tag: 'toggle-button',
			viewModel: function(){
				var vm = new SimpleMap({
					value: false
				});
				vm.toggle = function() {
					this.set( "value", !this.get( "value" ));
				};

				return vm;
			},
			template: stache('<button type="button" on:el:click="toggle()">{{value}}</button>')
		});
		var template = stache('<toggle-button vm:value:bind="./does-not-exist" />');

		var fragment = template({});

		domMutateNode.appendChild.call(this.fixture, fragment);
		var button = this.fixture.getElementsByTagName('button')[0];

		// Get first text for DOM and VDOM
		function text (node) {
			while (node && node.nodeType !== 3) {
				node = node.firstChild;
			}
			return node && node.nodeValue;
		}

		equal(text(button), 'false', 'Initial value is "false"');
		domEvents.dispatch(button, 'click');
		equal(text(button), 'true', 'Value is "true" after first click');
		domEvents.dispatch(button, 'click');
		equal(text(button), 'false', 'Value is "false" after second click');
	});

	test("two way - viewModel (#1700)", function(){

		var template = stache("<div vm:viewModelProp:bind='scopeProp'/>");
		var map = new SimpleMap({ scopeProp: "Hello" });

		var scopeMapSetCalled = 0;

		// overwrite setKeyValue to catch child->parent updates
		var origMapSetKeyValue = map[canSymbol.for("can.setKeyValue")];
		map[canSymbol.for("can.setKeyValue")] = function(attrName, value){
			if(typeof attrName === "string" && arguments.length > 1) {
				scopeMapSetCalled++;
			}

			return origMapSetKeyValue.apply(this, arguments);
		};

		// RENDER
		var frag = template(map);
		var viewModel = canViewModel(frag.firstChild);

		equal(scopeMapSetCalled, 0, "set is not called on scope map");
		equal(viewModel.get("viewModelProp"), "Hello", "initial value set" );

		viewModel = canViewModel(frag.firstChild);

		var viewModelSetCalled = 1; // set once already - on "initial value set"
		var origViewModelSet = viewModel[canSymbol.for("can.setKeyValue")];
		viewModel[canSymbol.for("can.setKeyValue")] = function(attrName){
			if(typeof attrName === "string" && arguments.length > 1) {
				viewModelSetCalled++;
			}

			return origViewModelSet.apply(this, arguments);
		};
		viewModel.set("viewModelProp", "HELLO");
		equal(map.get("scopeProp"), "HELLO", "binding from child to parent");
		equal(scopeMapSetCalled, 1, "set is called on scope map");
		equal(viewModelSetCalled, 2, "set is called viewModel");

		map.set("scopeProp", "WORLD");
		equal(viewModel.get("viewModelProp"), "WORLD", "binding from parent to child" );
		equal(scopeMapSetCalled, 1, "can.setKey is not called again on scope map");
		equal(viewModelSetCalled, 3, "set is called again on viewModel");
	});

	test("standard attributes should not set viewModel props", function(){
		MockComponent.extend({
			tag: "test-elem",
			viewModel: SimpleMap
		});

		var template = stache("<test-elem foo=\"bar\"/>");

		var frag = template(new SimpleMap({
			bar: true
		}));

		var vm = canViewModel(frag.firstChild);

		equal(vm.get('foo'), undefined);
	});

	test("set string on the viewModel", function(){
		expect(2);
		var ViewModel = DefineMap.extend({
			foo: {
				type: "string",
				set: function(val){
					equal(val, "bar");
				}
			},
			baz: {
				type: "string",
				set: function(val){
					equal(val, "qux");
				}
			}
		});

		MockComponent.extend({
			tag: "test-elem",
			viewModel: ViewModel
		});

		var template = stache("<test-elem foo:from=\"'bar'\" baz:from=\"'qux'\"/>");
		template();
	});

	test('viewModel behavior event bindings should be removed when the bound element is', function (assert) {
		MockComponent.extend({
			tag: "view-model-binder",
			viewModel: {},
			template: stache('<span />')
		});

		var done = assert.async();
		var onNodeAttributeChange = domMutate.onNodeAttributeChange;

		var attributeChangeCount = 0;
		var isAttributeChangeTracked = false;
		var isTarget = function (target) {
			return target.nodeName === 'VIEW-MODEL-BINDER';
		};

		domMutate.onNodeAttributeChange = function (node) {
			if (!isTarget(node)) {
				return onNodeAttributeChange.apply(null, arguments);
			}

			attributeChangeCount++;
			isAttributeChangeTracked = true;
			var disposal = onNodeAttributeChange.apply(null, arguments);
			return function () {
				attributeChangeCount--;
				return disposal();
			};
		};

		var viewModel = new SimpleMap({
			isShowing: true,
			bar: 'baz'
		});
		var template = stache('<div>{{#if isShowing}}<view-model-binder foo:bind="bar"/><hr/>{{/if}}</div>');
		var fragment = template(viewModel);
		domMutateNode.appendChild.call(this.fixture, fragment);
		// We use the also effected hr so we
		// can test the span handlers in isolation.
		var hr = this.fixture.firstChild.lastChild;
		var removalDisposal = domMutate.onNodeRemoval(hr, function () {
			removalDisposal();
			domMutate.onNodeAttributeChange = onNodeAttributeChange;

			assert.ok(isAttributeChangeTracked, 'Attribute foo:bind="bar" should be tracked');
			assert.equal(attributeChangeCount, 0, 'all attribute listeners should be disposed');
			done();
		});
		viewModel.attr('isShowing', false);
	});

	canTestHelpers.dev.devOnlyTest("warning displayed when using @", function(){
		expect(3);
		var teardown = canTestHelpers.dev.willWarn("myTemplate.stache:1: functions are no longer called by default so @ is unnecessary in '@scope.vars.refKey'.");

		MockComponent.extend({
			tag : 'foo-bar',
			viewModel : {
				method : function() {
					ok(true, "foo called");
					return 5;
				}
			}
		});

		var template = stache("myTemplate.stache",
			"<foo-bar method:to='@scope.vars.refKey'></foo-bar>{{scope.vars.refKey()}}");

		var frag = template({});
		equal( frag.lastChild.nodeValue, "5");
		equal(teardown(), 2, "warnings displayed for read and write");

	});

	QUnit.test("bindings.viewModel makeViewModel gets passed the binding state", function(){

		var element = document.createElement("bindings-viewmodel");
		element.setAttribute("age:from","years");

		stacheBindings.behaviors.viewModel(element, {
			scope: new Scope({years: 22})
		}, function(data, hasDataBinding, bindingState){
			QUnit.equal(bindingState.isSettingOnViewModel,true, "isSettingOnViewModel called with correct value");
			QUnit.ok(!bindingState.isSettingViewModel, "isSettingOnViewModel called with correct value");
		}, {});

		var element2 = document.createElement("bindings-viewmodel");
		element2.setAttribute("this:from","user");

		stacheBindings.behaviors.viewModel(element2, {
			scope: new Scope({user: {name: "me"}})
		}, function(data, hasDataBinding, bindingState){
			QUnit.ok(!bindingState.isSettingOnViewModel, "isSettingOnViewModel called with correct value");
			QUnit.ok(bindingState.isSettingViewModel, "isSettingOnViewModel called with correct value");
		}, {});

	});

	QUnit.test("double parent update", function() {
		var parentVM = new SimpleMap({
			parentValue: ""
		});
		MockComponent.extend({
			tag: "parent-that-gets",
			viewModel: parentVM,
			template: stache('<child-that-updates child:to="this.parentValue"/>')
		});

		MockComponent.extend({
			tag: "child-that-updates",
			viewModel: new SimpleMap({
				child: "CHILD1"
			}),
			template: stache('<gc-that-updates gc:to="this.child"/>')
		});

		MockComponent.extend({
			tag: "gc-that-updates",
			viewModel: new SimpleMap({
				gc: "gc"
			})
		});

		var template = stache("{{# if(this.show) }}<parent-that-gets/>{{/if}}");
		var root = new SimpleMap({show: false});
		template(root);
		root.set("show", true);

		QUnit.equal(parentVM.get("parentValue"), "gc");
	});

	QUnit.test("scope.event should be available", function() {
		var vm = new SimpleMap({});
		MockComponent.extend({
			tag: "event-producer",
			viewModel: vm,
			template: stache('')
		});

		var template = stache("<event-producer on:event='this.doSomething(scope.event, scope.arguments, scope.args)'/>");

		template({
			doSomething: function(events, argums, args){
				QUnit.equal(events.type , "event", "got an event");
				QUnit.equal(argums.length, 2, "two arguments");
				QUnit.equal(args.length, 3, "3 args");
			}
		});
		vm.dispatch({type: "event"},[1,2]);
	});
	
	QUnit.test("nested props with two way binding", function() {
		var nestedValue = new SimpleMap({
			first: 'Matt'
		});
		var childVM = new SimpleMap({
			name: nestedValue
		});
		MockComponent.extend({
			tag: "my-child",
			viewModel: childVM,
			template: stache('<input value:bind="name.first" />')
		});
		var parentVM = new SimpleMap({
			name: 'Justin'
		});
		MockComponent.extend({
			tag: "my-parent",
			viewModel: parentVM,
			template: stache('<my-child name.first:bind="name" /><input value:bind="name" />')
		});

		var template = stache("<my-parent />")();

		var parentInput = template.childNodes.item(0).childNodes.item(1);
		var childInput = template.childNodes.item(0).childNodes.item(0).childNodes.item(0);

		parentInput.value = 'updated';
		domEvents.dispatch(parentInput, 'change');

		QUnit.equal(parentVM.get('name'), 'updated', 'parent vm has correct value');
		QUnit.equal(nestedValue.get('first'), 'updated', 'child vm has correct value');

		childInput.value = 'child-updated';
		domEvents.dispatch(childInput, 'change');

		QUnit.equal(parentVM.get('name'), 'child-updated', 'parent vm has correct value');
		QUnit.equal(nestedValue.get('first'), 'child-updated', 'child vm has correct value');
	});
});
示例#9
0
testHelpers.dev.devOnlyTest('can-reflect-dependencies', function(assert) {
	var done = assert.async();
	assert.expect(3);

	var div = document.createElement('div');
	document.body.appendChild(div);

	var attr = new SimpleObservable('class');
	var value = new SimpleObservable('foo');

	var text = new Observation(function() {
		var html = '';
		if (attr.get() && value.get()) {
			html += attr.get() + '="' + value.get() + '"';
		}
		return html;
	});

	live.attrs(div, text);

	assert.deepEqual(
		canReflectDeps
			.getDependencyDataOf(div)
			.whatChangesMe
			.mutate
			.valueDependencies,
		new Set([text]),
		'getDependencyDataOf(<div>) should return the observation as a dependency'
	);

	assert.deepEqual(
		canReflectDeps
			.getDependencyDataOf(text)
			.whatIChange
			.mutate
			.valueDependencies,
		new Set([div]),
		'getDependencyDataOf(observation) should return the div as a dependency'
	);

	var undo = domMutate.onNodeRemoval(div, function checkTeardown () {
		undo();

		assert.equal(
			typeof canReflectDeps.getDependencyDataOf(div),
			'undefined',
			'dependencies should be cleared out when element is removed'
		);

		done();
	});

	div.parentNode.removeChild(div);
});
示例#10
0
var canRoute = require('can-route');
var QUnit = require('steal-qunit');
var testHelpers = require('can-test-helpers');

QUnit.module("can-route .register", {
	setup: function(){
		canRoute.routes = {};
	}
});

testHelpers.dev.devOnlyTest("should warn when two routes have same map properties", function () {
	var teardown = testHelpers.dev.willWarn(/two routes were registered with matching keys/);

	canRoute.register("{page}/{subpage}");
	canRoute.register("foo/{page}/{subpage}");

	equal(teardown(), 1);
});

testHelpers.dev.devOnlyTest("should warn when two routes have same map properties - including defaults", function () {
	var teardown = testHelpers.dev.willWarn(/two routes were registered with matching keys/);

	canRoute.register("foo/{page}/{subpage}");
	canRoute.register("{page}/{subpage}");

	equal(teardown(), 1);
});

testHelpers.dev.devOnlyTest("should not warn when two routes have same map properties - but different defaults(#36)", function () {
	var teardown = testHelpers.dev.willWarn(/two routes were registered with matching keys/);
		view: "Hello, World",
		ViewModel: {
			items: {
				default: function() {
					return [ "one", "two" ];
				}
			}
		}
	});

	var renderer = stache("<viewmodel-lists></viewmodel-lists>");

	var fragOne = renderer();
	var vm = viewModel(fragOne.firstChild);

	QUnit.ok(vm.items instanceof define.DefineList, 'vm is a DefineList');
});

testHelpers.dev.devOnlyTest("filename should be passed to stache() for inline views", function() {
	Component.extend({
		tag: "my-filename-component",
		ViewModel: {},
		view: "{{scope.filename}}"
	});

	var renderer = stache("<my-filename-component></my-filename-component>");
	var frag = renderer();

	QUnit.equal(frag.firstChild.innerHTML, "MyFilenameComponentView", "filename was provided to stache()");
});
示例#12
0
testHelpers.dev.devOnlyTest("child elements must disconnect before parents can re-evaluate", 1,function(){
	var observable = new SimpleObservable("value");

	var childObservation = new Observation(function child(){
		QUnit.ok(true, "called child content once");
		observable.get();
		return "CHILD CONTENT";
	},null, {priority: 1});

	var htmlNodeList= [];

	var parentObservation = new Observation(function parent(){
		var result = observable.get();
		if(result === "value") {
			var childTextNode = document.createTextNode('');
			var childFrag = document.createDocumentFragment();
			childFrag.appendChild(childTextNode);
			var nodeList = [childTextNode];

			NodeLists.register(nodeList, null, htmlNodeList, true);
			live.html(childTextNode, childObservation, null, nodeList);
			return childFrag;
		} else {
			return "NEW CONTENT";
		}
	},null,{priority: 0});

	var parentTextNode = document.createTextNode('');
	var div = document.createElement('div');
	div.appendChild(parentTextNode);
	htmlNodeList.push(parentTextNode);

	NodeLists.register(htmlNodeList, function(){}, true, true);
	live.html(parentTextNode, parentObservation, div, htmlNodeList);

	observable.set("VALUE");
});