import { setupRerender } from 'preact/test-utils';
import { createElement as h, render } from 'preact';
import { setupScratch, teardown } from '../../../test/_util/helpers';
import { useState } from '../../src';

/** @jsx h */


describe('useState', () => {

	/** @type {HTMLDivElement} */
	let scratch;

	/** @type {() => void} */
	let rerender;

	beforeEach(() => {
		scratch = setupScratch();
		rerender = setupRerender();
	});

	afterEach(() => {
		teardown(scratch);
	});


	it('serves the same state across render calls', () => {
		const stateHistory = [];

		function Comp() {
			const [state] = useState({ a: 1 });
			stateHistory.push(state);
			return null;
		}

		render(<Comp />, scratch);
		render(<Comp />, scratch);

		expect(stateHistory).to.deep.equal([{ a: 1 }, { a: 1 }]);
		expect(stateHistory[0]).to.equal(stateHistory[1]);
	});

	it('can initialize the state via a function', () => {
		const initState = sinon.spy(() => { 1; });

		function Comp() {
			useState(initState);
			return null;
		}

		render(<Comp />, scratch);
		render(<Comp />, scratch);

		expect(initState).to.be.calledOnce;
	});

	it('does not rerender on equal state', () => {
		let lastState;
		let doSetState;

		const Comp = sinon.spy(() => {
			const [state, setState] = useState(0);
			lastState = state;
			doSetState = setState;
			return null;
		});

		render(<Comp />, scratch);
		expect(lastState).to.equal(0);
		expect(Comp).to.be.calledOnce;

		doSetState(0);
		rerender();
		expect(lastState).to.equal(0);
		expect(Comp).to.be.calledOnce;

		doSetState(() => 0);
		rerender();
		expect(lastState).to.equal(0);
		expect(Comp).to.be.calledOnce;
	});

	it('rerenders when setting the state', () => {
		let lastState;
		let doSetState;

		const Comp = sinon.spy(() => {
			const [state, setState] = useState(0);
			lastState = state;
			doSetState = setState;
			return null;
		});

		render(<Comp />, scratch);
		expect(lastState).to.equal(0);
		expect(Comp).to.be.calledOnce;

		doSetState(1);
		rerender();
		expect(lastState).to.equal(1);
		expect(Comp).to.be.calledTwice;

		// Updater function style
		doSetState(current => current * 10);
		rerender();
		expect(lastState).to.equal(10);
		expect(Comp).to.be.calledThrice;
	});

	it('can be set by another component', () => {
		function StateContainer() {
			const [count, setCount] = useState(0);
			return (<div>
				<p>Count: {count}</p>
				<Increment increment={() => setCount(c => c + 10)} />
			</div>);
		}

		function Increment(props) {
			return <button onClick={props.increment}>Increment</button>;
		}

		render(<StateContainer />, scratch);
		expect(scratch.textContent).to.include('Count: 0');

		const button = scratch.querySelector('button');
		button.click();

		rerender();
		expect(scratch.textContent).to.include('Count: 10');
	});
});

@@ -2799,13 +2799,823 @@
 ');%0A%09%7D);
+%0A%0A%09it('should handle queued useState', () =%3E %7B%0A%09%09function Message(%7B message, onClose %7D) %7B%0A%09%09%09const %5BisVisible, setVisible%5D = useState(Boolean(message));%0A%09%09%09const %5BprevMessage, setPrevMessage%5D = useState(message);%0A%0A%09%09%09if (message !== prevMessage) %7B%0A%09%09%09%09setPrevMessage(message);%0A%09%09%09%09setVisible(Boolean(message));%0A%09%09%09%7D%0A%0A%09%09%09if (!isVisible) %7B%0A%09%09%09%09return null;%0A%09%09%09%7D%0A%09%09%09return %3Cp onClick=%7BonClose%7D%3E%7Bmessage%7D%3C/p%3E;%0A%09%09%7D%0A%0A%09%09function App() %7B%0A%09%09%09const %5Bmessage, setMessage%5D = useState('Click Here!!');%0A%09%09%09return (%0A%09%09%09%09%3CMessage%0A%09%09%09%09%09onClose=%7B() =%3E %7B%0A%09%09%09%09%09%09setMessage('');%0A%09%09%09%09%09%7D%7D%0A%09%09%09%09%09message=%7Bmessage%7D%0A%09%09%09%09/%3E%0A%09%09%09);%0A%09%09%7D%0A%0A%09%09render(%3CApp /%3E, scratch);%0A%09%09expect(scratch.textContent).to.equal('Click Here!!');%0A%09%09const text = scratch.querySelector('p');%0A%09%09text.click();%0A%09%09rerender();%0A%09%09expect(scratch.innerHTML).to.equal('');%0A%09%7D);
 %0A%7D);%0A

add relevant test