diff --git a/src/__mocks__/store.js b/src/__mocks__/store.js index 396202d5e..2ada7f03b 100644 --- a/src/__mocks__/store.js +++ b/src/__mocks__/store.js @@ -1,21 +1,20 @@ -export default { - get: () => { - return Promise.resolve({ - data: [{ - "id": "47qAXb6fIm2zOKkLzMro", - "vat": "80", - "fileUrl": "https://test.storage.tld/v0/b/billable-677b6.a…f-1.jpg?alt=media&token=c1640e12-a24b-4b11-ae52-529112e9602a", - "status": "pending", - "type": "Hôtel et logement", - "commentary": "séminaire billed", - "name": "encore", - "fileName": "preview-facture-free-201801-pdf-1.jpg", - "date": "2004-04-04", - "amount": 400, - "commentAdmin": "ok", - "email": "a@a", - "pct": 20 - }, +const mockedBills = { + list() { + return Promise.resolve([{ + "id": "47qAXb6fIm2zOKkLzMro", + "vat": "80", + "fileUrl": "https://test.storage.tld/v0/b/billable-677b6.a…f-1.jpg?alt=media&token=c1640e12-a24b-4b11-ae52-529112e9602a", + "status": "pending", + "type": "Hôtel et logement", + "commentary": "séminaire billed", + "name": "encore", + "fileName": "preview-facture-free-201801-pdf-1.jpg", + "date": "2004-04-04", + "amount": 400, + "commentAdmin": "ok", + "email": "a@a", + "pct": 20 + }, { "id": "BeKy5Mo4jkmdfPGYpTxZ", "vat": "", @@ -60,7 +59,35 @@ export default { "commentary": "test2", "type": "Restaurants et bars", "fileUrl": "https://test.storage.tld/v0/b/billable-677b6.a…f-1.jpg?alt=media&token=4df6ed2c-12c8-42a2-b013-346c1346f732" - }] + }]) + + }, + create(bill) { + return Promise.resolve({fileUrl: 'https://localhost:3456/images/test.jpg', key: '1234'}) + }, + update(bill) { + return Promise.resolve({ + "id": "47qAXb6fIm2zOKkLzMro", + "vat": "80", + "fileUrl": "https://firebasestorage.googleapis.com/v0/b/billable-677b6.a…f-1.jpg?alt=media&token=c1640e12-a24b-4b11-ae52-529112e9602a", + "status": "pending", + "type": "Hôtel et logement", + "commentary": "séminaire billed", + "name": "encore", + "fileName": "preview-facture-free-201801-pdf-1.jpg", + "date": "2004-04-04", + "amount": 400, + "commentAdmin": "ok", + "email": "a@a", + "pct": 20 }) - } + }, +} + +export default { + bills() { + return mockedBills + //return {} + }, } + diff --git a/src/__tests__/Bills.js b/src/__tests__/Bills.js index 29ca2df68..e771f67e7 100644 --- a/src/__tests__/Bills.js +++ b/src/__tests__/Bills.js @@ -2,20 +2,34 @@ * @jest-environment jsdom */ -import { screen } from "@testing-library/dom" +import {screen, waitFor} from "@testing-library/dom" import BillsUI from "../views/BillsUI.js" import { bills } from "../fixtures/bills.js" +import { ROUTES_PATH} from "../constants/routes.js"; +import {localStorageMock} from "../__mocks__/localStorage.js"; + +import router from "../app/Router.js"; describe("Given I am connected as an employee", () => { describe("When I am on Bills Page", () => { - test("Then bill icon in vertical layout should be highlighted", () => { - const html = BillsUI({ data: []}) - document.body.innerHTML = html + test("Then bill icon in vertical layout should be highlighted", async () => { + + Object.defineProperty(window, 'localStorage', { value: localStorageMock }) + window.localStorage.setItem('user', JSON.stringify({ + type: 'Employee' + })) + const root = document.createElement("div") + root.setAttribute("id", "root") + document.body.append(root) + router() + window.onNavigate(ROUTES_PATH.Bills) + await waitFor(() => screen.getByTestId('icon-window')) + const windowIcon = screen.getByTestId('icon-window') //to-do write expect expression + }) test("Then bills should be ordered from earliest to latest", () => { - const html = BillsUI({ data: bills }) - document.body.innerHTML = html + document.body.innerHTML = BillsUI({ data: bills }) const dates = screen.getAllByText(/^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$/i).map(a => a.innerHTML) const antiChrono = (a, b) => ((a < b) ? 1 : -1) const datesSorted = [...dates].sort(antiChrono) diff --git a/src/__tests__/Dashboard.js b/src/__tests__/Dashboard.js index 409553496..22be98d66 100644 --- a/src/__tests__/Dashboard.js +++ b/src/__tests__/Dashboard.js @@ -2,16 +2,18 @@ * @jest-environment jsdom */ -import { fireEvent, screen } from "@testing-library/dom" +import {fireEvent, screen, waitFor} from "@testing-library/dom" import userEvent from '@testing-library/user-event' import DashboardFormUI from "../views/DashboardFormUI.js" import DashboardUI from "../views/DashboardUI.js" import Dashboard, { filteredBills, cards } from "../containers/Dashboard.js" -import { ROUTES } from "../constants/routes" +import { ROUTES, ROUTES_PATH } from "../constants/routes" import { localStorageMock } from "../__mocks__/localStorage.js" -import store from "../__mocks__/store" +import mockStore from "../__mocks__/store" import { bills } from "../fixtures/bills" +import router from "../app/Router" +jest.mock("../app/store", () => mockStore) describe('Given I am connected as an Admin', () => { describe('When I am on Dashboard page, there are bills, and there is one pending', () => { @@ -34,21 +36,19 @@ describe('Given I am connected as an Admin', () => { }) describe('When I am on Dashboard page but it is loading', () => { test('Then, Loading page should be rendered', () => { - const html = DashboardUI({ loading: true }) - document.body.innerHTML = html + document.body.innerHTML = DashboardUI({ loading: true }) expect(screen.getAllByText('Loading...')).toBeTruthy() }) }) describe('When I am on Dashboard page but back-end send an error message', () => { test('Then, Error page should be rendered', () => { - const html = DashboardUI({ error: 'some error message' }) - document.body.innerHTML = html + document.body.innerHTML = DashboardUI({ error: 'some error message' }) expect(screen.getAllByText('Erreur')).toBeTruthy() }) }) describe('When I am on Dashboard page and I click on arrow', () => { - test('Then, tickets list should be unfolding, and cars should contain first and lastname', async () => { + test('Then, tickets list should be unfolding, and cards should appear', async () => { const onNavigate = (pathname) => { document.body.innerHTML = ROUTES({ pathname }) @@ -60,11 +60,9 @@ describe('Given I am connected as an Admin', () => { })) const dashboard = new Dashboard({ - document, onNavigate, store: null, bills, localStorage: window.localStorage + document, onNavigate, store: null, bills:bills, localStorage: window.localStorage }) - const html = DashboardUI({ data: bills }) - - document.body.innerHTML = html + document.body.innerHTML = DashboardUI({ data: { bills } }) const handleShowTickets1 = jest.fn((e) => dashboard.handleShowTickets(e, bills, 1)) const handleShowTickets2 = jest.fn((e) => dashboard.handleShowTickets(e, bills, 2)) @@ -77,49 +75,85 @@ describe('Given I am connected as an Admin', () => { icon1.addEventListener('click', handleShowTickets1) userEvent.click(icon1) expect(handleShowTickets1).toHaveBeenCalled() - userEvent.click(icon1) - + await waitFor(() => screen.getByTestId(`open-bill47qAXb6fIm2zOKkLzMro`) ) + expect(screen.getByTestId(`open-bill47qAXb6fIm2zOKkLzMro`)).toBeTruthy() icon2.addEventListener('click', handleShowTickets2) userEvent.click(icon2) expect(handleShowTickets2).toHaveBeenCalled() + await waitFor(() => screen.getByTestId(`open-billUIUZtnPQvnbFnB0ozvJh`) ) + expect(screen.getByTestId(`open-billUIUZtnPQvnbFnB0ozvJh`)).toBeTruthy() icon3.addEventListener('click', handleShowTickets3) userEvent.click(icon3) expect(handleShowTickets3).toHaveBeenCalled() - + await waitFor(() => screen.getByTestId(`open-billBeKy5Mo4jkmdfPGYpTxZ`) ) + expect(screen.getByTestId(`open-billBeKy5Mo4jkmdfPGYpTxZ`)).toBeTruthy() }) }) describe('When I am on Dashboard page and I click on edit icon of a card', () => { - test('Then, right form should be filled', () => { - const html = cards(bills) - document.body.innerHTML = html + test('Then, right form should be filled', () => { const onNavigate = (pathname) => { document.body.innerHTML = ROUTES({ pathname }) } - const store = null Object.defineProperty(window, 'localStorage', { value: localStorageMock }) + window.localStorage.setItem('user', JSON.stringify({ + type: 'Admin' + })) + const dashboard = new Dashboard({ - document, onNavigate, store, bills, localStorage: window.localStorage + document, onNavigate, store: null, bills:bills, localStorage: window.localStorage }) + document.body.innerHTML = DashboardUI({ data: { bills } }) + const handleShowTickets1 = jest.fn((e) => dashboard.handleShowTickets(e, bills, 1)) + const icon1 = screen.getByTestId('arrow-icon1') + icon1.addEventListener('click', handleShowTickets1) + userEvent.click(icon1) + expect(handleShowTickets1).toHaveBeenCalled() + expect(screen.getByTestId(`open-bill47qAXb6fIm2zOKkLzMro`)).toBeTruthy() + const iconEdit = screen.getByTestId('open-bill47qAXb6fIm2zOKkLzMro') + userEvent.click(iconEdit) + expect(screen.getByTestId(`dashboard-form`)).toBeTruthy() + }) + }) + + describe('When I am on Dashboard page and I click 2 times on edit icon of a card', () => { + test('Then, big bill Icon should Appear', () => { + + const onNavigate = (pathname) => { + document.body.innerHTML = ROUTES({ pathname }) + } - const handleEditTicket = jest.fn((e) => dashboard.handleEditTicket(e, bills[0], bills)) + Object.defineProperty(window, 'localStorage', { value: localStorageMock }) + window.localStorage.setItem('user', JSON.stringify({ + type: 'Admin' + })) + + const dashboard = new Dashboard({ + document, onNavigate, store: null, bills:bills, localStorage: window.localStorage + }) + document.body.innerHTML = DashboardUI({ data: { bills } }) + + const handleShowTickets1 = jest.fn((e) => dashboard.handleShowTickets(e, bills, 1)) + const icon1 = screen.getByTestId('arrow-icon1') + icon1.addEventListener('click', handleShowTickets1) + userEvent.click(icon1) + expect(handleShowTickets1).toHaveBeenCalled() + expect(screen.getByTestId(`open-bill47qAXb6fIm2zOKkLzMro`)).toBeTruthy() const iconEdit = screen.getByTestId('open-bill47qAXb6fIm2zOKkLzMro') - iconEdit.addEventListener('click', handleEditTicket) userEvent.click(iconEdit) - expect(handleEditTicket).toHaveBeenCalled() userEvent.click(iconEdit) - expect(handleEditTicket).toHaveBeenCalled() + const bigBilledIcon = screen.queryByTestId("big-billed-icon") + expect(bigBilledIcon).toBeTruthy() }) }) + describe('When I am on Dashboard and there are no bills', () => { test('Then, no cards should be shown', () => { - const html = cards([]) - document.body.innerHTML = html - + document.body.innerHTML = cards([]) const iconEdit = screen.queryByTestId('open-bill47qAXb6fIm2zOKkLzMro') expect(iconEdit).toBeNull() }) @@ -133,8 +167,8 @@ describe('Given I am connected as Admin, and I am on Dashboard page, and I click window.localStorage.setItem('user', JSON.stringify({ type: 'Admin' })) - const html = DashboardFormUI(bills[0]) - document.body.innerHTML = html + document.body.innerHTML = DashboardFormUI(bills[0]) + const onNavigate = (pathname) => { document.body.innerHTML = ROUTES({ pathname }) } @@ -158,8 +192,8 @@ describe('Given I am connected as Admin, and I am on Dashboard page, and I click window.localStorage.setItem('user', JSON.stringify({ type: 'Admin' })) - const html = DashboardFormUI(bills[0]) - document.body.innerHTML = html + document.body.innerHTML = DashboardFormUI(bills[0]) + const onNavigate = (pathname) => { document.body.innerHTML = ROUTES({ pathname }) } @@ -185,8 +219,7 @@ describe('Given I am connected as Admin and I am on Dashboard page and I clicked window.localStorage.setItem('user', JSON.stringify({ type: 'Admin' })) - const html = DashboardFormUI(bills[0]) - document.body.innerHTML = html + document.body.innerHTML = DashboardFormUI(bills[0]) const onNavigate = (pathname) => { document.body.innerHTML = ROUTES({ pathname }) } @@ -211,29 +244,66 @@ describe('Given I am connected as Admin and I am on Dashboard page and I clicked describe("Given I am a user connected as Admin", () => { describe("When I navigate to Dashboard", () => { test("fetches bills from mock API GET", async () => { - const getSpy = jest.spyOn(store, "get") - const bills = await store.get() - expect(getSpy).toHaveBeenCalledTimes(1) - expect(bills.data.length).toBe(4) + localStorage.setItem("user", JSON.stringify({ type: "Admin", email: "a@a" })); + const root = document.createElement("div") + root.setAttribute("id", "root") + document.body.append(root) + router() + window.onNavigate(ROUTES_PATH.Dashboard) + await waitFor(() => screen.getByText("Validations")) + const contentPending = await screen.getByText("En attente (1)") + expect(contentPending).toBeTruthy() + const contentRefused = await screen.getByText("Refusé (2)") + expect(contentRefused).toBeTruthy() + expect(screen.getByTestId("big-billed-icon")).toBeTruthy() }) - test("fetches bills from an API and fails with 404 message error", async () => { - store.get.mockImplementationOnce(() => - Promise.reject(new Error("Erreur 404")) + describe("When an error occurs on API", () => { + beforeEach(() => { + jest.spyOn(mockStore, "bills") + Object.defineProperty( + window, + 'localStorage', + { value: localStorageMock } ) - const html = DashboardUI({ error: "Erreur 404" }) - document.body.innerHTML = html + window.localStorage.setItem('user', JSON.stringify({ + type: 'Admin', + email: "a@a" + })) + const root = document.createElement("div") + root.setAttribute("id", "root") + document.body.appendChild(root) + router() + }) + test("fetches bills from an API and fails with 404 message error", async () => { + + mockStore.bills.mockImplementationOnce(() => { + return { + list : () => { + return Promise.reject(new Error("Erreur 404")) + } + }}) + window.onNavigate(ROUTES_PATH.Dashboard) + await new Promise(process.nextTick); const message = await screen.getByText(/Erreur 404/) expect(message).toBeTruthy() }) + test("fetches messages from an API and fails with 500 message error", async () => { - store.get.mockImplementationOnce(() => - Promise.reject(new Error("Erreur 500")) - ) - const html = DashboardUI({ error: "Erreur 500" }) - document.body.innerHTML = html + + mockStore.bills.mockImplementationOnce(() => { + return { + list : () => { + return Promise.reject(new Error("Erreur 500")) + } + }}) + + window.onNavigate(ROUTES_PATH.Dashboard) + await new Promise(process.nextTick); const message = await screen.getByText(/Erreur 500/) expect(message).toBeTruthy() }) }) + + }) }) diff --git a/src/__tests__/DashboardFormUI.js b/src/__tests__/DashboardFormUI.js index 8d75804d9..e106a60f9 100644 --- a/src/__tests__/DashboardFormUI.js +++ b/src/__tests__/DashboardFormUI.js @@ -68,7 +68,7 @@ describe('Given I am connected as an Admin and I am on Dashboard Page', () => { expect(screen.getByText(bill.commentAdmin)).toBeTruthy() }) }) - describe('When acceptrefuseded bill is passed to DashboardUI', () => { + describe('When refused bill is passed to DashboardUI', () => { test(('Then, it should show admin commentary'), () => { const html = DashboardFormUI(billrefused) document.body.innerHTML = html diff --git a/src/__tests__/Logout.js b/src/__tests__/Logout.js index ca3d1dc54..653eed604 100644 --- a/src/__tests__/Logout.js +++ b/src/__tests__/Logout.js @@ -24,7 +24,6 @@ const bills = [{ "commentAdmin": "ok", "email": "a@a", "pct": 20, - "email": "john.snow@billed.com" }] describe('Given I am connected', () => { diff --git a/src/app/Router.js b/src/app/Router.js index 4d326d33d..ccae18be7 100644 --- a/src/app/Router.js +++ b/src/app/Router.js @@ -52,14 +52,14 @@ export default () => { rootDiv.innerHTML = ROUTES({ pathname, loading: true }) const bills = new Dashboard({ document, onNavigate, store, bills: [], localStorage }) bills.getBillsAllUsers().then(bills => { - rootDiv.innerHTML = DashboardUI({ data: { bills } }) - new Dashboard({ document, onNavigate, store, bills, localStorage }) - }).catch(error => { + rootDiv.innerHTML = DashboardUI({data: {bills}}) + new Dashboard({document, onNavigate, store, bills, localStorage}) + }).catch(error => { rootDiv.innerHTML = ROUTES({ pathname, error }) }) } } - + window.onpopstate = (e) => { const user = JSON.parse(localStorage.getItem('user')) if (window.location.pathname === "/" && !user) { @@ -113,4 +113,4 @@ export default () => { return null } - + diff --git a/src/containers/Bills.js b/src/containers/Bills.js index 3cc4e9f99..80ce7c113 100644 --- a/src/containers/Bills.js +++ b/src/containers/Bills.js @@ -11,22 +11,22 @@ export default class { if (buttonNewBill) buttonNewBill.addEventListener('click', this.handleClickNewBill) const iconEye = document.querySelectorAll(`div[data-testid="icon-eye"]`) if (iconEye) iconEye.forEach(icon => { - icon.addEventListener('click', (e) => this.handleClickIconEye(icon)) + icon.addEventListener('click', () => this.handleClickIconEye(icon)) }) new Logout({ document, localStorage, onNavigate }) } - handleClickNewBill = e => { + handleClickNewBill = () => { this.onNavigate(ROUTES_PATH['NewBill']) } handleClickIconEye = (icon) => { const billUrl = icon.getAttribute("data-bill-url") const imgWidth = Math.floor($('#modaleFile').width() * 0.5) - $('#modaleFile').find(".modal-body").html(`
`) + $('#modaleFile').find(".modal-body").html(`
Bill
`) $('#modaleFile').modal('show') } - + getBills = () => { if (this.store) { return this.store diff --git a/src/containers/Dashboard.js b/src/containers/Dashboard.js index bf76207f3..28ac3d616 100644 --- a/src/containers/Dashboard.js +++ b/src/containers/Dashboard.js @@ -13,7 +13,9 @@ export const filteredBills = (data, status) => { // in jest environment if (typeof jest !== 'undefined') { selectCondition = (bill.status === status) - } else { + } + /* istanbul ignore next */ + else { // in prod environment const userEmail = JSON.parse(localStorage.getItem("user")).email selectCondition = @@ -73,14 +75,13 @@ export default class { $('#arrow-icon1').click((e) => this.handleShowTickets(e, bills, 1)) $('#arrow-icon2').click((e) => this.handleShowTickets(e, bills, 2)) $('#arrow-icon3').click((e) => this.handleShowTickets(e, bills, 3)) - this.getBillsAllUsers() new Logout({ localStorage, onNavigate }) } handleClickIconEye = () => { const billUrl = $('#icon-eye-d').attr("data-bill-url") const imgWidth = Math.floor($('#modaleFileAdmin1').width() * 0.8) - $('#modaleFileAdmin1').find(".modal-body").html(`
`) + $('#modaleFileAdmin1').find(".modal-body").html(`
Bill
`) if (typeof $('#modaleFileAdmin1').modal === 'function') $('#modaleFileAdmin1').modal('show') } @@ -99,7 +100,7 @@ export default class { $(`#open-bill${bill.id}`).css({ background: '#0D5AE5' }) $('.dashboard-right-container div').html(` -
${BigBilledIcon}
+
${BigBilledIcon}
`) $('.vertical-navbar').css({ height: '120vh' }) this.counter ++ @@ -152,7 +153,6 @@ export default class { } - // not need to cover this function by tests getBillsAllUsers = () => { if (this.store) { return this.store @@ -168,11 +168,14 @@ export default class { })) return bills }) - .catch(console.log) + .catch(error => { + throw error; + }) } } - + // not need to cover this function by tests + /* istanbul ignore next */ updateBill = (bill) => { if (this.store) { return this.store @@ -182,4 +185,4 @@ export default class { .catch(console.log) } } -} \ No newline at end of file +} diff --git a/src/containers/Login.js b/src/containers/Login.js index 7a9e12427..c3cb058bd 100644 --- a/src/containers/Login.js +++ b/src/containers/Login.js @@ -34,7 +34,7 @@ export default class Login { PREVIOUS_LOCATION = this.PREVIOUS_LOCATION this.document.body.style.backgroundColor="#fff" }) - + } handleSubmitAdmin = e => { @@ -92,4 +92,4 @@ export default class Login { return null } } -} \ No newline at end of file +} diff --git a/src/fixtures/bills.js b/src/fixtures/bills.js index 2fd081f35..dd9ffff13 100644 --- a/src/fixtures/bills.js +++ b/src/fixtures/bills.js @@ -58,4 +58,4 @@ export const bills = [{ "type": "Restaurants et bars", "fileUrl": "https://test.storage.tld/v0/b/billable-677b6.a…f-1.jpg?alt=media&token=4df6ed2c-12c8-42a2-b013-346c1346f732" } -] \ No newline at end of file +]