diff --git a/README.md b/README.md index 37c5076..9d95e09 100644 --- a/README.md +++ b/README.md @@ -51,18 +51,20 @@ PS.: It is important to add the `--template ui5-webcomponents-react-seed` at the - Multiple Scripts. -# Engine Included +# Engine & Samples Included - Fallback Engine (``, `` and ``); - MockServer Engine (w/ `json-server`); -- HTTP Request Engine (w/ `Request`, `APIProvider`, `BrowserProvider`); +- API HTTP Request Engine (w/ `Request`, `APIProvider`, `BrowserProvider`); - Permission Engine (w/ `RouteValidator` and `ComponentValidator`). - Pagination Engine (w/ custom hook `usePaginatedGet`). +- ToDo Form Edition w/ `yup` and `formik`. + # Hooks Included - `useRequest`: Which includes `get`, `post`, `patch`, `delete`, `put` HTTP helpers; @@ -75,7 +77,6 @@ Following one of the several recommendations for structuring files on a React ba The only custom change we have incremented were the Custom Components and the folder for each project containing the `tests` artefacts. - # Scripts Included In the project directory, you can run: diff --git a/package.json b/package.json index bdbba37..5f8356a 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "env-cmd": "^10.1.0", "eslint-config-prettier": "^6.11.0", "eslint-plugin-prettier": "^3.1.4", + "formik": "^2.1.7", "husky": "^4.2.5", "i18next": "^19.7.0", "i18next-browser-languagedetector": "^6.0.1", @@ -67,7 +68,8 @@ "react-query": "^2.17.2", "react-query-devtools": "^2.5.0", "react-router-dom": "^5.2.0", - "react-scripts": "3.4.3" + "react-scripts": "3.4.3", + "yup": "^0.29.3" }, "scripts": { "build": "react-scripts build", diff --git a/server/data/Todo/GET_TODO_BY_ID.js b/server/data/Todo/GET_TODO_BY_ID.js index 81d19b2..c48be5a 100644 --- a/server/data/Todo/GET_TODO_BY_ID.js +++ b/server/data/Todo/GET_TODO_BY_ID.js @@ -1,10 +1,14 @@ +const { MemoryRouter } = require('react-router-dom'); + module.exports = { data: { todos: { id: 'UG9rZW1vbjowMDE=', - number: '001', + description: '001', name: 'Task 1', - completed: false, + completed: true, + priority: 'HIGH', + type: 'PERSONAL', }, }, }; diff --git a/server/data/Todo/GET_TODO_LIST.js b/server/data/Todo/GET_TODO_LIST.js index af6844e..36ecf73 100644 --- a/server/data/Todo/GET_TODO_LIST.js +++ b/server/data/Todo/GET_TODO_LIST.js @@ -2,61 +2,61 @@ module.exports = { content: [ { id: 'UG9rZW1vbjowMDE=', - number: '001', + description: '001', name: 'Task 1', completed: false, }, { id: '2U9frg1Z1W1o1DE=', - number: '002', + description: '002', name: 'Task 2', completed: false, }, { id: '2Ug11Z1dv1W1og1DE=', - number: '003', + description: '003', name: 'Task 3', completed: false, }, { id: 'gxfas1cczg1ff1DE=', - number: '004', + description: '004', name: 'Task 4', completed: false, }, { id: '2Uxfg1ka1Zga1o1DE=', - number: '005', + description: '005', name: 'Task 5', completed: false, }, { id: '2z11Uxgfg1kaza1DE=', - number: '006', + description: '006', name: 'Task 9', completed: false, }, { id: '2Uxgfg1ka1Zga11DE=', - number: '007', + description: '007', name: 'Task 7', completed: false, }, { id: '2Uxfag3ka1Zga1o1DE=', - number: '008', + description: '008', name: 'Task 8', completed: false, }, { id: '2Uxfg7ka1Zga1o1DE=', - number: '009', + description: '009', name: 'Task 9', completed: false, }, { id: '2Ugg7ka1Zg31o1DE=', - number: '010', + description: '010', name: 'Task 10', completed: false, }, diff --git a/server/data/Todo/GET_TODO_LIST_PAGE_1.js b/server/data/Todo/GET_TODO_LIST_PAGE_1.js index b2ac349..eaf3e54 100644 --- a/server/data/Todo/GET_TODO_LIST_PAGE_1.js +++ b/server/data/Todo/GET_TODO_LIST_PAGE_1.js @@ -2,7 +2,7 @@ module.exports = { content: [ { id: '5Uxfhxka1Zga1o1DE=', - number: '011', + description: '011', name: 'Task 11', completed: false, }, diff --git a/server/routes.json b/server/routes.json index 6a2a643..d16bb70 100644 --- a/server/routes.json +++ b/server/routes.json @@ -1,6 +1,6 @@ { "*/v1/user/logged": "/GET_USER_LOGGED", - "*/v1/todo/detail/:id": "/GET_TODO_BY_ID", "*/v1/todo/all\\?page=0": "/GET_TODO_LIST", - "*/v1/todo/all\\?page=1": "/GET_TODO_LIST_PAGE_1" + "*/v1/todo/all\\?page=1": "/GET_TODO_LIST_PAGE_1", + "*/v1/todo/:id": "/GET_TODO_BY_ID" } diff --git a/src/App.js b/src/App.js index 7bd7f50..a8e4774 100644 --- a/src/App.js +++ b/src/App.js @@ -9,7 +9,6 @@ import Shell from './components/Shell/Shell'; import Routes from './routes/Routes'; import './App.css'; -import CenteredContent from './components/Layout/CenteredContent'; function App() { const { t } = useTranslation(); @@ -20,9 +19,7 @@ function App() { - - - + ); diff --git a/src/auth/Components/Validator.js b/src/auth/components/Validator.js similarity index 100% rename from src/auth/Components/Validator.js rename to src/auth/components/Validator.js diff --git a/src/auth/Components/Validator.test.js b/src/auth/components/Validator.test.js similarity index 86% rename from src/auth/Components/Validator.test.js rename to src/auth/components/Validator.test.js index 4188bac..dda9766 100644 --- a/src/auth/Components/Validator.test.js +++ b/src/auth/components/Validator.test.js @@ -3,7 +3,7 @@ import React from 'react'; import '@testing-library/jest-dom/extend-expect'; import { render, waitFor, screen, serverCustom } from '../../util/TestSetup'; import ComponentValidator from './Validator'; -import APIProvider from '../../util/URL/APIProvider'; +import APIProvider from '../../util/api/url/APIProvider'; describe('Validator.js Test Suite', () => { const GET_USER_LOGGED_RESPONSE = { @@ -25,7 +25,7 @@ describe('Validator.js Test Suite', () => {

