import '@testing-library/jest-dom/extend-expect';
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import ShowMoreLess, { Props, TEST_ID, TERM_LESS, TERM_MORE } from '../ShowMoreLess';

describe('<ShowMoreLess>', () => {
    let defaultProps: Props;

    const renderMocked = (props?: Partial<Props>) =>
        render(<ShowMoreLess {...defaultProps} {...props} />);

    beforeEach(() => {
        defaultProps = {
            className: 'TestClass',
            onClick: jest.fn(),
            onLess: jest.fn(),
            onMore: jest.fn(),
        };
    });

    test('renders ShowMoreLess', () => {
        const component = renderMocked();
        const showMoreLessComponent = component.getByTestId(TEST_ID);
        const button = component.getByText(TERM_MORE);
        const chevron = showMoreLessComponent.getElementsByClassName('Icons-down-direction-arrow')[0];

        expect(showMoreLessComponent).toBeVisible();
        expect(button).toBeVisible();
        expect(chevron).toBeVisible();
    });

    test('renders ShowMoreLess with ShowLess option', () => {
        const component = renderMocked({ expanded: true });
        const button = component.getByText(TERM_LESS);
        const chevron = component.container.getElementsByClassName('Icons-up-direction-arrow')[0];

        expect(button).toBeVisible();
        expect(chevron).toBeVisible();
    });

    test('does not render ShowMoreLess if only ShowMore allowed', () => {
        const component = renderMocked({ expanded: true, onlyExpand: true });
        const showMoreLessComponent = component.queryByTestId(TEST_ID);

        expect(showMoreLessComponent).toBeNull();
    });

    test('renders loading indicator if isLoading is true and only ShowMore allowed', () => {
        const { container } = renderMocked({ expanded: true, onlyExpand: true, isLoading: true });
        const loadingIndicator = container.getElementsByClassName('LoadingIndicator')[0];

        expect(loadingIndicator).toBeVisible();
    });

    test('renders loading state', () => {
        const { container } = renderMocked({ isLoading: true });
        const loadingIndicator = container.getElementsByClassName('LoadingIndicator')[0];

        expect(loadingIndicator).toBeVisible();
    });

    describe('with handleClick', () => {
        test('does not call onClick if in loading state', () => {
            const component = renderMocked({ isLoading: true });
            fireEvent.click(component.getByTestId(TEST_ID));

            expect(defaultProps.onClick).toHaveBeenCalledTimes(0);
        });
        test('calls onClick', () => {
            const component = renderMocked();
            fireEvent.click(component.getByTestId(TEST_ID));

            expect(defaultProps.onClick).toHaveBeenCalledTimes(1);
        });
        test('skips call of onClick if not defined', () => {
            const component = renderMocked({ onClick: undefined });
            fireEvent.click(component.getByTestId(TEST_ID));

            expect(defaultProps.onClick).toHaveBeenCalledTimes(0);
        });

        test('calls onMore', () => {
            const component = renderMocked();
            fireEvent.click(component.getByTestId(TEST_ID));

            expect(defaultProps.onMore).toHaveBeenCalledTimes(1);
        });
        test('skips call of onMore if not defined', () => {
            const component = renderMocked({ onMore: undefined });
            fireEvent.click(component.getByTestId(TEST_ID));

            expect(defaultProps.onMore).toHaveBeenCalledTimes(0);
        });

        test('calls onLess', () => {
            const component = renderMocked({ expanded: true });
            fireEvent.click(component.getByTestId(TEST_ID));

            expect(defaultProps.onLess).toHaveBeenCalledTimes(1);
        });
        test('skips call of onLess if not defined', () => {
            const component = renderMocked({ expanded: true, onLess: undefined });
            fireEvent.click(component.getByTestId(TEST_ID));

            expect(defaultProps.onLess).toHaveBeenCalledTimes(0);
        });
    });
});
