Fakultas Ilmu Komputer UI

Commit dcf286a3 authored by WILLIAM GATES's avatar WILLIAM GATES
Browse files

Merge branch 'staging' into 'master'

Complete Donation Functionality

See merge request !61
parents 1b7ec6d8 8588c98e
Pipeline #49113 passed with stages
in 6 minutes and 15 seconds
{
"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";
break;