Bladeren bron

Merge branch 'feature/unit_tests_candidate_details_page-fe' of Neca/HRCenter into FE_dev

pull/155/head
safet.purkovic 3 jaren geleden
bovenliggende
commit
f201f72588

+ 133
- 0
src/__tests__/ReduxTests/candidateDetailsPageReducer.test.js Bestand weergeven

@@ -0,0 +1,133 @@
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)
);
});
});

+ 0
- 3
src/__tests__/ReduxTests/candidatesPageReducer.test.js Bestand weergeven

@@ -29,13 +29,10 @@ describe("CandidatesPage render tests", () => {
let mockDispatch;

beforeEach(() => {
// Mock useSelector hook
spyOnUseSelector = jest.spyOn(redux, "useSelector");
spyOnUseSelector.mockReturnValueOnce(mockState.technologies.technologies);
// Mock useDispatch hook
spyOnUseDispatch = jest.spyOn(redux, "useDispatch");

// Mock dispatch function returned from useDispatch
mockDispatch = jest.fn();
spyOnUseDispatch.mockReturnValue(mockDispatch);
});

+ 23
- 18
src/__tests__/ReduxTests/tableViewPageReducer.test.js Bestand weergeven

@@ -15,6 +15,7 @@ import {
filterCandidatesError,
} from "../../store/actions/candidates/candidatesActions";
import { PAGE_SIZE_CANDIDATES } from "../../constants/keyCodeConstants";
import * as helper from "../../util/helpers/rejectErrorCodeHelper";

describe("TableViewPage render tests", () => {
const cont = (
@@ -80,26 +81,30 @@ describe("TableViewPage render tests", () => {
);
});

// 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)
);
});
});

+ 22
- 3
src/__tests__/UITests/adsCandidatesPageUI.test.js Bestand weergeven

@@ -1,4 +1,4 @@
import { render } from "@testing-library/react";
import { render, fireEvent } from "@testing-library/react";
import * as redux from "react-redux";
import store from "../../store";
import { mockState } from "../../mockState";
@@ -7,10 +7,20 @@ import history from "../../store/utils/history";
import AdsCandidatesPage from "../../pages/CandidatesPage/AdsCandidatesPage";

describe("TableViewPage render tests", () => {
var props = {
history: {
replace: jest.fn(),
push: jest.fn(),
location: {
pathname: "/candidates",
},
},
};

const cont = (
<redux.Provider store={store}>
<Router history={history}>
<AdsCandidatesPage search="" />
<AdsCandidatesPage search="" {...props} />
</Router>
</redux.Provider>
);
@@ -33,7 +43,7 @@ describe("TableViewPage render tests", () => {
).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);
expect(container.getElementsByClassName("ads-candidates").length).toBe(
mockState.candidates.adsCandidates.length
@@ -46,4 +56,13 @@ describe("TableViewPage render tests", () => {
container.getElementsByClassName("active-ads-ads-arrows").length
).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);
});
});

+ 97
- 0
src/__tests__/UITests/candidateDetailsPageUI.test.js Bestand weergeven

@@ -0,0 +1,97 @@
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);
});
});

+ 1
- 0
src/assets/styles/components/_candidatePage.scss Bestand weergeven

@@ -392,6 +392,7 @@
line-height: 20px;
text-decoration-line: underline;
color: #226cb0;
cursor: pointer;
}

.tagStyle {

+ 0
- 3
src/components/Candidates/CandidateCard.js Bestand weergeven

@@ -7,9 +7,6 @@ const CandidateCard = ({ candidate, className, history }) => {
const navigateToDetailsPage = () => {
history.push({
pathname: CANDIDATES_PAGE + "/" + candidate.applicantId,
state: {
from: history.location.pathname,
},
});
};


+ 19
- 7
src/pages/CandidatesPage/CandidateDetailsPage.js Bestand weergeven

@@ -1,6 +1,6 @@
import React 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 planeImage from "../../../src/assets/images/planeVectorBlue.png";
import IconButton from "../../components/IconButton/IconButton";
@@ -204,6 +204,12 @@ const CandidateDetailsPage = ({ history }) => {
}
};

const goToPageWithAllCandidates = () => {
history.push({
pathname: "/candidates",
});
};

return (candidate && Object.keys(candidate).length === 0) ||
user === undefined ? (
<p>Loading...</p>
@@ -267,7 +273,7 @@ const CandidateDetailsPage = ({ history }) => {
>
<p className="candidate-property-value">{candidate.email}</p>
<p className="candidate-property-value">
{candidate.phoneNumber}
{candidate.phoneNumber === "" ? "/" : candidate.phoneNumber}
</p>
</div>
</div>
@@ -283,13 +289,15 @@ const CandidateDetailsPage = ({ history }) => {
className="candidate-property-container"
>
<p className="candidate-property-value">
{candidate.linkedlnLink ?? "/"}
{candidate.linkedlnLink === "" ? "/" : candidate.linkedlnLink}
</p>
<p className="candidate-property-value">
{candidate.gitHubLink ?? "/"}
{candidate.githubLink === "" ? "/" : candidate.githubLink}
</p>
<p className="candidate-property-value">
{candidate.bitBucketLink ?? "/"}
{candidate.bitBucketLink === ""
? "/"
: candidate.bitBucketLink}
</p>
</div>
</div>
@@ -435,9 +443,13 @@ const CandidateDetailsPage = ({ history }) => {
</div>
</div>
<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
</Link>
</p>
<a
className="applicant-cv-button"
download={candidate.firstName + candidate.lastName + ".pdf"}

Laden…
Annuleren
Opslaan