{childText}

, - { route: '/todo/list' }, + { route: '/todo/all' }, ); const child = await waitFor(() => screen.getByText(childText)); @@ -39,22 +39,23 @@ describe('Validator.js Test Suite', () => {

{childText}

, - { route: '/todo/list' }, + { route: '/todo/all' }, ); const child = await waitFor(() => screen.getByText(childText)); expect(child).toBeInTheDocument(); }); - test('should not appear in the document', async () => { + test.only('should not appear in the document', async () => { const childText = 'inner text'; render(

{childText}

, - { route: '/todo/list' }, + { route: '/todo/all' }, ); + console.log('PATHHHHHH', window.location.pathname); const child = screen.queryByAltText(childText); expect(child).not.toBeInTheDocument(); diff --git a/src/auth/Components/__snapshots__/Validator.test.js.snap b/src/auth/components/__snapshots__/Validator.test.js.snap similarity index 100% rename from src/auth/Components/__snapshots__/Validator.test.js.snap rename to src/auth/components/__snapshots__/Validator.test.js.snap diff --git a/src/auth/Routes/Validator.js b/src/auth/routes/Validator.js similarity index 100% rename from src/auth/Routes/Validator.js rename to src/auth/routes/Validator.js diff --git a/src/components/Form/FieldBase/FieldBase.js b/src/components/Form/FieldBase/FieldBase.js new file mode 100644 index 0000000..bcfd4d9 --- /dev/null +++ b/src/components/Form/FieldBase/FieldBase.js @@ -0,0 +1,19 @@ +import React from 'react'; + +import { FlexBox, FlexBoxDirection } from '@ui5/webcomponents-react'; +import Label from '../Label/Label'; + +const FieldBase = ({ labelText, ...props }) => { + return ( + + {labelText && ( + + )} + {props.children} + + ); +}; + +export default FieldBase; diff --git a/src/components/Form/FieldBase/FieldBase.test.js b/src/components/Form/FieldBase/FieldBase.test.js new file mode 100644 index 0000000..2c01525 --- /dev/null +++ b/src/components/Form/FieldBase/FieldBase.test.js @@ -0,0 +1,40 @@ +import React from 'react'; + +import '@testing-library/jest-dom/extend-expect'; +import { render, screen } from '../../../util/TestSetup'; + +import FieldBase from '../FieldBase/FieldBase'; + +describe('FieldBase.js Test Suite', () => { + beforeEach(() => { + render( + +

Some Inner Text

+
, + ); + }); + + test('should match snapshot', () => { + const { asFragment } = render( + +

+
, + ); + + expect(asFragment()).toMatchSnapshot(); + }); + + test('should render', () => { + const component = screen.getByTestId('fieldbase-wrapper'); + + expect(component).toBeInTheDocument(); + }); + + test('should render with Inner Component with Text Content as text', () => { + const component = screen.getByTestId('fieldbase-wrapper'); + const innerComponent = screen.getByTestId('inner-component-wrapper'); + + expect(component).toBeInTheDocument(); + expect(innerComponent).toHaveTextContent('Some Inner Text'); + }); +}); diff --git a/src/components/Form/FieldBase/__snapshots__/FieldBase.test.js.snap b/src/components/Form/FieldBase/__snapshots__/FieldBase.test.js.snap new file mode 100644 index 0000000..ea39cae --- /dev/null +++ b/src/components/Form/FieldBase/__snapshots__/FieldBase.test.js.snap @@ -0,0 +1,31 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`FieldBase.js Test Suite should match snapshot 1`] = ` + +
+ Label { + "_domRefReadyPromise": Promise { + "_deferredResolve": [Function], + }, + "_firePropertyChange": false, + "_fullyConnected": false, + "_inDOM": false, + "_monitoredChildProps": Map {}, + "_shouldInvalidateParent": false, + "_state": Object { + "for": "", + "required": false, + "showColon": false, + "wrap": true, + }, + "_upToDate": false, + } +

+

+
+`; diff --git a/src/components/Form/Input/Input.js b/src/components/Form/Input/Input.js new file mode 100644 index 0000000..e853d94 --- /dev/null +++ b/src/components/Form/Input/Input.js @@ -0,0 +1,24 @@ +import React from 'react'; + +import { spacing } from '@ui5/webcomponents-react-base'; +import { Input as UI5Input, ValueState } from '@ui5/webcomponents-react'; +import FieldBase from '../FieldBase/FieldBase'; + +const Input = ({ field, form: { touched, errors }, labelText, style, ...props }) => { + const errorMsg = touched[field.name] && errors[field.name]; + const errorState = errorMsg ? ValueState.Error : ValueState.None; + + const innerStyle = { + ...style, + ...spacing.sapUiTinyMarginBottom, + width: '100%', + }; + + return ( + + {errorMsg}} style={innerStyle} {...props} {...field} /> + + ); +}; + +export default Input; diff --git a/src/components/Form/Input/Input.test.js b/src/components/Form/Input/Input.test.js new file mode 100644 index 0000000..93faf57 --- /dev/null +++ b/src/components/Form/Input/Input.test.js @@ -0,0 +1,32 @@ +import React from 'react'; + +import '@testing-library/jest-dom/extend-expect'; +import { render, screen } from '../../../util/TestSetup'; + +import Input from '../Input/Input'; + +describe('Input.js Test Suite', () => { + test('should match snapshot', () => { + const { asFragment } = render(); + + expect(asFragment()).toMatchSnapshot(); + }); + + test('should have rendered with the fieldbase', () => { + render(); + + const fieldbase = screen.getByTestId('fieldbase-wrapper'); + const component = screen.getByTestId('input-wrapper'); + + expect(fieldbase).toBeInTheDocument(); + expect(component).toBeInTheDocument(); + }); + + test('should have attribute name as description if passed', () => { + render(); + + const component = screen.getByTestId('input-wrapper'); + + expect(component).toHaveProperty('name', 'description'); + }); +}); diff --git a/src/components/Form/Input/__snapshots__/Input.test.js.snap b/src/components/Form/Input/__snapshots__/Input.test.js.snap new file mode 100644 index 0000000..5a2c19f --- /dev/null +++ b/src/components/Form/Input/__snapshots__/Input.test.js.snap @@ -0,0 +1,39 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Input.js Test Suite should match snapshot 1`] = ` + +
+ Label { + "_domRefReadyPromise": Promise { + "_deferredResolve": [Function], + }, + "_firePropertyChange": false, + "_fullyConnected": false, + "_inDOM": false, + "_monitoredChildProps": Map {}, + "_shouldInvalidateParent": false, + "_state": Object { + "for": "", + "required": false, + "showColon": false, + "wrap": true, + }, + "_upToDate": false, + } + + + +
+
+`; diff --git a/src/components/Form/Label/Label.js b/src/components/Form/Label/Label.js new file mode 100644 index 0000000..a8aa5e8 --- /dev/null +++ b/src/components/Form/Label/Label.js @@ -0,0 +1,20 @@ +import React from 'react'; + +import { spacing } from '@ui5/webcomponents-react-base'; +import { Label as UI5Label } from '@ui5/webcomponents-react'; + +const Label = ({ style, ...props }) => { + const innerStyle = { + ...style, + ...spacing.sapUiTinyMarginBottom, + lineHeight: '20px', + }; + + return ( + + {props.children} + + ); +}; + +export default Label; diff --git a/src/components/Form/Label/Label.test.js b/src/components/Form/Label/Label.test.js new file mode 100644 index 0000000..64a6b10 --- /dev/null +++ b/src/components/Form/Label/Label.test.js @@ -0,0 +1,41 @@ +import React from 'react'; + +import '@testing-library/jest-dom/extend-expect'; +import { render, screen } from '../../../util/TestSetup'; + +import Label from '../Label/Label'; + +describe('Label.js Test Suite', () => { + test('should match snapshot', () => { + const { asFragment } = render( + , + ); + + expect(asFragment()).toMatchSnapshot(); + }); + + test('should render children', () => { + render( + , + ); + + const component = screen.getByTestId('label-wrapper'); + const inner = screen.getByTestId('inner-text-wrapper'); + + expect(component).toBeInTheDocument(); + expect(inner).toBeInTheDocument(); + }); + + test('should render with lineHeight of 20px', () => { + render(