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", "presets": ["@babel/preset-react", "@babel/preset-env",
[ [
"@emotion/babel-preset-css-prop", "@emotion/babel-preset-css-prop"
{
"sourceMap": false
}
] ]
], ],
"plugins": [ "plugins": [
[ [
"transform-inline-environment-variables" "transform-inline-environment-variables"
], ],
[
"emotion" "emotion"
] ]
]
} }
...@@ -26,5 +26,5 @@ test-report.xml ...@@ -26,5 +26,5 @@ test-report.xml
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
package-lock.json
/.vscode /.vscode
.parcel-cache
\ No newline at end of file
image: node:12.16.3-buster-slim
stages: stages:
- lint - lint
- test - test
...@@ -5,14 +6,12 @@ stages: ...@@ -5,14 +6,12 @@ stages:
- deploy - deploy
lint: lint:
image: node:latest
stage: lint stage: lint
script: script:
- npm install - npm install
- npm run lint - npm run lint
test: test:
image: node:latest
stage: test stage: test
artifacts: artifacts:
expire_in: 1 hour expire_in: 1 hour
...@@ -34,7 +33,6 @@ sonar_scanner_test: ...@@ -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 - 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: staging:
image: node:latest
stage: deploy stage: deploy
variables: variables:
NETLIFY_AUTH_TOKEN: $STAGING_NETLIFY_AUTH_TOKEN NETLIFY_AUTH_TOKEN: $STAGING_NETLIFY_AUTH_TOKEN
...@@ -49,7 +47,6 @@ staging: ...@@ -49,7 +47,6 @@ staging:
- staging - staging
production: production:
image: node:latest
stage: deploy stage: deploy
variables: variables:
AWS_ACCESS_KEY_ID: $PRODUCTION_AWS_ACCESS_KEY_ID AWS_ACCESS_KEY_ID: $PRODUCTION_AWS_ACCESS_KEY_ID
......
This diff is collapsed.
...@@ -11,20 +11,19 @@ ...@@ -11,20 +11,19 @@
"@reach/router": "^1.3.3", "@reach/router": "^1.3.3",
"bootstrap": "^4.4.1", "bootstrap": "^4.4.1",
"jquery": "^3.5.0", "jquery": "^3.5.0",
"moment": "^2.24.0", "moment": "2.24.0",
"moment-timezone": "^0.5.28", "moment-timezone": "^0.5.28",
"popper.js": "^1.16.1", "popper.js": "^1.16.1",
"react": "^16.13.1", "react": "^16.13.1",
"react-bootstrap": "^1.0.1",
"react-dom": "^16.13.1", "react-dom": "^16.13.1",
"react-hook-form": "^5.6.0", "react-hook-form": "^5.6.1",
"react-moment": "^0.9.7", "react-moment": "^0.9.7",
"react-number-format": "^4.4.1", "react-number-format": "^4.4.1",
"react-promise-tracker": "^2.1.0" "react-promise-tracker": "^2.1.0"
}, },
"scripts": { "scripts": {
"start": "parcel public/index.html", "start": "cross-env REACT_APP_BASE_URL=https://industripilar-staging.herokuapp.com parcel public/index.html",
"build": "parcel build public/index.html --experimental-scope-hoisting", "build": "parcel build public/index.html",
"test": "jest", "test": "jest",
"test:coverage": "jest --coverage", "test:coverage": "jest --coverage",
"lint": "eslint \"src/**/*.{js,jsx}\" --quiet", "lint": "eslint \"src/**/*.{js,jsx}\" --quiet",
...@@ -46,15 +45,16 @@ ...@@ -46,15 +45,16 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.9.0", "@babel/core": "^7.9.6",
"@babel/preset-env": "^7.9.5", "@babel/preset-env": "^7.9.6",
"@babel/preset-react": "^7.9.4", "@babel/preset-react": "^7.9.4",
"@testing-library/dom": "^7.2.2", "@testing-library/dom": "^7.2.2",
"@testing-library/react": "^10.0.3", "@testing-library/react": "^10.0.4",
"@types/jest": "^25.2.1", "@types/jest": "^25.2.1",
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",
"babel-plugin-emotion": "^10.0.33", "babel-plugin-emotion": "^10.0.33",
"babel-plugin-transform-inline-environment-variables": "^0.4.3", "babel-plugin-transform-inline-environment-variables": "^0.4.3",
"cross-env": "^7.0.2",
"enzyme": "^3.11.0", "enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2", "enzyme-adapter-react-16": "^1.15.2",
"eslint": "^6.8.0", "eslint": "^6.8.0",
...@@ -63,14 +63,14 @@ ...@@ -63,14 +63,14 @@
"eslint-plugin-import": "^2.20.2", "eslint-plugin-import": "^2.20.2",
"eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-react": "^7.19.0", "eslint-plugin-react": "^7.19.0",
"eslint-plugin-react-hooks": "^2.5.1", "eslint-plugin-react-hooks": "^4.0.0",
"jest": "^25.4.0", "jest": "^25.5.4",
"jest-environment-enzyme": "^7.1.2", "jest-environment-enzyme": "^7.1.2",
"jest-enzyme": "^7.1.2", "jest-enzyme": "^7.1.2",
"jest-fetch-mock": "^3.0.3", "jest-fetch-mock": "^3.0.3",
"jest-sonar-reporter": "^2.0.0", "jest-sonar-reporter": "^2.0.0",
"mutationobserver-shim": "^0.3.5", "mutationobserver-shim": "^0.3.5",
"parcel-bundler": "^1.12.4", "parcel": "^2.0.0-alpha.3.2",
"prettier": "^2.0.5", "prettier": "^2.0.5",
"regenerator-runtime": "^0.13.5" "regenerator-runtime": "^0.13.5"
}, },
......
...@@ -4,6 +4,7 @@ import * as ACTIONS from "./store/actions/actions"; ...@@ -4,6 +4,7 @@ import * as ACTIONS from "./store/actions/actions";
import AuthContext from "./utils/contex"; import AuthContext from "./utils/contex";
import Routes from "./routes"; import Routes from "./routes";
import Loader from "./component/Loader"; import Loader from "./component/Loader";
import { createMuiTheme, ThemeProvider } from "@material-ui/core/styles";
const ApplicationState = () => { const ApplicationState = () => {
const [stateAuthReducer, dispatchAuthReducer] = useReducer( const [stateAuthReducer, dispatchAuthReducer] = useReducer(
...@@ -19,8 +20,10 @@ const ApplicationState = () => { ...@@ -19,8 +20,10 @@ const ApplicationState = () => {
dispatchAuthReducer(ACTIONS.logout()); dispatchAuthReducer(ACTIONS.logout());
}; };
const theme = createMuiTheme();
return ( return (
<div> <ThemeProvider theme={theme}>
<Loader /> <Loader />
<AuthContext.Provider <AuthContext.Provider
value={{ value={{
...@@ -31,7 +34,7 @@ const ApplicationState = () => { ...@@ -31,7 +34,7 @@ const ApplicationState = () => {
> >
<Routes /> <Routes />
</AuthContext.Provider> </AuthContext.Provider>
</div> </ThemeProvider>
); );
}; };
export default ApplicationState; export default ApplicationState;
...@@ -11,6 +11,25 @@ afterEach(cleanup); ...@@ -11,6 +11,25 @@ afterEach(cleanup);
test("Test detail pengguna renders", async () => { test("Test detail pengguna renders", async () => {
fetch 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( .once(
JSON.stringify({ JSON.stringify({
count: 17, 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,