| import * as redux from "react-redux"; | |||||
| import store from "../../store"; | |||||
| import { Router } from "react-router-dom"; | |||||
| import history from "../../store/utils/history"; | |||||
| import { mockState } from "../../mockState"; | |||||
| import { render } from "@testing-library/react"; | |||||
| import * as api from "../../request/candidatesRequest"; | |||||
| import { runSaga } from "redux-saga"; | |||||
| import { CANDIDATE_FETCH } from "../../store/actions/candidate/candidateActionConstants"; | |||||
| import { FETCH_USERS_REQ } from "../../store/actions/users/usersActionConstants"; | |||||
| import { getSingleCandidate } from "../../store/saga/candidatesSaga"; | |||||
| import { | |||||
| fetchCandidateSuccess, | |||||
| fetchCandidateError, | |||||
| } from "../../store/actions/candidate/candidateActions"; | |||||
| import * as helper from "../../util/helpers/rejectErrorCodeHelper"; | |||||
| import CandidateDetailsPage from "../../pages/CandidatesPage/CandidateDetailsPage"; | |||||
| const mockHistoryPush = jest.fn(); | |||||
| // mock param which we send as part of URL | |||||
| jest.mock("react-router-dom", () => ({ | |||||
| ...jest.requireActual("react-router-dom"), | |||||
| useHistory: () => ({ | |||||
| push: mockHistoryPush, | |||||
| }), | |||||
| useParams: () => ({ | |||||
| id: 1, | |||||
| }), | |||||
| })); | |||||
| describe("CandidateDetailsPage render tests", () => { | |||||
| var props = { | |||||
| history: { | |||||
| replace: jest.fn(), | |||||
| push: jest.fn(), | |||||
| location: { | |||||
| pathname: "", | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <CandidateDetailsPage {...props} /> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector | |||||
| .mockReturnValueOnce(mockState.users.users) | |||||
| .mockReturnValueOnce(mockState.users.user) | |||||
| .mockReturnValueOnce(mockState.candidate.candidate); | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| // Mock dispatch function returned from useDispatch | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should dispatch fetch candidate request when rendered", () => { | |||||
| render(cont); | |||||
| expect(mockDispatch).toHaveBeenCalledWith({ | |||||
| payload: { id: 1 }, | |||||
| type: CANDIDATE_FETCH, | |||||
| }); | |||||
| }); | |||||
| it("Should dispatch fetch users request when rendered", () => { | |||||
| render(cont); | |||||
| expect(mockDispatch).toHaveBeenCalledWith({ | |||||
| type: FETCH_USERS_REQ, | |||||
| }); | |||||
| }); | |||||
| it("should load and handle candidate in case of success", async () => { | |||||
| const dispatchedActions = []; | |||||
| helper.rejectErrorCodeHelper = jest.fn(() => "Server error"); | |||||
| const mockedCall = { data: mockState.candidate.candidate }; | |||||
| api.getCandidate = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.candidate.candidate, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getSingleCandidate, { payload: { id: 1 } }).done; | |||||
| expect(api.getCandidate.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| fetchCandidateSuccess(mockedCall.data) | |||||
| ); | |||||
| }); | |||||
| it("should handle candidate load errors in case of failure", async () => { | |||||
| const dispatchedActions = []; | |||||
| helper.rejectErrorCodeHelper = jest.fn( | |||||
| () => mockState.candidate.fetchCandidateErrorMessage | |||||
| ); | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: mockState.candidate.fetchCandidateErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api.getCandidate = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.candidate.candidate, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getSingleCandidate, { payload: { id: 1 } }).done; | |||||
| expect(api.getCandidate.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| fetchCandidateError(error.response.data.message) | |||||
| ); | |||||
| }); | |||||
| }); |
| let mockDispatch; | let mockDispatch; | ||||
| beforeEach(() => { | beforeEach(() => { | ||||
| // Mock useSelector hook | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | spyOnUseSelector = jest.spyOn(redux, "useSelector"); | ||||
| spyOnUseSelector.mockReturnValueOnce(mockState.technologies.technologies); | spyOnUseSelector.mockReturnValueOnce(mockState.technologies.technologies); | ||||
| // Mock useDispatch hook | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | ||||
| // Mock dispatch function returned from useDispatch | |||||
| mockDispatch = jest.fn(); | mockDispatch = jest.fn(); | ||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | spyOnUseDispatch.mockReturnValue(mockDispatch); | ||||
| }); | }); |
| filterCandidatesError, | filterCandidatesError, | ||||
| } from "../../store/actions/candidates/candidatesActions"; | } from "../../store/actions/candidates/candidatesActions"; | ||||
| import { PAGE_SIZE_CANDIDATES } from "../../constants/keyCodeConstants"; | import { PAGE_SIZE_CANDIDATES } from "../../constants/keyCodeConstants"; | ||||
| import * as helper from "../../util/helpers/rejectErrorCodeHelper"; | |||||
| describe("TableViewPage render tests", () => { | describe("TableViewPage render tests", () => { | ||||
| const cont = ( | const cont = ( | ||||
| ); | ); | ||||
| }); | }); | ||||
| // it("should handle candidates load errors in case of failure", async () => { | |||||
| // const dispatchedActions = []; | |||||
| it("should handle technologies load errors in case of failure", async () => { | |||||
| const dispatchedActions = []; | |||||
| helper.rejectErrorCodeHelper = jest.fn( | |||||
| () => mockState.candidates.fetchCandidatesErrorMessage | |||||
| ); | |||||
| // const error = { | |||||
| // response: { | |||||
| // data: { message: mockState.candidates.fetchCandidatesErrorMessage }, | |||||
| // }, | |||||
| // }; | |||||
| // api.getFilteredCandidates = jest.fn(() => Promise.reject(error)); | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: mockState.candidates.fetchCandidatesErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api.getFilteredCandidates = jest.fn(() => Promise.reject(error)); | |||||
| // const fakeStore = { | |||||
| // getState: () => mockState.candidates.items, | |||||
| // dispatch: (action) => dispatchedActions.push(action), | |||||
| // }; | |||||
| const fakeStore = { | |||||
| getState: () => mockState.candidates.candidates, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // await runSaga(fakeStore, fc.filterCandidates, {}).done; | |||||
| await runSaga(fakeStore, fc.filterCandidates, {}).done; | |||||
| // expect(api.getFilteredCandidates.mock.calls.length).toBe(1); | |||||
| // expect(dispatchedActions).toContainEqual( | |||||
| // filterCandidatesError(error.response.data.message) | |||||
| // ); | |||||
| // }); | |||||
| expect(api.getFilteredCandidates.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| filterCandidatesError(error.response.data.message) | |||||
| ); | |||||
| }); | |||||
| }); | }); |
| import { render } from "@testing-library/react"; | |||||
| import { render, fireEvent } from "@testing-library/react"; | |||||
| import * as redux from "react-redux"; | import * as redux from "react-redux"; | ||||
| import store from "../../store"; | import store from "../../store"; | ||||
| import { mockState } from "../../mockState"; | import { mockState } from "../../mockState"; | ||||
| import AdsCandidatesPage from "../../pages/CandidatesPage/AdsCandidatesPage"; | import AdsCandidatesPage from "../../pages/CandidatesPage/AdsCandidatesPage"; | ||||
| describe("TableViewPage render tests", () => { | describe("TableViewPage render tests", () => { | ||||
| var props = { | |||||
| history: { | |||||
| replace: jest.fn(), | |||||
| push: jest.fn(), | |||||
| location: { | |||||
| pathname: "/candidates", | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| const cont = ( | const cont = ( | ||||
| <redux.Provider store={store}> | <redux.Provider store={store}> | ||||
| <Router history={history}> | <Router history={history}> | ||||
| <AdsCandidatesPage search="" /> | |||||
| <AdsCandidatesPage search="" {...props} /> | |||||
| </Router> | </Router> | ||||
| </redux.Provider> | </redux.Provider> | ||||
| ); | ); | ||||
| ).toBeDefined(); | ).toBeDefined(); | ||||
| }); | }); | ||||
| it("Number of sliders should be equal to length of our array adsCandidates", () => { | |||||
| it("Number of sliders should be equal to length of our adsCandidates array", () => { | |||||
| const { container } = render(cont); | const { container } = render(cont); | ||||
| expect(container.getElementsByClassName("ads-candidates").length).toBe( | expect(container.getElementsByClassName("ads-candidates").length).toBe( | ||||
| mockState.candidates.adsCandidates.length | mockState.candidates.adsCandidates.length | ||||
| container.getElementsByClassName("active-ads-ads-arrows").length | container.getElementsByClassName("active-ads-ads-arrows").length | ||||
| ).toBe(0); | ).toBe(0); | ||||
| }); | }); | ||||
| it("Should render candidate details page", () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click( | |||||
| container.getElementsByClassName("candidate-card-container")[0] | |||||
| ); | |||||
| const arg = { pathname: "/candidates/1" }; | |||||
| expect(props.history.push).toHaveBeenCalledWith(arg); | |||||
| }); | |||||
| }); | }); |
| import { render, fireEvent, screen } from "@testing-library/react"; | |||||
| import * as redux from "react-redux"; | |||||
| import store from "../../store"; | |||||
| import { mockState } from "../../mockState"; | |||||
| import { Router } from "react-router-dom"; | |||||
| import history from "../../store/utils/history"; | |||||
| import CandidateDetailsPage from "../../pages/CandidatesPage/CandidateDetailsPage"; | |||||
| describe("CandidateDetailsPage render tests", () => { | |||||
| var props = { | |||||
| history: { | |||||
| replace: jest.fn(), | |||||
| push: jest.fn(), | |||||
| location: { | |||||
| pathname: "/candidates/1", | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <CandidateDetailsPage {...props} /> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector | |||||
| .mockReturnValueOnce(mockState.users.users) | |||||
| .mockReturnValueOnce(mockState.users.user) | |||||
| .mockReturnValueOnce(mockState.candidate.candidate) | |||||
| .mockReturnValueOnce(mockState.users.users) | |||||
| .mockReturnValueOnce(mockState.users.user) | |||||
| .mockReturnValueOnce(mockState.candidate.candidate); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should render", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("main-candidate-container")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should render button for deleting candidate", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("candidate-btn")[0]).toBeDefined(); | |||||
| }); | |||||
| it("Should render dialog after clicking button for deleting candidate", () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click(container.getElementsByClassName("candidate-btn")[0]); | |||||
| expect(screen.getByTestId("alert-container")).toBeDefined(); | |||||
| }); | |||||
| it("Should render div for sending comment", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("comment-container")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should render button for downloading CV", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("applicant-cv-button")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should render two ads for candidate", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("applicant-add").length).toBe(2); | |||||
| }); | |||||
| it("Should render three comments", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("comment-sub-container").length | |||||
| ).toBe(3); | |||||
| }); | |||||
| it("Should render page with all candidates", () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click( | |||||
| container.getElementsByClassName("applicant-ads-back-button")[0] | |||||
| ); | |||||
| const arg = { pathname: "/candidates" }; | |||||
| expect(props.history.push).toHaveBeenCalledWith(arg); | |||||
| }); | |||||
| }); |
| line-height: 20px; | line-height: 20px; | ||||
| text-decoration-line: underline; | text-decoration-line: underline; | ||||
| color: #226cb0; | color: #226cb0; | ||||
| cursor: pointer; | |||||
| } | } | ||||
| .tagStyle { | .tagStyle { |
| const navigateToDetailsPage = () => { | const navigateToDetailsPage = () => { | ||||
| history.push({ | history.push({ | ||||
| pathname: CANDIDATES_PAGE + "/" + candidate.applicantId, | pathname: CANDIDATES_PAGE + "/" + candidate.applicantId, | ||||
| state: { | |||||
| from: history.location.pathname, | |||||
| }, | |||||
| }); | }); | ||||
| }; | }; | ||||
| import React from "react"; | import React from "react"; | ||||
| import { useEffect, useState, useRef } from "react"; | import { useEffect, useState, useRef } from "react"; | ||||
| import { Link, useParams } from "react-router-dom"; | |||||
| import { useParams } from "react-router-dom"; | |||||
| import deleteImage from "../../../src/assets/images/delete.png"; | import deleteImage from "../../../src/assets/images/delete.png"; | ||||
| import planeImage from "../../../src/assets/images/planeVectorBlue.png"; | import planeImage from "../../../src/assets/images/planeVectorBlue.png"; | ||||
| import IconButton from "../../components/IconButton/IconButton"; | import IconButton from "../../components/IconButton/IconButton"; | ||||
| } | } | ||||
| }; | }; | ||||
| const goToPageWithAllCandidates = () => { | |||||
| history.push({ | |||||
| pathname: "/candidates", | |||||
| }); | |||||
| }; | |||||
| return (candidate && Object.keys(candidate).length === 0) || | return (candidate && Object.keys(candidate).length === 0) || | ||||
| user === undefined ? ( | user === undefined ? ( | ||||
| <p>Loading...</p> | <p>Loading...</p> | ||||
| > | > | ||||
| <p className="candidate-property-value">{candidate.email}</p> | <p className="candidate-property-value">{candidate.email}</p> | ||||
| <p className="candidate-property-value"> | <p className="candidate-property-value"> | ||||
| {candidate.phoneNumber} | |||||
| {candidate.phoneNumber === "" ? "/" : candidate.phoneNumber} | |||||
| </p> | </p> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| className="candidate-property-container" | className="candidate-property-container" | ||||
| > | > | ||||
| <p className="candidate-property-value"> | <p className="candidate-property-value"> | ||||
| {candidate.linkedlnLink ?? "/"} | |||||
| {candidate.linkedlnLink === "" ? "/" : candidate.linkedlnLink} | |||||
| </p> | </p> | ||||
| <p className="candidate-property-value"> | <p className="candidate-property-value"> | ||||
| {candidate.gitHubLink ?? "/"} | |||||
| {candidate.githubLink === "" ? "/" : candidate.githubLink} | |||||
| </p> | </p> | ||||
| <p className="candidate-property-value"> | <p className="candidate-property-value"> | ||||
| {candidate.bitBucketLink ?? "/"} | |||||
| {candidate.bitBucketLink === "" | |||||
| ? "/" | |||||
| : candidate.bitBucketLink} | |||||
| </p> | </p> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className="applicant-ads-buttons-container"> | <div className="applicant-ads-buttons-container"> | ||||
| <Link to="/candidates" className="applicant-ads-back-button"> | |||||
| <p | |||||
| to="/candidates" | |||||
| className="applicant-ads-back-button" | |||||
| onClick={goToPageWithAllCandidates} | |||||
| > | |||||
| Nazad na sve kandidate | Nazad na sve kandidate | ||||
| </Link> | |||||
| </p> | |||||
| <a | <a | ||||
| className="applicant-cv-button" | className="applicant-cv-button" | ||||
| download={candidate.firstName + candidate.lastName + ".pdf"} | download={candidate.firstName + candidate.lastName + ".pdf"} |