Fakultas Ilmu Komputer UI

Commit 8588c98e authored by WILLIAM GATES's avatar WILLIAM GATES
Browse files

Complete Donation Functionality

parent 1b7ec6d8
{
"presets": ["@babel/preset-react", "@babel/preset-env",
[
"@emotion/babel-preset-css-prop",
{
"sourceMap": false
}
"@emotion/babel-preset-css-prop"
]
],
"plugins": [
[
"transform-inline-environment-variables"
],
[
"emotion"
]
]
}
......@@ -26,5 +26,5 @@ test-report.xml
npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json
/.vscode
.parcel-cache
\ No newline at end of file
image: node:12.16.3-buster-slim
stages:
- lint
- test
......@@ -5,14 +6,12 @@ stages:
- deploy
lint:
image: node:latest
stage: lint
script:
- npm install
- npm run lint
test:
image: node:latest
stage: test
artifacts:
expire_in: 1 hour
......@@ -34,7 +33,6 @@ sonar_scanner_test:
- sonar-scanner -Dsonar.projectKey=$SONARQUBE_PROJECT_KEY -Dsonar.host.url=$SONARQUBE_HOST_URL -Dsonar.login=$SONARQUBE_TOKEN -Dsonar.branch.name=$CI_COMMIT_REF_NAME
staging:
image: node:latest
stage: deploy
variables:
NETLIFY_AUTH_TOKEN: $STAGING_NETLIFY_AUTH_TOKEN
......@@ -49,7 +47,6 @@ staging:
- staging
production:
image: node:latest
stage: deploy
variables:
AWS_ACCESS_KEY_ID: $PRODUCTION_AWS_ACCESS_KEY_ID
......
This diff is collapsed.
......@@ -11,20 +11,19 @@
"@reach/router": "^1.3.3",
"bootstrap": "^4.4.1",
"jquery": "^3.5.0",
"moment": "^2.24.0",
"moment": "2.24.0",
"moment-timezone": "^0.5.28",
"popper.js": "^1.16.1",
"react": "^16.13.1",
"react-bootstrap": "^1.0.1",
"react-dom": "^16.13.1",
"react-hook-form": "^5.6.0",
"react-hook-form": "^5.6.1",
"react-moment": "^0.9.7",
"react-number-format": "^4.4.1",
"react-promise-tracker": "^2.1.0"
},
"scripts": {
"start": "parcel public/index.html",
"build": "parcel build public/index.html --experimental-scope-hoisting",
"start": "cross-env REACT_APP_BASE_URL=https://industripilar-staging.herokuapp.com parcel public/index.html",
"build": "parcel build public/index.html",
"test": "jest",
"test:coverage": "jest --coverage",
"lint": "eslint \"src/**/*.{js,jsx}\" --quiet",
......@@ -46,15 +45,16 @@
]
},
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.5",
"@babel/core": "^7.9.6",
"@babel/preset-env": "^7.9.6",
"@babel/preset-react": "^7.9.4",
"@testing-library/dom": "^7.2.2",
"@testing-library/react": "^10.0.3",
"@testing-library/react": "^10.0.4",
"@types/jest": "^25.2.1",
"babel-eslint": "^10.1.0",
"babel-plugin-emotion": "^10.0.33",
"babel-plugin-transform-inline-environment-variables": "^0.4.3",
"cross-env": "^7.0.2",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"eslint": "^6.8.0",
......@@ -63,14 +63,14 @@
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-react": "^7.19.0",
"eslint-plugin-react-hooks": "^2.5.1",
"jest": "^25.4.0",
"eslint-plugin-react-hooks": "^4.0.0",
"jest": "^25.5.4",
"jest-environment-enzyme": "^7.1.2",
"jest-enzyme": "^7.1.2",
"jest-fetch-mock": "^3.0.3",
"jest-sonar-reporter": "^2.0.0",
"mutationobserver-shim": "^0.3.5",
"parcel-bundler": "^1.12.4",
"parcel": "^2.0.0-alpha.3.2",
"prettier": "^2.0.5",
"regenerator-runtime": "^0.13.5"
},
......
......@@ -4,6 +4,7 @@ import * as ACTIONS from "./store/actions/actions";
import AuthContext from "./utils/contex";
import Routes from "./routes";
import Loader from "./component/Loader";
import { createMuiTheme, ThemeProvider } from "@material-ui/core/styles";
const ApplicationState = () => {
const [stateAuthReducer, dispatchAuthReducer] = useReducer(
......@@ -19,8 +20,10 @@ const ApplicationState = () => {
dispatchAuthReducer(ACTIONS.logout());
};
const theme = createMuiTheme();
return (
<div>
<ThemeProvider theme={theme}>
<Loader />
<AuthContext.Provider
value={{
......@@ -31,7 +34,7 @@ const ApplicationState = () => {
>
<Routes />
</AuthContext.Provider>
</div>
</ThemeProvider>
);
};
export default ApplicationState;
......@@ -11,6 +11,25 @@ afterEach(cleanup);
test("Test detail pengguna renders", async () => {
fetch
.once({
id: "8e9a8f94-cb5c-4b2d-b4f1-81ccfb9f1b0a",
donation_number: "7NGVBN",
user: "45897cc5-968c-44cf-931d-e646b095fcaf",
user_username: "admin-staging",
program: "6d7462da-6a85-4e2b-9930-69567090a5d5",
program_code: "3MXZ9T",
user_full_name: "Hello",
user_phone_number: "012345",
program_name: "dummy 2",
amount: "10000.00",
donation_status: "001",
readable_donation_status: "Menunggu konfirmasi admin",
proof_of_bank_transfer: "a",
user_bank_account_name: "Jeffrey",
user_bank_account_number: "12345678",
created_at: "2020-04-28T21:34:15.565614+07:00",
updated_at: "2020-04-28T21:34:15.565651+07:00",
})
.once(
JSON.stringify({
count: 17,
......
import { act, cleanup, fireEvent, render } from "@testing-library/react";
import AuthContext from "../../utils/contex";
import React from "react";
import DetailDonasi from "../../page/donasi/DetailDonasi";
import { waitFor } from "@testing-library/dom";
beforeEach(() => {
fetch.resetMocks();
});
afterEach(cleanup);
test("Test detail loaded donasi", async () => {
fetch.mockResponseOnce(
JSON.stringify({
id: "8e9a8f94-cb5c-4b2d-b4f1-81ccfb9f1b0a",
donation_number: "7NGVBN",
user: "45897cc5-968c-44cf-931d-e646b095fcaf",
user_username: "admin-staging",
program: "6d7462da-6a85-4e2b-9930-69567090a5d5",
program_code: "3MXZ9T",
user_full_name: "Hello",
user_phone_number: "012345",
program_name: "dummy 2",
amount: "10000.00",
donation_status: "001",
readable_donation_status: "Menunggu konfirmasi admin",
proof_of_bank_transfer: "a",
user_bank_account_name: "Jeffrey",
user_bank_account_number: "12345678",
created_at: "2020-04-28T21:34:15.565614+07:00",
updated_at: "2020-04-28T21:34:15.565651+07:00",
})
);
const { getByTestId } = render(
<AuthContext.Provider value={{ profile: { token: "tester" } }}>
<DetailDonasi idDonasi={"8e9a8f94-cb5c-4b2d-b4f1-81ccfb9f1b0a"} />
</AuthContext.Provider>
);
const wait = getByTestId("waiting-detail-donasi");
expect(wait.textContent).toContain("Fetching data..");
await waitFor(() => getByTestId("page-detail-donasi"));
const data = getByTestId("page-detail-donasi");
expect(data.textContent).toContain("DONASI");
await act(async () => {
await fireEvent.click(getByTestId("button-see-proof"));
});
const close = getByTestId("button-close-proof");
expect(close.textContent).toContain("Close");
await act(async () => {
await fireEvent.click(close);
});
const dropdown = getByTestId("dropdown-status");
expect(dropdown.children.length).toEqual(4);
});
import { act, cleanup, fireEvent, render } from "@testing-library/react";
import AuthContext from "../../utils/contex";
import React from "react";
import ListDonasi from "../../page/donasi/ListDonasi";
import { waitFor } from "@testing-library/dom";
beforeEach(() => {
fetch.resetMocks();
});
afterEach(cleanup);
test("Test List donasi", async () => {
fetch.mockResponseOnce(
JSON.stringify({
count: 1,
next: null,
previous: null,
results: [
{
id: "8e9a8f94-cb5c-4b2d-b4f1-81ccfb9f1b0a",
donation_number: "7NGVBN",
user: "45897cc5-968c-44cf-931d-e646b095fcaf",
program: "6d7462da-6a85-4e2b-9930-69567090a5d5",
program_code: "3MXZ9T",
user_username: "admin-staging",
user_full_name: "",
user_phone_number: "",
program_name: "dummy 2",
amount: "10000.00",
donation_status: "001",
readable_donation_status: "Menunggu konfirmasi admin",
proof_of_bank_transfer: null,
user_bank_account_name: "Jeffrey",
user_bank_account_number: "12345678",
created_at: "2020-04-28T21:34:15.565614+07:00",
updated_at: "2020-04-28T21:34:15.565651+07:00",
},
],
})
);
const { getByTestId } = render(
<AuthContext.Provider value={{ profile: { token: "tester" } }}>
<ListDonasi />
</AuthContext.Provider>
);
await waitFor(() => getByTestId("tableList"));
const data = getByTestId("tableList");
expect(data.textContent).toContain("admin-staging");
expect(data.textContent).toContain("Menunggu konfirmasi admin");
expect(fetch.mock.calls.length).toEqual(1);
});
test(" Test List transaksi filter", async () => {
fetch.once(
JSON.stringify({
count: 1,
next: null,
previous: null,
results: [
{
id: "8e9a8f94-cb5c-4b2d-b4f1-81ccfb9f1b0a",
donation_number: "7NGVBN",
user: "45897cc5-968c-44cf-931d-e646b095fcaf",
program: "6d7462da-6a85-4e2b-9930-69567090a5d5",
program_code: "3MXZ9T",
user_username: "admin-staging",
user_full_name: "",
user_phone_number: "",
program_name: "dummy 2",
amount: "10000.00",
donation_status: "001",
readable_donation_status: "Menunggu konfirmasi admin",
proof_of_bank_transfer: null,
user_bank_account_name: "Jeffrey",
user_bank_account_number: "12345678",
created_at: "2020-04-28T21:34:15.565614+07:00",
updated_at: "2020-04-28T21:34:15.565651+07:00",
},
],
})
);
const { getByTestId, getByLabelText } = render(
<AuthContext.Provider value={{ profile: { token: "tester" } }}>
<ListDonasi />
</AuthContext.Provider>
);
await waitFor(() => getByTestId("tableList"));
const data = getByTestId("tableList");
expect(data.textContent).toContain("admin-staging");
expect(data.textContent).toContain("Menunggu konfirmasi admin");
expect(fetch.mock.calls.length).toEqual(1);
await act(async () => {
await fireEvent.click(getByTestId("filter-button"));
});
await act(async () => {
await fireEvent.input(
getByLabelText("Status Donasi:", { target: { value: "001" } })
);
await fireEvent.click(getByTestId("submit-filter"));
});
expect(data.textContent).toContain("admin-staging");
expect(fetch.mock.calls.length).toEqual(2);
});
import { act, cleanup, render, fireEvent } from "@testing-library/react";
import AuthContext from "../../utils/contex";
import React from "react";
import DetailProgram from "../../page/program/DetailProgram";
import { waitFor } from "@testing-library/dom";
beforeEach(() => {
fetch.resetMocks();
});
afterEach(cleanup);
test("Test detail program renders", async () => {
fetch.mockResponseOnce(
JSON.stringify({
id: "6d7462da-6a85-4e2b-9930-69567090a5d5",
code: "3MXZ9T",
name: "dummy 2",
description: "yeyyy",
start_date_time: null,
end_date_time: null,
location: "Depok",
speaker: "Eddrick",
poster_image:
"https://industripilar-api-staging.s3.amazonaws.com/media/uploads/programs/1_txtcYocQEGtOFN33ZCTDbw.png",
})
);
const { getByTestId } = render(
<AuthContext.Provider value={{ profile: { token: "BEBAS" } }}>
<DetailProgram />
</AuthContext.Provider>
);
await waitFor(() => getByTestId("program"));
const program = getByTestId("program");
expect(program.textContent).toContain("Eddrick");
expect(fetch.mock.calls.length).toEqual(1);
});
test("Test mock detail program return error", async () => {
fetch.mockReject(new Error("fake error message"));
const { getByTestId } = render(
<AuthContext.Provider value={{ profile: { token: "BEBAS" } }}>
<DetailProgram />
</AuthContext.Provider>
);
await waitFor(() => getByTestId("page"));
const page = getByTestId("page");
expect(page.textContent).toContain("Error !, Please relogin..");
});
test("Test detail program delete", async () => {
fetch.mockResponseOnce(
JSON.stringify({
id: "6d7462da-6a85-4e2b-9930-69567090a5d5",
code: "3MXZ9T",
name: "dummy 2",
description: "yeyyy",
start_date_time: null,
end_date_time: null,
location: "Depok",
speaker: "Eddrick",
poster_image:
"https://industripilar-api-staging.s3.amazonaws.com/media/uploads/programs/1_txtcYocQEGtOFN33ZCTDbw.png",
})
);
const { getByTestId } = render(
<AuthContext.Provider value={{ profile: { token: "BEBAS" } }}>
<DetailProgram />
</AuthContext.Provider>
);
await waitFor(() => getByTestId("page"));
const produk = getByTestId("page");
expect(produk.textContent).toContain("dummy 2");
expect(fetch.mock.calls.length).toEqual(1);
const btnDeleteModal = getByTestId("button-delete-program-modal");
await act(async () => {
await fireEvent.click(btnDeleteModal);
});
const btnDelete = getByTestId("button-delete-program");
await act(async () => {
await fireEvent.click(btnDelete);
});
expect(fetch.mock.calls.length).toEqual(2);
});
test("Test detail produk delete error", async () => {
fetch
.mockResponseOnce(
JSON.stringify({
id: "6d7462da-6a85-4e2b-9930-69567090a5d5",
code: "3MXZ9T",
name: "dummy 2",
description: "yeyyy",
start_date_time: null,
end_date_time: null,
location: "Depok",
speaker: "Eddrick",
poster_image:
"https://industripilar-api-staging.s3.amazonaws.com/media/uploads/programs/1_txtcYocQEGtOFN33ZCTDbw.png",
})
)
.mockReject(new Error("fake error message"));
const { getByTestId } = render(
<AuthContext.Provider value={{ profile: { token: "BEBAS" } }}>
<DetailProgram />
</AuthContext.Provider>
);
await waitFor(() => getByTestId("page"));
const produk = getByTestId("page");
expect(produk.textContent).toContain("Eddrick");
expect(fetch.mock.calls.length).toEqual(1);
const btnDeleteModal = getByTestId("button-delete-program-modal");
await act(async () => {
await fireEvent.click(btnDeleteModal);
});
const btnDelete = getByTestId("button-delete-program");
await act(async () => {
await fireEvent.click(btnDelete);
});
expect(fetch.mock.calls.length).toEqual(2);
expect(produk.textContent).toContain(
"Tidak dapat menghapus program, mohon periksa apakah ada program ini."
);
});
import { act, cleanup, fireEvent, render } from "@testing-library/react";
import AuthContext from "../../utils/contex";
import React from "react";
import TambahProgram from "../../page/program/TambahProgram";
beforeEach(() => {
fetch.resetMocks();
});
afterEach(cleanup);
test("Test tambah program renders", async () => {
fetch.once(
JSON.stringify({
count: 5,
next: null,
previous: null,
results: [
{
id: "6d7462da-6a85-4e2b-9930-69567090a5d5",
code: "3MXZ9T",
name: "dummy 2",
description: "yeyyy",
start_date_time: null,
end_date_time: null,
location: "Depok",
speaker: "Eddrick",
poster_image:
"https://industripilar-api-staging.s3.amazonaws.com/media/uploads/programs/1_txtcYocQEGtOFN33ZCTDbw.png",
},
{
id: "282007ff-d0be-4d68-823e-03bde086ee79",
code: "89Z6GX",
name: "Sample",
description: "Sample",
start_date_time: null,
end_date_time: null,
location: "Sample",
speaker: "Sample",
poster_image:
"https://industripilar-api-staging.s3.amazonaws.com/media/uploads/programs/output_0.jpg",
},
],
})
);
const { getByTestId } = render(
<AuthContext.Provider value={{ profile: { token: "BEBAS" } }}>
<TambahProgram />
</AuthContext.Provider>
);
const name_program = getByTestId("name-program-input");
await act(async () => {
await fireEvent.input(name_program, { target: { value: "test" } });
});
const desc_program = getByTestId("description-program-input");
await act(async () => {
await fireEvent.input(desc_program, { target: { value: "test" } });
});
const start_date_time = getByTestId("start-date-time-program-input");
await act(async () => {
await fireEvent.input(start_date_time, {
target: { value: "2020-05-12T19:30" },
});
});
const end_date_time = getByTestId("end-date-time-program-input");
await act(async () => {
await fireEvent.input(end_date_time, {
target: { value: "2020-05-15T19:30" },
});
});
await act(async () => {
await fireEvent.submit(getByTestId("submit-program"));
});
expect(fetch.mock.calls.length).toEqual(1);
});
......@@ -2,6 +2,7 @@ import React from "react";
import { usePromiseTracker } from "react-promise-tracker";
import { Backdrop, CircularProgress } from "@material-ui/core";
import { makeStyles } from "@material-ui/core/styles";
import { css } from "@emotion/core";
const useStyles = makeStyles((theme) => ({
backdrop: {
zIndex: theme.zIndex.drawer + 1,
......@@ -13,7 +14,11 @@ const Loader = () => {
const { promiseInProgress } = usePromiseTracker();
return (
<Backdrop className={classes.backdrop} open={promiseInProgress}>
<CircularProgress color="inherit" />
<CircularProgress
css={css`
color: inherit;
`}
/>
</Backdrop>
);
};
......
......@@ -52,7 +52,7 @@ const Sidebar = () => {
<LinkSidebar to="/produk">PRODUK</LinkSidebar>
<LinkSidebar to="/transaksi">TRANSAKSI</LinkSidebar>
<LinkSidebar to="/program">PROGRAM</LinkSidebar>
<LinkSidebar to="/product1">DONASI</LinkSidebar>
<LinkSidebar to="/donasi">DONASI</LinkSidebar>
<LinkSidebar to="/pengguna">PENGGUNA</LinkSidebar>
<Center
css={css`
......
import React from "react";
import { css } from "@emotion/core";
const StatusDonasi = ({ status, label }) => {
let color;
switch (status) {
case "001":
color = "#EAC435";