patchamama / fullstackopen-Course-and-testing

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

fullstackopen-Course-and-testing

Deploy Examples

Part 1. Introduction to React

a. Introduction to React

npm create vite@latest
cd <install-dir>
npm install
npm run dev


Resources

b. JavaScript

Node.js is a JavaScript runtime environment based on Google's Chrome V8 JavaScript engine and works practically anywhere - from servers to mobile phones. The latest versions of Node already understand the latest versions of JavaScript, so the code does not need to be transpiled.

Arrays

The contents of the array can be modified even though it is defined as a const. Because the array is an object, the variable always points to the same object. However, the content of the array changes as new items are added to it.

const t = [1, -1, 3]
t.push(5) //[1, -1, 3, 5]
const t2 = t.concat(5) //t2 = [1, -1, 3, 5]

// destructuring assignment
const t = [1, 2, 3, 4, 5]
const [first, second, ...rest] = t
console.log(first, second) // 1, 2 is printed
console.log(rest) // [3, 4, 5] is printed

t.forEach((value) => {
  console.log(value) // numbers 1, -1, 3, 5 are printed, each on its own line
})

const m2 = t.map((value) => '<li>' + value + '</li>')
console.log(m2)
// [ '<li>1</li>', '<li>2</li>', '<li>3</li>' ] is printed

Functions

const sum = (p1, p2) => {
  console.log(p1)
  console.log(p2)
  return p1 + p2
}

const result = sum(1, 5)
console.log(result)

// If there is just a single parameter, we can exclude the parentheses from the definition:
const square = (p) => {
  console.log(p)
  return p * p

  // If the function only contains a single expression then the braces are not needed.
  const square = (p) => p * p

  const t = [1, 2, 3]
  const tSquared = t.map((p) => p * p)
  // tSquared is now [1, 4, 9]

  // There are two ways to reference the function; one is giving a name in a function declaration.
  function product(a, b) {
    return a * b
  }

  const result = product(2, 6)
  // result is now 12

  //The other way to define the function is by using a function expression.
  const average = function (a, b) {
    return (a + b) / 2
  }

  const result = average(2, 5)
  // result is now 3.5
}

Object methods and "this"

const arto = {
  name: 'Arto Hellas',
  age: 35,
  education: 'PhD',
  greet: function () {
    console.log('hello, my name is ' + this.name)
  },

  doAddition: function (a, b) {
    console.log(a + b)
  },
}

arto.doAddition(1, 4) // 5 is printed

const referenceToAddition = arto.doAddition
referenceToAddition(10, 15) // 25 is printed

Classes

class Person {
  constructor(name, age) {
    this.name = name
    this.age = age
  }
  greet() {
    console.log('hello, my name is ' + this.name)
  }
}

const adam = new Person('Adam Ondra', 35)
adam.greet()

const janja = new Person('Janja Garnbret', 22)
janja.greet()

JavaScript materials

https://fullstackopen.com/en/part1/java_script#classes

Resources

c. Component state, event handlers



Resources

d. A more complex state, debugging React apps



Complex state

It is forbidden in React to mutate state directly, since it can result in unexpected side effects

There are situations where it can be beneficial to store a piece of application state in a more complex data structure: https://react.dev/learn/choosing-the-state-structure

Debugging React applications

https://fullstackopen.com/en/part1/a_more_complex_state_debugging_react_apps#debugging-react-applications

Useful Reading

https://fullstackopen.com/en/part1/a_more_complex_state_debugging_react_apps#useful-reading

Web programmers oath

Full stack development is extremely hard, that is why I will use all the possible means to make it easier:

  • I will have my browser developer console open all the time
  • I will use the network tab of the browser dev tools to ensure that frontend and backend are communicating as I expect
  • I will constantly keep an eye on the state of the server to make sure that the data sent there by the frontend is saved there as I expect
  • I will keep an eye on the database: does the backend save data there in the right format
  • I progress with small steps:
    • when I suspect that there is a bug in the frontend, I make sure that the backend works for sure
    • when I suspect that there is a bug in the backend, I make sure that the frontend works for sure
  • I will write lots of console.log statements to make sure I understand how the code and the tests behave and to help pinpoint problems
  • If my code does not work, I will not write more code. Instead, I start deleting the code until it works or just return to a state when everything still was still working
  • If a test does not pass, I make sure that the tested functionality for sure works in the application

Part 2. Communicating with server

a. Rendering a collection, modules



JavaScript Arrays

Resources

b. Forms



c. Getting data from server

The browser as a runtime environment

npm install json-server --save-dev
npx json-server --port 3001 --watch db.json

In http://localhost:3001/notes will be the notes.

Plugin to browser JSONVue

  • Install axios
npm install axios

Resources



d. Altering data in server



e. Adding styles to React app



Part 5. Testing React apps

a. Login in frontend

// Primer terminal para ejecutar el backend nodeJS (part4)
cd part5/backend
npm run dev

// En un segundo terminal abierto para ejecutar react (part5 a partir de part2)
cd part5
npm run dev


b. props.children and proptypes


npm install prop-types
npm install --save-dev eslint-plugin-jest

See .eslintrc.cjs file and .eslintignore

c. Testing React apps

Install libraries (react-testing-library):

npm install jest babel-jest @babel/preset-env @babel/preset-react
npm install --save-dev @testing-library/react @testing-library/jest-dom jest-environment-jsdom @babel/preset-env @babel/preset-react
npm install --save-dev @testing-library/user-event

