import { newSpecPage } from "@stencil/core/testing";
jest.mock('../../utils/google-maps-loader');
import { BpSdkGooglePlacesAutocomplete } from "./bp-sdk-google-places-autocomplete";
describe('bp-sdk-google-places-autocomplete', () => {
    beforeEach(() => {
        globalThis.google = {
            maps: {
                places: {
                    Autocomplete: class {
                        addListener() { }
                        getPlace() {
                            return {};
                        }
                    },
                },
            },
        };
    });
    it('renders', async () => {
        const page = await newSpecPage({
            html: '<bp-sdk-google-places-autocomplete min_value="1" max_value="1"></bp-sdk-google-places-autocomplete>',
            components: [BpSdkGooglePlacesAutocomplete],
        });
        const instance = page.rootInstance;
        instance.labelId = 'aria';
        instance.labelledBy = 'label';
        await page.waitForChanges();
        const input = page.body.querySelector('.bp-sdk-google-places-autocomplete__input');
        expect(input.getAttribute('aria-labelledby')).toEqual('label aria');
        expect(input.getAttribute('minLength')).toEqual('1');
        expect(input.getAttribute('maxLength')).toEqual('1');
    });
    it('renders missing ranges', async () => {
        const page = await newSpecPage({
            html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
            components: [BpSdkGooglePlacesAutocomplete],
        });
        const instance = page.rootInstance;
        instance.labelId = 'aria';
        instance.labelledBy = 'label';
        instance.min = undefined;
        instance.max = undefined;
        await page.waitForChanges();
        const input = page.body.querySelector('.bp-sdk-google-places-autocomplete__input');
        expect(input.getAttribute('aria-labelledby')).toEqual('label aria');
        expect(input.getAttribute('minLength')).toEqual('-1');
        expect(input.getAttribute('maxLength')).toEqual('-1');
    });
    it('renders placeholder as fallback label', async () => {
        const page = await newSpecPage({
            html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
            components: [BpSdkGooglePlacesAutocomplete],
        });
        const instance = page.rootInstance;
        instance.label = undefined;
        instance.placeholder = 'placeholder';
        await page.waitForChanges();
        const input = page.body.querySelector('.bp-sdk-google-places-autocomplete__input');
        expect(input.getAttribute('aria-label')).toEqual(instance.placeholder);
    });
    it('renders error text', async () => {
        const page = await newSpecPage({
            html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
            components: [BpSdkGooglePlacesAutocomplete],
        });
        page.rootInstance.errorText = 'some error';
        page.rootInstance.touched = true;
        page.rootInstance.pristine = false;
        await page.waitForChanges();
        const element = page.body.querySelector('bp-sdk-errors-container');
        expect(element).toBeTruthy();
    });
    it('hides error text if completed', async () => {
        const page = await newSpecPage({
            html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
            components: [BpSdkGooglePlacesAutocomplete],
        });
        page.rootInstance.errorText = 'some error';
        page.rootInstance.touched = true;
        page.rootInstance.pristine = false;
        page.rootInstance.isCompleted = true;
        await page.waitForChanges();
        const element = page.body.querySelector('bp-sdk-errors-container');
        expect(element).toBeFalsy();
    });
    it('renders errors', async () => {
        const page = await newSpecPage({
            html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
            components: [BpSdkGooglePlacesAutocomplete],
        });
        page.rootInstance.errors = ['some error'];
        page.rootInstance.touched = true;
        page.rootInstance.pristine = false;
        await page.waitForChanges();
        const element = page.body.querySelector('bp-sdk-errors-container');
        expect(element).toBeTruthy();
    });
    it('renders errors if isCompleted', async () => {
        const page = await newSpecPage({
            html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
            components: [BpSdkGooglePlacesAutocomplete],
        });
        page.rootInstance.errors = ['some error'];
        page.rootInstance.touched = true;
        page.rootInstance.pristine = false;
        page.rootInstance.isCompleted = true;
        await page.waitForChanges();
        const element = page.body.querySelector('bp-sdk-errors-container');
        expect(element).toBeTruthy();
    });
    it('renders no errors if none', async () => {
        const page = await newSpecPage({
            html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
            components: [BpSdkGooglePlacesAutocomplete],
        });
        page.rootInstance.errors = [];
        page.rootInstance.touched = true;
        page.rootInstance.pristine = false;
        await page.waitForChanges();
        const element = page.body.querySelector('bp-sdk-errors-container');
        expect(element).toBeFalsy();
    });
    it('renders no errors if errors is falsy', async () => {
        const page = await newSpecPage({
            html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
            components: [BpSdkGooglePlacesAutocomplete],
        });
        page.rootInstance.errors = null;
        page.rootInstance.touched = true;
        page.rootInstance.pristine = false;
        await page.waitForChanges();
        const element = page.body.querySelector('bp-sdk-errors-container');
        expect(element).toBeFalsy();
    });
    it('renders external component if defined', async () => {
        const whenDefinedMock = jest.spyOn(customElements, 'whenDefined').mockResolvedValueOnce({});
        const page = await newSpecPage({
            html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
            components: [BpSdkGooglePlacesAutocomplete],
        });
        await page.waitForChanges();
        const element = page.root.querySelector('div');
        expect(element).toBeFalsy();
        whenDefinedMock.mockRestore();
    });
    describe('when the component is marked as read only', () => {
        const value = 'llama';
        let page;
        let instance;
        beforeEach(async () => {
            page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            instance = page.rootInstance;
            instance.isReadOnly = true;
            instance.filter = 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('componentDidLoad', () => {
        it('should make expected calls', async () => {
            const page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            const instance = page.rootInstance;
            jest.spyOn(instance, 'setupAutocomplete').mockImplementation(() => { });
            await page.waitForChanges();
            instance.isLoaded = false;
            await instance.componentDidLoad();
            expect(instance.isLoaded).toBeTruthy();
        });
    });
    describe('onIsLoadedChange', () => {
        it('should make expected calls', async () => {
            const page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            const instance = page.rootInstance;
            jest.spyOn(instance, 'onGoogleApiKeyChange').mockImplementation((() => { }));
            await page.waitForChanges();
            instance.onIsLoadedChange(true);
            expect(instance.onGoogleApiKeyChange).toHaveBeenCalledTimes(1);
        });
        it('does nothing if false', async () => {
            const page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            const instance = page.rootInstance;
            jest.spyOn(instance, 'onGoogleApiKeyChange').mockImplementation((() => { }));
            await page.waitForChanges();
            instance.onIsLoadedChange(false);
            expect(instance.onGoogleApiKeyChange).toHaveBeenCalledTimes(0);
        });
    });
    describe('onGoogleApiKeyChange', () => {
        it('should make expected calls', async () => {
            const page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            const instance = page.rootInstance;
            jest.spyOn(instance, 'setupAutocomplete').mockImplementation(() => { });
            instance.isLoaded = true;
            await page.waitForChanges();
            await instance.onGoogleApiKeyChange('bob');
            expect(instance.setupAutocomplete).toHaveBeenCalledTimes(1);
        });
        it('does nothing if not loaded', async () => {
            const page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            const instance = page.rootInstance;
            jest.spyOn(instance, 'setupAutocomplete').mockImplementation(() => { });
            instance.isLoaded = false;
            await page.waitForChanges();
            await instance.onGoogleApiKeyChange('bob');
            expect(instance.setupAutocomplete).toHaveBeenCalledTimes(0);
        });
        it('does nothing if no api key', async () => {
            const page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            const instance = page.rootInstance;
            jest.spyOn(instance, 'setupAutocomplete').mockImplementation(() => { });
            instance.isLoaded = true;
            await page.waitForChanges();
            await instance.onGoogleApiKeyChange('');
            expect(instance.setupAutocomplete).toHaveBeenCalledTimes(0);
        });
    });
    describe('setupAutocomplete', () => {
        it('sets up autocomplete', async () => {
            const page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            await page.waitForChanges();
            const instance = page.rootInstance;
            const addListenerSpy = jest.fn();
            const autocompleteClass = class {
                constructor() {
                    this.addListener = addListenerSpy;
                }
            };
            globalThis.google.maps.places.Autocomplete = autocompleteClass;
            instance.setupAutocomplete();
            expect(addListenerSpy).toHaveBeenCalledTimes(1);
        });
    });
    describe('disconnectedCallback', () => {
        it('does nothing if no place changed event', async () => {
            const page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            await page.waitForChanges();
            const instance = page.rootInstance;
            instance.placeChangedEvent = null;
            page.win['google'] = {
                maps: {
                    event: {
                        removeListener: jest.fn(),
                    },
                },
            };
            instance.disconnectedCallback();
            expect(page.win['google'].maps.event.removeListener).toHaveBeenCalledTimes(0);
        });
        it('destroys listener', async () => {
            const page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            await page.waitForChanges();
            const instance = page.rootInstance;
            instance.placeChangedEvent = 'some value';
            page.win['google'] = {
                maps: {
                    event: {
                        removeListener: jest.fn(),
                    },
                },
            };
            instance.disconnectedCallback();
            expect(page.win['google'].maps.event.removeListener).toHaveBeenCalledTimes(1);
            expect(page.win['google'].maps.event.removeListener).toHaveBeenCalledWith(instance.placeChangedEvent);
        });
    });
    describe('handlePlaceChanged', () => {
        it('should make expected calls', async () => {
            const page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            await page.waitForChanges();
            const instance = page.rootInstance;
            instance.onPlaceChanged = jest.fn();
            instance.handlePlaceChanged();
            expect(instance.onPlaceChanged).toHaveBeenCalledTimes(1);
        });
    });
    describe('onPlacesChange', () => {
        it('should do nothing if places is same', async () => {
            const page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            await page.waitForChanges();
            const instance = page.rootInstance;
            jest.spyOn(instance.valueUpdate, 'emit');
            jest.spyOn(instance.placesUpdate, 'emit');
            const value = {
                name: 'some value',
            };
            instance.value = value;
            instance.autocomplete = {
                getPlace: jest.fn(() => value),
            };
            instance.onPlaceChanged();
            expect(instance.autocomplete.getPlace).toHaveBeenCalledTimes(1);
            expect(instance.valueUpdate.emit).toHaveBeenCalledTimes(0);
            expect(instance.placesUpdate.emit).toHaveBeenCalledTimes(0);
        });
        it('should do nothing if useExternal', async () => {
            const page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            await page.waitForChanges();
            const instance = page.rootInstance;
            jest.spyOn(instance.valueUpdate, 'emit');
            jest.spyOn(instance.placesUpdate, 'emit');
            const value = {
                name: 'some value',
            };
            instance.useExternal = true;
            instance.autocomplete = {
                getPlace: jest.fn(() => value),
            };
            instance.onPlaceChanged();
            expect(instance.autocomplete.getPlace).toHaveBeenCalledTimes(0);
            expect(instance.valueUpdate.emit).toHaveBeenCalledTimes(0);
            expect(instance.placesUpdate.emit).toHaveBeenCalledTimes(0);
        });
        it('should emit place if changed', async () => {
            const page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            await page.waitForChanges();
            const instance = page.rootInstance;
            jest.spyOn(instance.valueUpdate, 'emit');
            jest.spyOn(instance.placesUpdate, 'emit');
            const value = {
                name: 'some value',
            };
            instance.autocomplete = {
                getPlace: jest.fn(() => value),
            };
            instance.onPlaceChanged();
            expect(instance.autocomplete.getPlace).toHaveBeenCalledTimes(1);
            expect(instance.valueUpdate.emit).toHaveBeenCalledTimes(1);
            expect(instance.valueUpdate.emit).toHaveBeenCalledWith(value.name);
            expect(instance.placesUpdate.emit).toHaveBeenCalledTimes(1);
            expect(instance.placesUpdate.emit).toHaveBeenCalledWith(value);
        });
        it('skip value if no name', async () => {
            const page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            await page.waitForChanges();
            const instance = page.rootInstance;
            jest.spyOn(instance.valueUpdate, 'emit');
            jest.spyOn(instance.placesUpdate, 'emit');
            const value = {};
            instance.autocomplete = {
                getPlace: jest.fn(() => value),
            };
            instance.onPlaceChanged();
            expect(instance.autocomplete.getPlace).toHaveBeenCalledTimes(1);
            expect(instance.valueUpdate.emit).toHaveBeenCalledTimes(0);
            expect(instance.placesUpdate.emit).toHaveBeenCalledTimes(1);
            expect(instance.placesUpdate.emit).toHaveBeenCalledWith(value);
        });
    });
    describe('onChange', () => {
        it('makes expected calls', async () => {
            const page = await newSpecPage({
                html: '<bp-sdk-google-places-autocomplete></bp-sdk-google-places-autocomplete>',
                components: [BpSdkGooglePlacesAutocomplete],
            });
            await page.waitForChanges();
            const instance = page.rootInstance;
            jest.spyOn(instance.valueUpdate, 'emit').mockImplementation((() => { }));
            const value = 'some value';
            instance.onChange({
                target: {
                    value,
                },
            });
            expect(instance.valueUpdate.emit).toHaveBeenCalledTimes(1);
            expect(instance.valueUpdate.emit).toHaveBeenCalledWith(value);
        });
    });
});
