import { Component } from '../../src/preact';
import { createLinkedState } from '../../src/linked-state';

describe('linked-state', () => {
	class TestComponent extends Component {	}
	let testComponent, linkFunction;

	before( () => {
		testComponent = new TestComponent();
		sinon.spy(TestComponent.prototype, 'setState');
	});

	describe('createLinkedState without eventPath argument', () => {

		before( () => {
			linkFunction = createLinkedState(testComponent,'testStateKey');
			expect(linkFunction).to.be.a('function');
		});

		beforeEach( () => {
			TestComponent.prototype['setState'].reset();
		});

		it('should use value attribute on text input when no eventPath is supplied', () => {
			let element = document.createElement('input');
			element.type= 'text';
			element.value = 'newValue';

			linkFunction.call(element);
			expect(TestComponent.prototype.setState).to.have.been.calledOnce;
			expect(TestComponent.prototype.setState).to.have.been.calledWith({'testStateKey': 'newValue'});
		});

		it('should use checked attribute on checkbox input when no eventPath is supplied', () => {
			let checkboxElement = document.createElement('input');
			checkboxElement.type= 'checkbox';
			checkboxElement.checked = true;

			linkFunction.call(checkboxElement);
			expect(TestComponent.prototype.setState).to.have.been.calledOnce;
			expect(TestComponent.prototype.setState).to.have.been.calledWith({'testStateKey': true});
		});

		it('should use checked attribute on radio input when no eventPath is supplied', () => {
			let radioElement = document.createElement('input');
			radioElement.type= 'radio';
			radioElement.checked = true;
			linkFunction.call(radioElement);
			expect(TestComponent.prototype.setState).to.have.been.calledOnce;
			expect(TestComponent.prototype.setState).to.have.been.calledWith({'testStateKey': true});
		});


		it('should set dot notated state key appropriately', () => {
			linkFunction = createLinkedState(testComponent,'nested.state.key');
			let element = document.createElement('input');
			element.type= 'text';
			element.value = 'newValue';

			linkFunction.call(element);
			expect(TestComponent.prototype.setState).to.have.been.calledOnce;
			expect(TestComponent.prototype.setState).to.have.been.calledWith({nested: {state: {key: 'newValue'}}});
		});

	});

	describe('createLinkedState with eventPath argument', () => {

		before( () => {
			linkFunction = createLinkedState(testComponent,'testStateKey', 'nested.path');
			expect(linkFunction).to.be.a('function');
		});

		beforeEach( () => {
			TestComponent.prototype['setState'].reset();
		});

		it('should give precedence to nested.path on event over nested.path on component', () => {
			let event = {nested: {path: 'nestedPathValueFromEvent'}};
			let component = {_component: {nested: {path: 'nestedPathValueFromComponent'}}};

			linkFunction.call(component, event);
			expect(TestComponent.prototype.setState).to.have.been.calledOnce;
			expect(TestComponent.prototype.setState).to.have.been.calledWith({'testStateKey': 'nestedPathValueFromEvent'});
		});

		it('should use nested.path when supplied on component and nested.path not in event', () => {
			let event = {};
			let component = {_component: {nested: {path: 'nestedPathValueFromComponent'}}};

			linkFunction.call(component, event);
			expect(TestComponent.prototype.setState).to.have.been.calledOnce;
			expect(TestComponent.prototype.setState).to.have.been.calledWith({'testStateKey': 'nestedPathValueFromComponent'});
		});

		it('should call the function with the calling element as "this" if value is a function', () => {
			let element = document.createElement('input');
			element.type= 'text';
			element.anAttribute = 'functionValue';
			let testFunction = function() { return this.anAttribute; };
			let event = {nested: {path: testFunction}};

			linkFunction.call(element, event);
			expect(TestComponent.prototype.setState).to.have.been.calledOnce;
			expect(TestComponent.prototype.setState).to.have.been.calledWith({'testStateKey': 'functionValue'});
		});

	});
});

@@ -813,32 +813,47 @@
 Function
-.call(
+(%7B currentTarget: 
 element
+ %7D
 );%0A
+%0A
 %09%09%09expec
@@ -1003,32 +1003,245 @@
 ': 'newValue'%7D);
+%0A%0A%09%09%09linkFunction.call(element);%0A%0A%09%09%09expect(TestComponent.prototype.setState).to.have.been.calledTwice;%0A%09%09%09expect(TestComponent.prototype.setState.secondCall).to.have.been.calledWith(%7B'testStateKey': 'newValue'%7D);
 %0A%09%09%7D);%0A%0A%09%09it('sh
@@ -1471,22 +1471,34 @@
 Function
-.call(
+(%7B currentTarget: 
 checkbox
@@ -1500,27 +1500,30 @@
 ckboxElement
+ %7D
 );%0A
+%0A
 %09%09%09expect(Te
@@ -1887,16 +1887,17 @@
 = true;%0A
+%0A
 %09%09%09linkF
@@ -1903,22 +1903,34 @@
 Function
-.call(
+(%7B currentTarget: 
 radioEle
@@ -1929,27 +1929,30 @@
 radioElement
+ %7D
 );%0A
+%0A
 %09%09%09expect(Te
@@ -2365,32 +2365,47 @@
 Function
-.call(
+(%7B currentTarget: 
 element
+ %7D
 );%0A
+%0A
 %09%09%09expec
@@ -3148,32 +3148,33 @@
 ponent, event);%0A
+%0A
 %09%09%09expect(TestCo
@@ -4060,32 +4060,58 @@
 ute; %7D;%0A
+%0A
 %09%09%09l
-et event = %7B
+inkFunction(%7B currentTarget:element, 
 nested: 
@@ -4135,49 +4135,12 @@
 on%7D%7D
+)
 ;%0A%0A
-%09%09%09linkFunction.call(element, event);%0A
 %09%09%09e

Update linked state tests for revised implementation