Fakultas Ilmu Komputer UI

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

Merge branch 'staging' into 'master'

Complete the Main Application Functionalities

See merge request !36
parents 5847bbf3 5e754c97
Pipeline #43823 passed with stages
in 96 minutes and 37 seconds
{
"presets": ["@babel/preset-react", "@babel/preset-env"]
"presets": ["@babel/preset-react", "@babel/preset-env",
[
"@emotion/babel-preset-css-prop",
{
"sourceMap": false
}
]
],
"plugins": [
[
"transform-inline-environment-variables"
],
[
"emotion"
]
]
}
......@@ -10,10 +10,13 @@
"rules": {
"react/prop-types": 0,
"react-hooks/rules-of-hooks": "error",
"no-console": "warn"
"no-console": "warn",
"emotion/no-vanilla": "error",
"emotion/import-from-emotion": "error",
"emotion/styled-import": "error"
},
"parser": "babel-eslint",
"plugins": ["react", "import", "jsx-a11y", "react-hooks"],
"plugins": ["react", "import", "jsx-a11y", "react-hooks", "emotion"],
"parserOptions": {
"ecmaVersion": 2019,
"sourceType": "module",
......
......@@ -6,6 +6,7 @@
.pnp.js
/.cache
/dist
.env
# testing
/coverage
......@@ -26,3 +27,4 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json
/.vscode
......@@ -39,10 +39,11 @@ staging:
variables:
NETLIFY_AUTH_TOKEN: $STAGING_NETLIFY_AUTH_TOKEN
NETLIFY_SITE_ID: $STAGING_NETLIFY_SITE_ID
REACT_APP_BASE_URL: $STAGING_REACT_APP_BASE_URL
script:
- npm install
- CI=false npm run build
- npm install netlify-cli -g
- npm install netlify-cli -g --unsafe-perm
- netlify deploy --dir dist --prod
only:
- staging
......@@ -54,6 +55,7 @@ production:
AWS_ACCESS_KEY_ID: $PRODUCTION_AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY: $PRODUCTION_AWS_SECRET_ACCESS_KEY
AWS_STORAGE_BUCKET_NAME: $PRODUCTION_AWS_STORAGE_BUCKET_NAME
REACT_APP_BASE_URL: $PRODUCTION_REACT_APP_BASE_URL
script:
- npm install
- CI=false npm run build
......
......@@ -2,3 +2,38 @@
[![pipeline status](https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2020/ppl-c/diskominfo-depok-tpu-online/post-rpl-web/badges/master/pipeline.svg)](https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2020/ppl-c/diskominfo-depok-tpu-online/post-rpl-web/commits/master)
[![coverage report](https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2020/ppl-c/diskominfo-depok-tpu-online/post-rpl-web/badges/master/coverage.svg)](https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2020/ppl-c/diskominfo-depok-tpu-online/post-rpl-web/commits/master)
A local e-commerce application created for ease of buying and selling transactions.
## Table of Contents
- [Install](#install)
- [Running Development Mode](#running-development-mode)
- [References](#references)
## Install
The Admin Website's frontend uses Node.js and is developed using React. You need to install the required dependencies prior to building and contributing to the project.
- [Node.js](https://nodejs.org/en/download/releases/) and npm package manager
Verify that Node.js has been successfully installed. Make sure the interpreter can be invoked from the shell. For example:
```
npm --version
```
Now install the packages required for Node.js:
```
npm install
```
## Running Development Mode
To serve the frontend:
```
npm run start
```
You can see the app running by going to localhost:1234 via your favourite web browser.
## References
- https://docs.gitlab.com/ee/user/markdown.html#wiki---direct-page-link
- https://nodejs.org/en/download/package-manager/
/* /index.html 200
......@@ -3,14 +3,28 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@reach/router": "^1.3.1",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-scripts": "3.3.1"
"@emotion/babel-preset-css-prop": "^10.0.27",
"@emotion/core": "^10.0.28",
"@emotion/styled": "^10.0.27",
"@material-ui/core": "^4.9.11",
"@material-ui/icons": "^4.9.1",
"@reach/router": "^1.3.3",
"bootstrap": "^4.4.1",
"jquery": "^3.5.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-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",
"build": "parcel build public/index.html --experimental-scope-hoisting",
"test": "jest",
"test:coverage": "jest --coverage",
"lint": "eslint \"src/**/*.{js,jsx}\" --quiet",
......@@ -21,9 +35,9 @@
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
"last 3 chrome version",
"last 3 firefox version",
"last 3 safari version"
],
"development": [
"last 1 chrome version",
......@@ -32,24 +46,40 @@
]
},
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/preset-env": "^7.8.4",
"@babel/preset-react": "^7.8.3",
"@testing-library/react": "^9.4.0",
"@types/jest": "^25.1.2",
"babel-eslint": "^10.0.3",
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.5",
"@babel/preset-react": "^7.9.4",
"@testing-library/dom": "^7.2.2",
"@testing-library/react": "^10.0.3",
"@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",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.0",
"eslint-plugin-import": "^2.20.1",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-emotion": "^10.0.27",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-react": "^7.18.3",
"eslint-plugin-react-hooks": "^2.3.0",
"jest": "^25.1.0",
"eslint-plugin-react": "^7.19.0",
"eslint-plugin-react-hooks": "^2.5.1",
"jest": "^25.4.0",
"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",
"prettier": "^1.19.1"
"prettier": "^2.0.5",
"regenerator-runtime": "^0.13.5"
},
"jest": {
"setupFilesAfterEnv": [
"jest-enzyme",
"<rootDir>/src/__test__/setup-jest.js"
],
"testEnvironment": "enzyme",
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js"
......
......@@ -3,18 +3,13 @@
<head>
<meta charset="utf-8" />
<link rel="icon" href="favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
......@@ -26,7 +21,7 @@
-->
<title>React App</title>
</head>
<body>
<body style="background-color: #F5F8F9">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
......
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
......@@ -5,3 +5,5 @@ sonar.testExecutionReportPaths=test-report.xml
sonar.scm.provider=git
sonar.sourceEncoding=UTF-8
sonar.sources=src
sonar.tests=src/__test__
sonar.exclusions=**/*-jest.js
\ No newline at end of file
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
import React from "react";
import "./App.css";
import ApplicationState from "./ApplicationState";
import "bootstrap/dist/css/bootstrap.min.css";
const App = () => {
return (
<div className="App">
<header className="App-header">
<p>Hello, World!</p>
</header>
</div>
);
return <ApplicationState />;
};
export default App;
import React from "react";
import { render } from "@testing-library/react";
import App from "./App";
test("renders hello world", () => {
const { getByText } = render(<App />);
const paragraphElement = getByText(/Hello, World!/i);
expect(paragraphElement.textContent).toStrictEqual("Hello, World!");
});
import React, { useReducer } from "react";
import AuthReducer, { initialState } from "./store/reducers/auth_reducer";
import * as ACTIONS from "./store/actions/actions";
import AuthContext from "./utils/contex";
import Routes from "./routes";
import Loader from "./component/Loader";
const ApplicationState = () => {
const [stateAuthReducer, dispatchAuthReducer] = useReducer(
AuthReducer,
initialState()
);
const handleLogin = (profile) => {
dispatchAuthReducer(ACTIONS.login(profile));
};
const handleLogout = () => {
dispatchAuthReducer(ACTIONS.logout());
};
return (
<div>
<Loader />
<AuthContext.Provider
value={{
...stateAuthReducer,
handleLogin,
handleLogout,
}}
>
<Routes />
</AuthContext.Provider>
</div>
);
};
export default ApplicationState;
import React from "react";
import { cleanup } from "@testing-library/react";
import App from "../App";
import { shallow } from "enzyme";
import ApplicationState from "../ApplicationState";
afterEach(cleanup);
test("renders Application State", () => {
const wrapper = shallow(<App />);
expect(wrapper.find(ApplicationState)).toHaveLength(1);
});
import React from "react";
import { cleanup, render } from "@testing-library/react";
import DetailPengguna from "../page/pengguna/DetailPengguna";
import AuthContext from "../utils/contex";
import { waitFor } from "@testing-library/dom";
beforeEach(() => {
fetch.resetMocks();
});
afterEach(cleanup);
test("Test detail pengguna renders", async () => {
fetch
.once(
JSON.stringify({
count: 17,
next:
"https://industripilar-staging.herokuapp.com/transactions/?page=2",
previous: null,
results: [
{
id: "0c1db3b2-48f0-4604-83ca-e8f16e8550ab",
transaction_number: "H793P5ZK",
user: "d4b98bb5-8ba4-4a41-af10-93abcf53df58",
user_username: "whtestest",
user_full_name: "Michael Wiryadinata halim",
user_phone_number: "+628192090199",
shipping_address: "ada deh test",
shipping_neighborhood: "002",
shipping_hamlet: "002",
shipping_urban_village: "penggilingan",
shipping_sub_district: "Dummy Sub-District",
transaction_items: [
{
id: "37f0298c-2e8a-4ab0-a094-e9177ddc60c4",
product: "3d403cd3-e356-4c15-9a86-8843333e2778",
product_code: "5VK6TY",
product_name: "produk barang",
product_price: "50000.00",
quantity: 7,
},
],
transaction_item_subtotal: "350000.00",
shipping_costs: "15000.00",
payment_method: "TRF",
readable_payment_method: "Transfer",
donation: "5000.00",
transaction_status: "002",
readable_transaction_status: "Waiting for seller confirmation",
proof_of_payment: null,
user_bank_account_name: "test",
user_bank_account_number: "1232131241321",
created_at: "2020-04-18T10:59:42.074386+07:00",
updated_at: "2020-04-18T11:00:18.150633+07:00",
subtotal: "370000.00",
},
],
})
)
.once(
JSON.stringify({
id: "663392ac-1dd6-462b-9301-a19c1287cefd",
username: "dummyuser",
full_name: "Dummy User",
phone_number: "+6285212345678",
address: "Jl. Dummy No.1",
neighborhood: "000",
hamlet: "000",
urban_village: "Dummy Urban Village",
sub_district: "Dummy Sub-District",
profile_picture: null,
})
);
const { getByTestId } = render(
<AuthContext.Provider value={{ profile: { token: "BEBAS" } }}>
<DetailPengguna />
</AuthContext.Provider>
);
await waitFor(() => getByTestId("profile"));
const profile = getByTestId("profile");
expect(profile.textContent).toContain("dummyuser");
expect(profile.textContent).toContain("+6285212345678");
expect(profile.textContent).toContain("Jl. Dummy No.1");
expect(profile.textContent).toContain("000");
expect(profile.textContent).toContain("000");
expect(profile.textContent).toContain("Dummy Sub-District");
expect(profile.textContent).toContain("Dummy Urban Village");
});
test("Test mock return error", async () => {
fetch
.once(
JSON.stringify({
count: 17,
next:
"https://industripilar-staging.herokuapp.com/transactions/?page=2",
previous: null,
results: [
{
id: "0c1db3b2-48f0-4604-83ca-e8f16e8550ab",
transaction_number: "H793P5ZK",
user: "d4b98bb5-8ba4-4a41-af10-93abcf53df58",
user_username: "whtestest",
user_full_name: "Michael Wiryadinata halim",
user_phone_number: "+628192090199",
shipping_address: "ada deh test",
shipping_neighborhood: "002",
shipping_hamlet: "002",
shipping_urban_village: "penggilingan",
shipping_sub_district: "Dummy Sub-District",
transaction_items: [
{
id: "37f0298c-2e8a-4ab0-a094-e9177ddc60c4",
product: "3d403cd3-e356-4c15-9a86-8843333e2778",
product_code: "5VK6TY",
product_name: "produk barang",
product_price: "50000.00",
quantity: 7,
},
],
transaction_item_subtotal: "350000.00",
shipping_costs: "15000.00",
payment_method: "TRF",
readable_payment_method: "Transfer",
donation: "5000.00",
transaction_status: "002",
readable_transaction_status: "Waiting for seller confirmation",
proof_of_payment: null,
user_bank_account_name: "test",
user_bank_account_number: "1232131241321",
created_at: "2020-04-18T10:59:42.074386+07:00",
updated_at: "2020-04-18T11:00:18.150633+07:00",
subtotal: "370000.00",
},
],
})
)
.mockReject(new Error("fake error message"));
const { getByTestId } = render(
<AuthContext.Provider value={{ profile: { token: "BEBAS" } }}>
<DetailPengguna />
</AuthContext.Provider>
);
const page = getByTestId("page-profile");
await waitFor(() =>
expect(page.textContent).toContain("Error !, Please relogin..")
);
});
import React from "react";
import { render, cleanup } from "@testing-library/react";
import ListPengguna from "../page/pengguna/ListPengguna";
import AuthContext from "../utils/contex";
import { waitFor } from "@testing-library/dom";
beforeEach(() => {
fetch.resetMocks();
});
afterEach(cleanup);
test("test fetching API", async () => {
fetch.mockResponseOnce(
JSON.stringify({
count: 2,
next: null,
previous: null,
results: [
{
id: "45897cc5-968c-44cf-931d-e646b095fcaf",
username: "admin-staging",
full_name: "",
phone_number: "",
address: "",
neighborhood: "",
hamlet: "",
urban_village: "",
sub_district: "",
profile_picture: null,
},
{
id: "663392ac-1dd6-462b-9301-a19c1287cefd",
username: "dummyuser",
full_name: "Dummy User",
phone_number: "+6285212345678",
address: "Jl. Dummy No.1",
neighborhood: "000",
hamlet: "000",
urban_village: "Dummy Urban Village",
sub_district: "Dummy Sub-District",
profile_picture: null,
},
],
})