import { newSpecPage } from "@stencil/core/testing";
import { BpSdkTextInput } from "./bp-sdk-text-input";
describe('bp-sdk-text-input', () => {
    describe('external renders', () => {
        it('renders external component if defined', async () => {
            const whenDefinedMock = jest.spyOn(customElements, 'whenDefined').mockResolvedValueOnce({});
            const page = await newSpecPage({
                html: '<bp-sdk-text-input></bp-sdk-text-input>',
                components: [BpSdkTextInput],
            });
            await page.waitForChanges();
            const element = page.root.querySelector('div');
            expect(element).toBeFalsy();
            expect(page.root.querySelector('bp-sdk-external-text-input')).toBeTruthy();
            whenDefinedMock.mockRestore();
        });
    });
    describe('renders', () => {
        let page;
        let element;
        beforeEach(async () => {
            page = await newSpecPage({
                html: '<bp-sdk-text-input></bp-sdk-text-input>',
                components: [BpSdkTextInput],
            });
            element = page.rootInstance;
        });
        it('vanilla', async () => {
            element.text = 'james';
            element.fieldType = null;
            element.max = null;
            element.min = null;
            element.labelledBy = 'label';
            element.labelId = 'aria';
            await page.waitForChanges();
            const input = page.root.querySelector('input');
            expect(input.value).toEqual('james');
            expect(input.minLength).toEqual(-1);
            expect(input.maxLength).toEqual(-1);
            expect(input.type).toEqual('text');
            expect(input.getAttribute('aria-labelledby')).toEqual('label aria');
        });
        it('responds to value changes', async () => {
            element.min = 0;
            element.max = 10;
            element.fieldType = 'text';
            element.text = 'james';
            await page.waitForChanges();
            const input = page.root.querySelector('input');
            expect(input.value).toEqual('james');
            expect(input.minLength).toEqual(0);
            expect(input.maxLength).toEqual(10);
            expect(input.type).toEqual('text');
        });
        it('renders errors', async () => {
            element.min = 0;
            element.max = 10;
            element.fieldType = 'text';
            element.text = 'james';
            element.touched = true;
            element.pristine = false;
            element.errors = ['required'];
            await page.waitForChanges();
            expect(page.body.querySelectorAll('bp-sdk-errors-container').length).toEqual(1);
        });
        it('renders errors if is completed', async () => {
            element.min = 0;
            element.max = 10;
            element.fieldType = 'text';
            element.text = 'james';
            element.touched = true;
            element.pristine = false;
            element.errors = ['required'];
            element.isCompleted = true;
            await page.waitForChanges();
            expect(page.body.querySelectorAll('bp-sdk-errors-container').length).toEqual(1);
        });
        it('renders error text', async () => {
            element.min = 0;
            element.max = 10;
            element.fieldType = 'text';
            element.text = 'james';
            element.touched = true;
            element.pristine = false;
            element.errorText = 'error';
            await page.waitForChanges();
            expect(page.body.querySelectorAll('bp-sdk-errors-container').length).toEqual(1);
        });
        it('hides error text if is completed', async () => {
            element.min = 0;
            element.max = 10;
            element.fieldType = 'text';
            element.text = 'james';
            element.touched = true;
            element.pristine = false;
            element.errorText = 'error';
            element.isCompleted = true;
            await page.waitForChanges();
            expect(page.body.querySelectorAll('bp-sdk-errors-container').length).toEqual(0);
        });
        it('renders handles null errors', async () => {
            element.min = 0;
            element.max = 10;
            element.fieldType = 'text';
            element.text = 'james';
            element.touched = true;
            element.pristine = false;
            element.errors = null;
            await page.waitForChanges();
            expect(page.body.querySelectorAll('bp-sdk-errors-container').length).toEqual(0);
        });
        it('uses tel if type is "number" and sets fallback pattern', async () => {
            element.fieldType = 'number';
            await page.waitForChanges();
            const input = page.root.querySelector('input');
            expect(input.type).toEqual('tel');
            expect(input.pattern).toEqual('^\\d*');
        });
        it('sets minLength/maxLength if type is is "text"', async () => {
            element.fieldType = 'text';
            const [min, max] = ['5', '100'];
            element.min = +min;
            element.max = +max;
            await page.waitForChanges();
            const input = page.root.querySelector('input');
            expect(input.minLength).toEqual(+min);
            expect(input.maxLength).toEqual(+max);
            expect(input.min).toEqual('');
            expect(input.max).toEqual('');
        });
        it('minLength/maxLength has fallback', async () => {
            element.fieldType = 'text';
            await page.waitForChanges();
            const input = page.root.querySelector('input');
            expect(input.minLength).toEqual(-1);
            expect(input.maxLength).toEqual(-1);
        });
        it('sets min/max if type is "number"', async () => {
            element.fieldType = 'number';
            const [min, max] = ['5', '100'];
            element.min = +min;
            element.max = +max;
            await page.waitForChanges();
            const input = page.root.querySelector('input');
            expect(input.min).toEqual(min);
            expect(input.max).toEqual(max);
            expect(input.minLength).toEqual(0);
            expect(input.maxLength).toEqual(0);
        });
        it('sets min/max has fallback', async () => {
            element.fieldType = 'number';
            element.min = undefined;
            element.max = undefined;
            await page.waitForChanges();
            const input = page.root.querySelector('input');
            expect(input.min).toEqual(Number.MIN_VALUE.toString());
            expect(input.max).toEqual(Number.MAX_VALUE.toString());
        });
        it('has no label if label prop is null', async () => {
            element.label = null;
            await page.waitForChanges();
            const label = page.root.querySelector('label');
            expect(label).toBeNull();
        });
        it('has a label if label prop is defined', async () => {
            element.label = 'I am a label';
            await page.waitForChanges();
            const label = page.root.querySelector('label');
            expect(label).toBeDefined();
        });
        it.each([
            ['placeholder', null, 'placeholder'],
            ['placeholder', 'label', null],
            [null, 'label', null],
            [null, null, null],
        ])('when the placeholder is "%s" and the label is "%s", the aria-label should be "%s"', async (placeholder, label, expectedAriaLabel) => {
            element.fieldType = 'text';
            element.label = label;
            element.placeholder = placeholder;
            await page.waitForChanges();
            const input = page.root.querySelector('input');
            const ariaLabel = input.getAttribute('aria-label');
            expect(ariaLabel).toEqual(expectedAriaLabel);
        });
        describe('when the component is marked as read only', () => {
            const value = 'llama';
            beforeEach(async () => {
                element.isReadOnly = true;
                element.text = value;
                await page.waitForChanges();
            });
            it('should render a read only value', () => {
                const element = page.body.querySelector('.read-only-value');
                expect(element.textContent).toEqual(value);
            });
            it('should not render an input', () => {
                expect(page.body.querySelectorAll('input').length).toEqual(0);
            });
        });
    });
    describe('event handling', () => {
        let page;
        beforeEach(async () => {
            page = await newSpecPage({
                html: '<bp-sdk-text-input></bp-sdk-text-input>',
                components: [BpSdkTextInput],
            });
        });
        it('emits on change', async () => {
            const inputSpy = jest.fn();
            page.win.addEventListener('valueUpdate', inputSpy);
            await page.waitForChanges();
            const input = page.root.querySelector('input');
            input.value = 'james';
            input.dispatchEvent(new Event('change'));
            await page.waitForChanges();
            let ev = inputSpy.mock.calls[inputSpy.mock.calls.length - 1][0].detail;
            expect(ev).toBe('james');
        });
        it('emits on paste', async () => {
            const inputSpy = jest.fn();
            page.win.addEventListener('valueUpdate', inputSpy);
            await page.waitForChanges();
            const input = page.root.querySelector('input');
            input.value = 'james';
            input.dispatchEvent(new Event('paste'));
            await page.waitForChanges();
            let ev = inputSpy.mock.calls[inputSpy.mock.calls.length - 1][0].detail;
            expect(ev).toBe('james');
        });
        it('emits on input', async () => {
            const inputSpy = jest.fn();
            page.win.addEventListener('valueUpdate', inputSpy);
            await page.waitForChanges();
            const input = page.root.querySelector('input');
            input.value = 'james';
            input.dispatchEvent(new Event('input'));
            await page.waitForChanges();
            let ev = inputSpy.mock.calls[inputSpy.mock.calls.length - 1][0].detail;
            expect(ev).toBe('james');
        });
    });
});
