jest.mock('@boldpenguin/sdk-utility', () => {
    return Object.assign({ __esModule: true }, jest.requireActual('@boldpenguin/sdk-utility'));
});
import * as utils from "@boldpenguin/sdk-utility";
import { LoadingStates } from "@boldpenguin/sdk-types";
import { newSpecPage } from "@stencil/core/testing";
import { VehicleVinService } from "../../services/vehicle-vin.service";
import { BpSdkVehicleVinContainer } from "./bp-sdk-vehicle-vin-container";
const fakeStore = {
    config: {
        env: 'testEnv',
        uri: 'https://test.local',
    },
    auth: {
        token: 'testToken',
    },
    application: {
        questionSets: {
            list: [
                {
                    question_set: {
                        code: 'vehicle_pool_master_question_set',
                    },
                    answers: [
                        {
                            id: 'testAnswerId',
                            answered_by_consumer: true,
                        },
                    ],
                },
            ],
        },
    },
    viewState: {
        vehicleOptions: {
            configurations: {
                testId: {},
            },
            selection: {
                testId: {
                    yearId: 2018,
                    makeId: '53',
                    modelId: '436357',
                    configurationId: '1440364',
                },
            },
            vin: {
                testId: {},
            },
        },
    },
    status: {
        remote: {
            vehicles: {
                vins: { testId: LoadingStates.Loaded },
            },
        },
    },
};
const setupPage = async () => {
    return await newSpecPage({
        html: '<bp-sdk-vehicle-vin-container question-group-id="testId"></bp-sdk-vehicle-vin-container>',
        components: [BpSdkVehicleVinContainer],
    });
};
const setupInstance = (page) => {
    const instance = page.rootInstance;
    instance.vinStatus = LoadingStates.NotLoaded;
    jest.spyOn(instance, 'loadVin').mockImplementation(jest.fn());
    instance.storeUnsubscribe = jest.fn();
    return instance;
};
describe('bp-sdk-vehicle-vin-container', () => {
    afterEach(() => {
        jest.restoreAllMocks();
    });
    it('renders', async () => {
        const page = await setupPage();
        await page.waitForChanges();
        page.root;
        const element = page.root.querySelector('bp-sdk-vehicle-vin');
        expect(element).toBeTruthy();
    });
    it('resets search', async () => {
        const page = await setupPage();
        await page.waitForChanges();
        page.root;
        const element = page.root.querySelector('bp-sdk-vehicle-vin');
        expect(element).toBeTruthy();
    });
    it('renders external component if defined', async () => {
        const whenDefinedMock = jest.spyOn(customElements, 'whenDefined').mockResolvedValueOnce({});
        const page = await setupPage();
        await page.waitForChanges();
        const element = page.root.querySelector('bp-sdk-vehicle-vin');
        expect(element).toBeFalsy();
        whenDefinedMock.mockRestore();
    });
    describe('componentDidLoad', () => {
        it('makes expected calls', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            jest.spyOn(instance, 'loadFocusEvents').mockImplementation(() => { });
            await page.waitForChanges();
            instance.componentDidLoad();
            expect(instance.loadFocusEvents).toBeCalledTimes(1);
        });
    });
    describe('disconnectedCallback', () => {
        it('makes expected calls', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            jest.spyOn(instance, 'unloadFocusEvents').mockImplementation(() => { });
            instance.disconnectedCallback();
            expect(instance.unloadFocusEvents).toBeCalledTimes(1);
            expect(instance.storeUnsubscribe).toBeCalledTimes(1);
        });
    });
    describe('loadFocusEvents', () => {
        it('sets expected values', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.useExternal = false;
            jest.spyOn(instance.el, 'addEventListener').mockReturnValue();
            await page.waitForChanges();
            instance.loadFocusEvents();
            expect(instance.el.addEventListener).toBeCalledTimes(1);
            expect(instance.el.addEventListener).toBeCalledWith('focusout', instance.onFocusOut);
        });
        it('handles truthy useExternal', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.useExternal = true;
            jest.spyOn(instance.el, 'addEventListener').mockReturnValue();
            await page.waitForChanges();
            instance.loadFocusEvents();
            expect(instance.el.addEventListener).toBeCalledTimes(0);
        });
    });
    describe('unloadFocusEvents', () => {
        it('sets expected values', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            jest.spyOn(instance.el, 'removeEventListener').mockImplementation(() => { });
            await page.waitForChanges();
            instance.unloadFocusEvents();
            expect(instance.el.removeEventListener).toBeCalledTimes(1);
            expect(instance.el.removeEventListener).toBeCalledWith('focusout', instance.onFocusOut);
        });
    });
    describe('onVinOptionsChange', () => {
        it('handles no options', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            await page.waitForChanges();
            instance.onVinOptionsChange({});
            expect(instance.canSearch).toBeTruthy();
            expect(instance.lastResponse).toBeUndefined();
            expect(instance.configurationOptions).toEqual({});
        });
        it('handles undefined options', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            await page.waitForChanges();
            instance.onVinOptionsChange(undefined);
            expect(instance.canSearch).toBeTruthy();
            expect(instance.lastResponse).toBeUndefined();
            expect(instance.configurationOptions).toEqual({});
        });
        it('handles success', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            await page.waitForChanges();
            const vin = {
                isAvailable: true,
                errorCount: 0,
                lastResponse: {},
            };
            instance.onVinOptionsChange(vin);
            expect(instance.canSearch).toBeTruthy();
            expect(instance.lastResponse).toBe(vin.lastResponse);
        });
        it('handles failure', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            await page.waitForChanges();
            const vin = {
                isAvailable: false,
                errorCount: 0,
                lastResponse: undefined,
            };
            instance.onVinOptionsChange(vin);
            expect(instance.canSearch).toBeFalsy();
            expect(instance.lastResponse).toBe(vin.lastResponse);
        });
    });
    describe('onVinStatusChange', () => {
        it('handles no options', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            await page.waitForChanges();
            instance.onVinStatusChange(undefined);
            expect(instance.vinResource).toEqual(LoadingStates.NotLoaded);
        });
        it('handles success', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            await page.waitForChanges();
            instance.onVinStatusChange(LoadingStates.Loaded);
            expect(instance.vinResource).toEqual(LoadingStates.Loaded);
        });
    });
    describe('onMakeDirty', () => {
        it('should ignore unchanged touched state', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.touched = false;
            instance.pristine = true;
            instance.onMakeDirty();
            expect(instance.touched).toBeTruthy();
            expect(instance.pristine).toBeFalsy();
        });
    });
    describe('updateErrors', () => {
        beforeAll(() => {
            jest.resetAllMocks();
        });
        it('returns required if error determined', async () => {
            jest.spyOn(utils, 'hasRequiredError').mockReturnValue(true);
            const page = await setupPage();
            const instance = setupInstance(page);
            await page.waitForChanges();
            instance.updateErrors(false, false, '');
            expect(instance.errors).toEqual(['required']);
        });
        it('handles valid vin', async () => {
            jest.spyOn(utils, 'hasRequiredError').mockReturnValue(false);
            const page = await setupPage();
            const instance = setupInstance(page);
            await page.waitForChanges();
            const vin = 'KMHCN46C88U271704';
            instance.updateErrors(true, true, vin);
            expect(instance.errors).toEqual([]);
            expect(instance.errorText).toBeUndefined();
        });
        it('handles invalid vin', async () => {
            jest.spyOn(utils, 'hasRequiredError').mockReturnValue(false);
            const page = await setupPage();
            const instance = setupInstance(page);
            await page.waitForChanges();
            const vin = 'KMHCM46C88U271704';
            expect(instance.errorText).toBeUndefined();
            instance.updateErrors(true, true, vin);
            expect(instance.errors).toEqual([]);
            expect(instance.errorText).not.toBeUndefined();
        });
        it('otherwise empty state', async () => {
            jest.spyOn(utils, 'hasRequiredError').mockReturnValue(false);
            const page = await setupPage();
            const instance = setupInstance(page);
            await page.waitForChanges();
            instance.updateErrors(false, false, '');
            expect(instance.errors).toEqual([]);
        });
    });
    describe('onValueUpdate', () => {
        let instance;
        let page;
        const originalValue = '1234';
        beforeEach(async () => {
            page = await setupPage();
            instance = setupInstance(page);
            instance.useExternal = false;
            instance.value = originalValue;
        });
        describe('error state updates', () => {
            beforeEach(() => {
                instance.errors = [];
                instance.errorText = '';
            });
            describe('when an external component is used', () => {
                beforeEach(() => {
                    instance.useExternal = true;
                    instance.onValueUpdate({ detail: '' });
                });
                it('should not update errors', () => {
                    expect(instance.errors).toEqual([]);
                });
                it('should not update error text', () => {
                    expect(instance.errorText).toEqual('');
                });
            });
            describe('when the value has not changed', () => {
                beforeEach(() => {
                    instance.onValueUpdate({ detail: originalValue });
                });
                it('should not update errors', () => {
                    expect(instance.errors).toEqual([]);
                });
                it('should not update error text', () => {
                    expect(instance.errorText).toEqual('');
                });
            });
            describe('when the value is invalid', () => {
                beforeEach(() => {
                    // set to true to force a required error
                    instance.touched = true;
                    instance.onValueUpdate({ detail: '' });
                });
                it('should update errors', () => {
                    expect(instance.errors).toEqual(['required']);
                });
                it('should update error text', () => {
                    expect(instance.errorText.length).toBeGreaterThan(0);
                });
            });
            describe('when the value is valid', () => {
                beforeEach(() => {
                    jest.spyOn(VehicleVinService, 'getValidationErrorMessage').mockReturnValue(undefined);
                    instance.onValueUpdate({ detail: 'vin' });
                });
                it('should not update errors', () => {
                    expect(instance.errors).toEqual([]);
                });
                it('should not update error text', () => {
                    expect(instance.errorText).toBeUndefined();
                });
            });
        });
        describe('pristine state updates', () => {
            beforeEach(() => {
                instance.pristine = true;
            });
            describe('when an external component is used', () => {
                beforeEach(() => {
                    instance.useExternal = true;
                    instance.onValueUpdate({ detail: '' });
                });
                it('should not update pristine', () => {
                    expect(instance.pristine).toEqual(true);
                });
            });
            describe('when the value has not changed', () => {
                beforeEach(() => {
                    instance.onValueUpdate({ detail: originalValue });
                });
                it('should not update pristine', () => {
                    expect(instance.pristine).toEqual(true);
                });
            });
            describe('when the value has changed', () => {
                const newValue = '1FAFP40634F172825';
                beforeEach(() => {
                    instance.onValueUpdate({ detail: newValue });
                });
                it('should mark the component as not pristine', () => {
                    expect(instance.pristine).toEqual(false);
                });
            });
        });
        describe('value updates', () => {
            describe('when an external component is used', () => {
                beforeEach(() => {
                    instance.useExternal = true;
                    instance.onValueUpdate({ detail: '' });
                });
                it('should not update value', () => {
                    expect(instance.value).toEqual(originalValue);
                });
            });
            describe('when the value has not changed', () => {
                beforeEach(() => {
                    instance.onValueUpdate({ detail: originalValue });
                });
                it('should not update value', () => {
                    expect(instance.value).toEqual(originalValue);
                });
            });
            describe('when the value has changed', () => {
                const newValue = '1FAFP40634F172825';
                beforeEach(() => {
                    instance.onValueUpdate({ detail: newValue });
                });
                it('should update the value', () => {
                    expect(instance.value).toEqual(newValue);
                });
            });
        });
        describe('canSave state updates', () => {
            beforeEach(() => {
                instance.canSave = true;
            });
            describe('when an external component is used', () => {
                beforeEach(() => {
                    instance.useExternal = true;
                    instance.onValueUpdate({ detail: '' });
                });
                it('should not update canSave', () => {
                    expect(instance.canSave).toEqual(true);
                });
            });
            describe('when the value has not changed', () => {
                beforeEach(() => {
                    instance.onValueUpdate({ detail: originalValue });
                });
                it('should not update canSave', () => {
                    expect(instance.canSave).toEqual(true);
                });
            });
            describe('when the value is missing', () => {
                beforeEach(() => {
                    // set to true to force a required error
                    instance.touched = true;
                    instance.onValueUpdate({ detail: '' });
                });
                it('should not be able to save', () => {
                    expect(instance.canSave).toEqual(false);
                });
            });
            describe('when the value is invalid', () => {
                beforeEach(() => {
                    jest.spyOn(VehicleVinService, 'getValidationErrorMessage').mockReturnValue('error');
                    instance.onValueUpdate({ detail: '1FAFP40634F0000' });
                });
                it('should not be able to save', () => {
                    expect(instance.canSave).toEqual(false);
                });
            });
            describe('when the value is valid', () => {
                beforeEach(() => {
                    jest.spyOn(VehicleVinService, 'getValidationErrorMessage').mockReturnValue(undefined);
                    instance.canSave = false;
                    instance.onValueUpdate({ detail: '1FAFP40634F172825' });
                });
                it('should be able to save', () => {
                    expect(instance.canSave).toEqual(true);
                });
            });
        });
        describe('events', () => {
            let emitSpy;
            beforeEach(() => {
                emitSpy = jest.spyOn(instance.vinUpdate, 'emit');
            });
            afterAll(() => {
                emitSpy === null || emitSpy === void 0 ? void 0 : emitSpy.mockRestore();
            });
            describe('when an external component is used', () => {
                beforeEach(() => {
                    instance.useExternal = true;
                    instance.onValueUpdate({ detail: '' });
                });
                it('should not emit an event', () => {
                    expect(emitSpy).not.toHaveBeenCalled();
                });
                it('should not update the VIN in the store', () => {
                    expect(instance.loadVin).not.toHaveBeenCalled();
                });
            });
            describe('when the value has not changed', () => {
                beforeEach(() => {
                    instance.onValueUpdate({ detail: originalValue });
                });
                it('should not emit an event', () => {
                    expect(emitSpy).not.toHaveBeenCalled();
                });
                it('should not update the VIN in the store', () => {
                    expect(instance.loadVin).not.toHaveBeenCalled();
                });
            });
            describe('when the value is invalid', () => {
                beforeEach(() => {
                    jest.spyOn(VehicleVinService, 'getValidationErrorMessage').mockReturnValue('error');
                    instance.onValueUpdate({ detail: '1FAFP40634F0000' });
                });
                it('should not emit an event', () => {
                    expect(emitSpy).not.toHaveBeenCalled();
                });
                it('should not update the VIN in the store', () => {
                    expect(instance.loadVin).not.toHaveBeenCalled();
                });
            });
            describe('when the value is valid', () => {
                const validVin = '1FAFP40634F172825';
                beforeEach(() => {
                    jest.spyOn(VehicleVinService, 'getValidationErrorMessage').mockReturnValue(undefined);
                    instance.onValueUpdate({ detail: validVin });
                });
                it('should emit an event', () => {
                    expect(emitSpy).toHaveBeenCalled();
                });
                it('should update the VIN in the store', () => {
                    expect(instance.loadVin).toHaveBeenCalledWith(expect.objectContaining({
                        vin: validVin,
                    }));
                });
            });
        });
    });
    describe('onFocusOut', () => {
        it('sets expected values', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.touched = false;
            instance.onFocusOut();
            expect(instance.touched).toBeTruthy();
        });
    });
    describe('onConfigurationOptionsChange', () => {
        it('handles no options', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            await page.waitForChanges();
            instance.onConfigurationOptionsChange({});
            expect(instance.hasResult).toBeFalsy();
        });
        it('handles success', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            await page.waitForChanges();
            const configs = { test: 'test' };
            instance.onConfigurationOptionsChange(configs);
            expect(instance.hasResult).toBeTruthy();
        });
        it('emits if only one configuration', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            jest.spyOn(instance.ymmcUpdate, 'emit').mockReturnValue(null);
            instance.onConfigurationOptionsChange({ testConfigId: '3dr Hatchback' });
            expect(instance.ymmcUpdate.emit).toHaveBeenCalledWith({ type: 'configuration', value: 'testConfigId' });
        });
        it('does not emit if multiple configurations', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            jest.spyOn(instance.ymmcUpdate, 'emit').mockReturnValue(null);
            instance.onConfigurationOptionsChange({ testConfigId: '3dr Hatchback', testConfigId2: '4dr Sedan' });
            expect(instance.ymmcUpdate.emit).not.toHaveBeenCalled();
        });
        it('does not emit if no configurations', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            jest.spyOn(instance.ymmcUpdate, 'emit').mockReturnValue(null);
            instance.onConfigurationOptionsChange(undefined);
            expect(instance.ymmcUpdate.emit).not.toHaveBeenCalled();
        });
    });
    describe('shouldSelectConfiguration', () => {
        it('should be true if multiple configurations', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.value = 'something';
            instance.configurationOptions = { testConfigId: '3dr Hatchback', testConfigId2: '4dr Sedan' };
            page.waitForChanges();
            expect(instance.shouldSelectConfiguration).toBe(true);
        });
        it('should be false if single configuration', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.value = 'something';
            instance.configurationOptions = { testConfigId: '3dr Hatchback' };
            page.waitForChanges();
            expect(instance.shouldSelectConfiguration).toBe(false);
        });
        it('should be false if no vin searched', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.value = '';
            instance.configurationOptions = { testConfigId: '3dr Hatchback', testConfigId2: '4dr Sedan' };
            instance.configurationOptions = { testConfigId: '3dr Hatchback' };
            page.waitForChanges();
            expect(instance.shouldSelectConfiguration).toBe(false);
        });
    });
    describe('mapStateToProps', () => {
        it('returns an object with the expected keys', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const result = instance.mapStateToProps(fakeStore);
            expect(result).toHaveProperty('configurationOptions');
            expect(result).toHaveProperty('config');
            expect(result).toHaveProperty('vinOptions');
            expect(result).toHaveProperty('vinStatus');
            expect(result).toHaveProperty('answeredBySource');
        });
        it('sets answered by source to consumer', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.answerId = 'testAnswerId';
            const result = instance.mapStateToProps(fakeStore);
            expect(result.answeredBySource).toEqual('Consumer');
        });
    });
    describe('handleSubscriptions', () => {
        it('calls unsubscribe if subscribed', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const unsubscribe = jest.fn();
            instance.storeUnsubscribe = unsubscribe;
            instance.handleSubscriptions();
            expect(unsubscribe).toHaveBeenCalled();
        });
        it('overwrites an existing subscribe function', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const unsubscribe = jest.fn();
            instance.storeUnsubscribe = unsubscribe;
            instance.handleSubscriptions();
            expect(instance.storeUnsubscribe).not.toEqual(unsubscribe);
            expect(instance.storeUnsubscribe).toBeDefined();
        });
        it('subscribes if not subscribed', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.storeUnsubscribe = null;
            instance.handleSubscriptions();
            expect(instance.storeUnsubscribe).not.toBeNull();
        });
        it('subscribes updates mapStateToProps if already has storeUnsubscribe', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const unsubscribe = jest.fn();
            instance.storeUnsubscribe = unsubscribe;
            instance.handleSubscriptions();
            expect(unsubscribe).toHaveBeenCalledTimes(1);
            expect(instance.storeUnsubscribe).not.toEqual(unsubscribe);
        });
    });
    describe('connectedCallback', () => {
        it('makes expected call if root available', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.handleSubscriptions = jest.fn();
            jest.spyOn(instance.el, 'querySelector').mockImplementationOnce(() => ({
                componentOnReady: () => Promise.resolve(true),
            }));
            instance.connectedCallback();
            await page.waitForChanges();
            expect(instance.handleSubscriptions).toBeCalledTimes(1);
        });
    });
});
