import React from 'react'; import { createMemoryHistory, createLocation } from 'history'; import ProjectBrief from 'organisms/ProjectBrief/ProjectBrief'; import { cleanup, render, waitForElement, fireEvent, act, wait } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; import { Provider } from 'react-redux'; import projectApi from 'API/projects'; import productApi from 'API/products'; import * as productActions from 'modules/products/actions'; import { Route, Router, match } from 'react-router'; import configureStore from 'redux-mock-store'; //ES6 modules import { Brand, Category } from 'API/projectData'; import { format } from 'date-fns'; import useCurrentProject from 'hooks/useCurrentProject'; import ReactDOM from 'react-dom'; afterEach(cleanup); const dispatch = jest.fn(); //MOCKED DATA const category: Category = { id: 1, name: 'toys', }; const brand: Brand = { id: 1, name: 'boys', }; const printingFilesDate = '2011-02-01'; const promoDate = '2011-01-01'; const createMockStore = (initialValues: any) => { const mockStore = configureStore(); const store = mockStore({ projectData: { categories: [category], brands: [brand], }, users: { currentUser: { id: 1, organization: { type: 'supplier', }, }, usersList: [], }, projects: { projectsList: [{ ...initialValues }], }, }); return store; }; const routeConfiguration = (path: string, params?: any) => { const history = createMemoryHistory({ initialEntries: [path] }); const match: match = { isExact: true, path, url: path, params: params ? params : {}, }; const location = createLocation(match.url); return { history, match, location }; }; const renderWithProviderAndRoute = (ui: any, { routeOptions, history, store }: any): any => { return { ...render( {ui} ), }; }; describe('new project', () => { const path = `/projects/new`; let { history, match, location } = routeConfiguration(path); beforeEach(() => (history = createMemoryHistory({ initialEntries: [path] }))); const initialValues = { id: 1, slug: 'test', name: 'test', products: 'test', maxProductStage: 'max', published: false, updatedAt: new Date(), createdAt: new Date(), printingFilesDate, publishable: false, description: 'description', category: category.id, brand: brand.id, promoDate, productsAmount: 1, }; const store = createMockStore(initialValues); it('should render blank ProjectBrief on /projects/new ', async () => { const { getByTestId } = renderWithProviderAndRoute( , { routeOptions: { exact: true, path }, history, store } ); const categoryDropdown = await waitForElement(() => getByTestId('categoryDropdown')); const brandDropdown = await waitForElement(() => getByTestId('brandDropdown')); const printingFilesDateField = await waitForElement(() => getByTestId('printingFilesDatePicker')); const promotionDateField = await waitForElement(() => getByTestId('poromoDateDatePicker')); const saveButton = await waitForElement(() => getByTestId('projectSaveButton')); const projectName = await waitForElement(() => getByTestId('projectName')); const description = await waitForElement(() => getByTestId('description')); expect(projectName).toBeInTheDocument(); expect(description).toBeInTheDocument(); expect(printingFilesDateField).toBeInTheDocument(); expect(promotionDateField).toBeInTheDocument(); expect(saveButton).toBeInTheDocument(); expect(brandDropdown).toBeInTheDocument(); expect(categoryDropdown).toBeInTheDocument(); }); it('should allow change form values', async () => { const { findByTestId, findByText, findAllByDisplayValue } = renderWithProviderAndRoute( , { routeOptions: { exact: true, path }, history, store } ); const brandDropdown = await waitForElement(() => findByTestId('brandDropdown')); const categoryDropdown = await waitForElement(() => findByTestId('categoryDropdown')); const projectName = await waitForElement(() => findByTestId('projectName')); const description = await waitForElement(() => findByTestId('description')); const dates = await waitForElement(() => findAllByDisplayValue(format(new Date(), 'yyyy-MM-dd'))); //CHECK IF DATE CHANGED fireEvent.change(dates[0], { target: { value: '2011-02-02' } }); expect(dates[0]).toHaveValue('2011-02-02'); fireEvent.change(dates[1], { target: { value: '2011-02-03' } }); expect(dates[1]).toHaveValue('2011-02-03'); //CHECK IF PROJECT NAME CHANGED fireEvent.change(projectName, { target: { value: 'projectName' } }); expect(projectName).toHaveValue('projectName'); //CHECK IF DESCRIPTION CHANGED fireEvent.change(description, { target: { value: 'description' } }); expect(description).toHaveValue('description'); //CHECK IF BRAND DROPDOWN VALUE CHANGED const brandValue = await waitForElement(() => findByTestId('brandValue')); expect(brandValue.innerHTML).toEqual('Marka'); fireEvent.click(brandDropdown); const brandItem = await waitForElement(() => findByText(brand.name)); expect(brandItem.innerHTML).toEqual(brand.name); fireEvent.click(brandItem); expect(brandValue.innerHTML).toEqual(brandItem.innerHTML); //CHECK IF CATEGORY DROPDOWN VALUE CHANGED const categoryValue = await waitForElement(() => findByTestId('categoryValue')); expect(categoryValue.innerHTML).toEqual('Kategoria'); fireEvent.click(categoryDropdown); const categoryItem = await waitForElement(() => findByText(category.name)); expect(categoryItem.innerHTML).toEqual(category.name); fireEvent.click(categoryItem); expect(categoryValue.innerHTML).toEqual(categoryItem.innerHTML); }); it('publish button should not be visible if publishabled is false', async () => { const { queryByTestId } = renderWithProviderAndRoute( , { routeOptions: { exact: true, path }, history, store } ); expect(queryByTestId('publishButton')).toBe(null); }); it('should not submit blank form', async () => { const { findByTestId, queryAllByTestId } = renderWithProviderAndRoute( , { routeOptions: { exact: true, path }, history, store } ); await act(async () => { const saveButton = await waitForElement(() => findByTestId('projectSaveButton')); fireEvent.click(saveButton); }); const errors = queryAllByTestId('inputError'); expect(errors).toHaveLength(5); }); it('should save proper form and redirect to /products/${pid}', async () => { projectApi.createNewProject.mockReturnValueOnce({ id: 1, }); productApi.getProductsByURL.mockReturnValueOnce([ { id: 1, }, ]); const { findByTestId, queryAllByTestId } = renderWithProviderAndRoute( , { routeOptions: { exact: true, path }, history, store } ); const saveButton = await waitForElement(() => findByTestId('projectSaveButton')); await act(async () => { fireEvent.click(saveButton); const errors = queryAllByTestId('inputError'); expect(errors).toHaveLength(0); }); expect(projectApi.createNewProject).toHaveBeenCalledTimes(1); expect(productApi.getProductsByURL).toHaveBeenCalledTimes(1); expect(history.location.pathname).toBe('/projects/1/products/1'); }); it('should setCurrentStage to 0', () => { const spy = jest.spyOn(productActions, 'setCurrentStage'); renderWithProviderAndRoute( , { routeOptions: { exact: true, path: '/projects/new' }, history, store } ); expect(spy).toHaveBeenCalledWith(0); expect(spy).toHaveBeenCalledTimes(1); }); }); describe('existing project not publishable', () => { const path = `/projects/1`; const { history, match, location } = routeConfiguration(path, { id: 1 }); const initialValues = { id: 1, slug: 'test', name: 'test', products: 'test', maxProductStage: 'max', published: false, updatedAt: new Date(), createdAt: new Date(), printingFilesDate, publishable: false, description: 'description', category: category.id, brand: brand.id, promoDate, productsAmount: 1, }; const store = createMockStore(initialValues); it('should set initial values', async () => { const { getByTestId, findByDisplayValue } = renderWithProviderAndRoute( , { routeOptions: { exact: true, path }, history, store } ); const projectName = await waitForElement(() => getByTestId('projectName')); const projectDesc = await waitForElement(() => getByTestId('description')); const categoryValue = await waitForElement(() => getByTestId('categoryValue')); const brandValue = await waitForElement(() => getByTestId('brandValue')); const promoDate = await waitForElement(() => findByDisplayValue(initialValues.printingFilesDate)); const pfDate = await waitForElement(() => findByDisplayValue(initialValues.promoDate)); expect(promoDate).toHaveValue(initialValues.printingFilesDate); expect(pfDate).toHaveValue(initialValues.promoDate); expect(categoryValue.innerHTML).toBe(category.name); expect(brandValue.innerHTML).toBe(brand.name); expect(projectName).toHaveValue(initialValues.name); expect(projectDesc).toHaveValue(initialValues.description); //TODO HOW TO CHECK FORMIK VALUES }); it('should expand dropdown', async () => { const { getByTestId } = renderWithProviderAndRoute( , { routeOptions: { exact: true, path }, history, store } ); const brand = await waitForElement(() => getByTestId('brandDropdown')); const category = await waitForElement(() => getByTestId('categoryDropdown')); fireEvent.click(brand); fireEvent.click(category); expect(brand).toHaveClass('is-active'); expect(category).toHaveClass('is-active'); }); }); describe('existing project publishable', () => { beforeAll(() => { ReactDOM.createPortal = jest.fn((element, node) => { return element; }); }); afterEach(() => { ReactDOM.createPortal.mockClear(); }); const path = `/projects/1`; const { history, match, location } = routeConfiguration(path, { id: 1 }); const initialValues = { id: 1, slug: 'test', name: 'test', products: 'test', maxProductStage: 'max', published: false, updatedAt: new Date(), createdAt: new Date(), printingFilesDate, publishable: true, description: 'description', category: category.id, brand: brand.id, promoDate, productsAmount: 1, }; const store = createMockStore(initialValues); it('publish button should be in DOM but disabled', async () => { useCurrentProject.mockReturnValue({ ...initialValues, publishable: false }); const { findByTestId } = renderWithProviderAndRoute( , { routeOptions: { exact: true, path }, history, store } ); const publishButton = await waitForElement(() => findByTestId('publishButton')); expect(publishButton).toBeInTheDocument(); expect(publishButton).toBeDisabled(); }); it('publish button should be in DOM and not disabled', async () => { useCurrentProject.mockReturnValue(initialValues); const { findByTestId } = renderWithProviderAndRoute( , { routeOptions: { exact: true, path }, history, store } ); const publishButton = await waitForElement(() => findByTestId('publishButton')); expect(publishButton).toBeInTheDocument(); expect(publishButton).not.toBeDisabled(); }); it('should open modal and spin spinner', async () => { projectApi.publishProject.mockReturnValueOnce({ ...initialValues, published: true }); useCurrentProject.mockReturnValue(initialValues); productApi.getProductsByURL.mockReturnValueOnce([ { id: 1, }, ]); const { findByTestId, findByText } = renderWithProviderAndRoute( , { routeOptions: { exact: true, path }, history, store } ); const publishButton = await waitForElement(() => findByTestId('publishButton')); expect(publishButton).toBeInTheDocument(); await act(async () => { fireEvent.click(publishButton); }); const modal = await waitForElement(() => findByText('Publikacja projektu')); const modalCancel = await waitForElement(() => findByTestId('modalCancel')); const modalSubmit = await waitForElement(() => findByTestId('modalSubmit')); expect(modal).toBeInTheDocument(); expect(modalSubmit).toBeInTheDocument(); expect(modalCancel).toBeInTheDocument(); fireEvent.click(modalSubmit); expect(modalSubmit).toHaveClass('is-loading'); await wait(() => expect(modalSubmit).not.toHaveClass('is-loading')); expect(modal).not.toBeInTheDocument(); }); describe('Published Project', () => { const path = `/projects/1`; const { history, match, location } = routeConfiguration(path, { id: 1 }); const initialValues = { id: 1, slug: 'test', name: 'test', products: 'test', maxProductStage: 'max', published: true, updatedAt: new Date(), createdAt: new Date(), printingFilesDate, publishable: false, description: 'description', category: category.id, brand: brand.id, promoDate, productsAmount: 1, }; const store = createMockStore(initialValues); it('should not display publish button when published is true', async () => { useCurrentProject.mockReturnValue(initialValues); const { queryByTestId } = renderWithProviderAndRoute( , { routeOptions: { exact: true, path }, history, store } ); expect(queryByTestId('publishButton')).toBe(null); }); it('should have disabled fields', async () => { useCurrentProject.mockReturnValue(initialValues); const { findByText, findByTestId, findByDisplayValue } = renderWithProviderAndRoute( , { routeOptions: { exact: true, path }, history, store } ); const brandValue = await waitForElement(() => findByTestId('brandValue')); const categoryValue = await waitForElement(() => findByTestId('categoryValue')); const projectName = await waitForElement(() => findByTestId('projectName')); const description = await waitForElement(() => findByTestId('description')); const promo = await waitForElement(() => findByDisplayValue(promoDate)); const pfDate = await waitForElement(() => findByDisplayValue(printingFilesDate)); expect(categoryValue.parentElement).toBeDisabled(); expect(brandValue.parentElement).toBeDisabled(); expect(promo).toBeDisabled(); expect(pfDate).toBeDisabled(); expect(projectName).toBeDisabled(); expect(description).toBeDisabled(); }); }); });