Extra configuration with vite.


d. End to end testing

Install Cypress:

npm install --save-dev cypress
npm install eslint-plugin-cypress --save-dev

Execute backend in test mode: cd backend && npm run start:test and frontend: npm run dev. Also in an additional terminal with cypress: npm run cypress:open



Part 6. Flux-architexture and Redux

a. Flux-architecture and Redux

npm create vite@latest
cd <install-dir>
npm install
npm run dev
npm install redux
npm install redux
npm install --save-dev jest @babel/preset-env @babel/preset-react eslint-plugin-jest
// add the library deep-freeze, which can be used to ensure that the reducer has been correctly defined as an immutable function
npm install --save-dev deep-freeze

Install test libraries and configuration

npm install redux

More components

b. Many Reducers

npm install @reduxjs/toolkit
console.log(JSON.parse(JSON.stringify(state)))

c. Communicating with server in a redux application

d. React Query, useReducer and the context

  • Managing data on the server with the React Query library
npm install @tanstack/react-query

Resources


Part 7. React router, custom hooks, styling app with CSS and webpack

a. React Router (v5)

Install react router:

npm install react-router-dom

See example using react Router, and the hooks useNavigate, useParams and useMatch here

b. Custom hooks

Let's define our own custom useField hook that simplifies the state management of the form:

const useField = (type) => {
  const [value, setValue] = useState('')

  const onChange = (event) => {
    setValue(event.target.value)
  }

  return {
    type,
    value,
    onChange,
  }
}

The hook can be used in the following way:

const App = () => {
  const name = useField('text')
  // ...

  return (
    <div>
      <form>
        <input type={name.type} value={name.value} onChange={name.onChange} />
        // ...
      </form>
    </div>
  )
}

Or with Spread attributes:

const App = () => {
  const name = useField('text')
  // ...

  return (
    <div>
      <form>
        <input {...name} />
        // ...
      </form>
    </div>
  )
}

As the example in the React documentation states, the following two ways of passing props to a component achieve the exact same result:

<Greeting firstName='Arto' lastName='Hellas' />

const person = {
  firstName: 'Arto',
  lastName: 'Hellas'
}

<Greeting {...person} />

Prototipo de hook para realizar peticiiones fetch con axios que se pueden usar en cualquier aplicación. Solo hay que actualizar baseURL y el token:

import axios from 'axios'
const baseUrl = '/api/notes'

let token = null

const setToken = (newToken) => {
  token = `bearer ${newToken}`
}

const getAll = async () => {
  const response = await axios.get(baseUrl)
  return response.data
}

const create = async (newObject) => {
  const config = {
    headers: { Authorization: token },
  }

  const response = await axios.post(baseUrl, newObject, config)
  return response.data
}

const update = async (id, newObject) => {
  const response = await axios.put(`${baseUrl}/${id}`, newObject)
  return response.data
}

export default { getAll, create, update, setToken }

c. React Bootstrap

Hay algunas versiones diferentes de React de Bootstrap como reactstrap y react-bootstrap.

Instalar react-bootstrap:

npm install react-bootstrap

Agregar en la sección del head en el archivo public/index.html:

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css"
  integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65"
  crossorigin="anonymous"
/>

Código de ejemplo aquí.

Material UI

Fuente: https://mui.com/

Instalar la librería:

npm install @mui/material @emotion/react @emotion/styled

Código de ejemplo aquí.

Ejecutar un servidor local para archivos estáticos. Ejecutar este comando en el directorio con el index:

npx static-server

Algunos comandos útiles

Puede verificar qué tan actualizadas están sus dependencias usando el comando:

npm outdated --depth 0

Las dependencias se pueden actualizar actualizando el archivo package.json y ejecutando el comando:

npm install -g npm-check-updates
npm-check-updates

El archivo package.json se actualiza ejecutando el comando ncu -u y npm install.

Para revisar dependencias con problemas de seguridad (npm audit) y hacer las correcciones: npm audit fix. El comando npm audit fix --force puede determinar en actualizaciones major que pueden colapsar la aplicación.

Seguridad

La documentación de Express incluye una sección sobre seguridad: Prácticas recomendadas de producción: seguridad, que vale la pena leer. También se recomienda agregar una librería llamada Helmet al backend. Incluye un conjunto de middlewares que eliminan algunas vulnerabilidades de seguridad en aplicaciones Express.

También vale la pena usar el plugin de seguridad de ESlint.

Instalar y configurar prettier:

npm install --save-dev --save-exact prettier
node --eval "fs.writeFileSync('.prettierrc','{\n\"trailingComma\": \"none\",\n\"tabWidth\": 2,\n\"semi\": false,\n\"singleQuote\": true,\n\"editor.formatOnSave\": true\n}\n')"
node --eval "fs.writeFileSync('.prettierignore','build\ncoverage')"

Fuente: https://prettier.io/docs/en/install


Part 9. TypeScript

README


Part 11. Continuous Integration / Continuous Delivery systems (CI/CD)

README


Part 12. Containers

README


Part 12. Using relational databases

README

About


Languages

Language:JavaScript 53.5%Language:HTML 35.5%Language:CSS 6.1%Language:TypeScript 3.3%Language:Dockerfile 1.5%Language:Pug 0.1%Language:Procfile 0.0%