Skip to content

marcuasc/Webutvikling

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 

Repository files navigation

Prosjekt 4b

Denne filen inneholder gruppens dokumentasjon fra prosjekt 3, samt en egen seksjon nederst i filen som viser til hvilke endringer som er gjort til leveransen av Prosjekt 4

Oversikt

Vi har laget en nettside der brukere kan søke etter filmer. Brukeren kan søke på filmtittler, filtrere på sjanger, filtrere på budsjett og filtrere på filmens lengde. Resultatsettet som passer med brukerens valg blir vist på listeform med tittel og bilde. Brukeren kan også sortere resultate etter tittel(alfabetisk/motsatt alfabetisk), varighet(stigende/synkende) og budsjett(stigende/synkende).

Alle filmene kan trykkes på for å vise ekstra informasjon. Her kan brukeren gi den valgte filmen en vurdering fra 1-5. Dette kan kun gjøres en gang per film per session.

Til høyre i headeren befinner det seg en knapp der brukeren kan bytte mellom light/darkmode.

Installasjon

Hvordan kjøre prosjektet

  • Lag en mappe der du kloner repoet.
  • Installer Node.js
  • Naviger deg inn i server mappen, og skriv npm installfor å installere nødvendige pakker. Deretter skriv npm start i terminalen for å starte backend
  • Åpne en ny terminal, naviger deg inn i client mappen, og skriv npm installfor å installere nødvendige pakker. Deretter skriv npm start for å starte frontend

Hvordan kjøre tester frontend

  • Naviger deg inn i clientmappen, og skriv npm test
  • For at cypress skal funke må både client og server kjøre

Hvordan kjøre tester backend

  • Avslutt prosessen som kjører backend
  • Naviger deg inn i servermappen, og skriv npm test

Merknader

  • Merk at man må være koblet til NTNU-nettverket (enten ved å være på NTNU, eller bruke VPN) for at serveren skal kunne koble seg til databasen.
  • VPN kan forårsake noen tester til å "time ut"

Backend

Film-objekter Databasen vår består kun av film-objekter.

Et film objekt ser slik ut:

movie: {
    title: {String},
    poster_path: {String},
    genre: {Array<String>},
    desc: {String},
    budget: {Number},
    release_date: {Date},
    duration: {Number},
    ratings: {Array<Number>}
}

Vi har valgt å lagre alle vurderinger av filmer som et array i hver film. Når er film hentes fra databasen blir gjennomsnittet av vurderingene regnet ut og returnert sammen med filmen.

poster_path inneholder en lenke til den valgte filmens poster på TMDB.

Rest API

Vi har laget et Rest-API for å kunne sende og hente data fra databasen. APIet er basert på express og mongoose, og er skrevet i JavaScript.

Vi har valgt å lage Rest-API i JavaScript ettersom gruppens medlemmer hadde erfaring med dette fra tidligere prosjekter.

APIet består av tre filer: index.js, routes/movie.js og model/movie.js.

index.js tar seg av koblingen til databasen, CORS-tillatelse og routing til riktig endepunkt.

model/movie.js inneholder skjemaet for hvilke atributter som inngår i en movie-objekt.

routes/movie.js inneholder tre endepunkter for å muliggjøre ønsket interaksjon med databasen.

router.get(/) er hovedmetoden som tar seg av søk på tittel, filtrering, sortering og pagination. Metoden tar inn et filtreringsobjekt fra makeFindObject() og et sorteringsobjekt fra makeSortObject() , og sender en GET-request til databasen med den generete adressen.
makeFindObject() og makeSortObject() tar inn et queryobjekt fra klienten ved hjelp av pakken qs, og genererer adressen som samsvarer med brukerens valg.

router.get(/) returnerer title og poster_path på filmobjektene som passer med søket, samt antall sider med filmer og hvilket side det hentes fra.

router.get(/id/:id) brukes for å finne alle atributtene til et filmobjekt, bestemt på ID. Denne metoden benyttes når en bruker trykker seg inn på en film for å se flere detaljer om filmen.

router.put(/id/:id) brukes for å oppdatere rangeringen på en film.

Database Databasen vår kjøres på NTNUs virituelle maskiner.

Databasen består av 1000 filmer. Dette er en tilstrekkelig mengde for å kunne teste nettsiden da alle sjangere er representert i et eksisterende film-objekt.

Filtrering på nedre/øvre for budsjett for en film vil naturligvis ikke gi noen treff for veldig høye/lave verdier, men dette kan ikke løses med større dataset. Det sammen gjelder nedre/øvre grense for sortering på varighet.

Datasettet er generert av en egen JSON-mapper gruppen har skrevet i JavaScript. Denne er ikke inkludert i leveransen til prosjektet. Vi hentet data gjennom APIet til TMDB, og mappet det om til å inneholde atributtene vi ønsket. Alle filmene i databasen inneholder originalt to vurderinger, som er tilfeldig generert.

Frontend

Typescript og React Frontend er (selvfølgelig) laget i React. Hele frontend delen bruker TypeScript på en god og hensiktsmessig måte.
Redux Vi bruker Redux for state management i vår applikasjon. All implementasjon av Redux ligger i mappen /src/redux.

Vi har delt opp Redux state management i flere reducers, hver til sin del av applikasjonen. Vi har delt det opp i search, sort, result og filter. Disse blir satt sammen igjen til en reducer i rootReducer.ts. Dette har vi gjort for å få en oversiktlig, hensiktsmessig og konsekvent implementasjon av state management.

Vi bruker redux-thunk for asynkrone handlinger, react-redux for å gi tilgang til state for alle komponenter og redux-devtools-extension for loggføring og debugging av redux.

I en ekte release ville vi fjernet redux-devtools-extension i og med at det kan åpne uønsket insikt i applikasjonen.

Under vil du se en ganske detaljert beskrivelse av hvordan vi bruker redux og hvorfor vi mener vi vise Videregående kunnskap og ferdigheter i state management.

Search

Denne delen av redux har ansvar for å holde informasjon angående (you guessed it) søk. Den holder oversikt om man fåreløpig søker, hvilket resultater man har fått, om man har fått en error på søket, hva man søkte på var, hvilken side man er på og hvor mange sider totalt søket ga.

Search har en del actions som komponenter kan ta i bruk, bla. fetchResults. Dette er en asynkron action, satt sammen av flere actions for å requeste resultater, og avhenging av respons, vise resultatene eller vise error av requesten. (Mer om dette i Rest API og Axios)

Komponentene som bruker denne delen av redux er: SearchResults, SearchBar og PageContainer.

Sort

Denne delen av redux har ansvar for å holde styr på hvordan resultatene ønskes å sorteres. Den holder informasjon om type sortering og i hvilken retning det ønskes.

Sort har actions for å oppdatere denne informasjonen som komponenter kan bruke.

Komponentene som bruker denne delen av redux er: SearchResults og SortSelect

Result

Denne delen av redux har ansvar for å holde styr på resultatet (filmen) brukeren for øyeblikket ønsker å se. Den holder informasjon om MovieDialog skal være åpen, om den foreløpig laster inn resultatet og om den fikk en error når den lastet inn. Den holder også all informasjonen om resultatet som den får Rest API'et.

Result har flere actions som komponenter kan ta i bruk, bla. fetchMovie og putRatings som begge er asynkrone handlinger. Mer om dette i Rest API og Axios.

Komponenter som tar i bruk denne delen av redux er: ResultContainer, CustomizedRatings og MovieDialog.

Filter

Denne delen av redux har ansvar for hvordan brukeren ønsker å filtrere på søket sitt. Den holder informasjon på om FilterDialog skal være åpen og på hilke sjangre, lengde og budsjett søket skal filtrere på.

Filter har actions vår å sette disse variablene.

Komponentene som tar i bruk denne delen av redux er: FilterDialog og SearchResults

Tredjepartskomponenter (MaterialUI) I dette prosjektet har vi brukt mange tredjepartskomponenter fra [Material UI](https://material-ui.com/). Vi valgte dette biblioteket av komponenter fordi det er meget populært (brukt av store firmaer som Nasa, Netflix og Amazon), det har god (ikke perfekt) støtte for TypeScript og det dekker alle våre behov for tredjepartskomponenter i dette prosjektet.

Ved å velge tredjepartskomponenter fra ett bibliotek, oppnår vi en gjennomgående stil med ekstra funksjonalitet som vi kanskje ellers ikke kunne fått (mer om dette i Design og responsivitet).

For å nevne noen komponenter fra MUI som vi bruker: MUIThemeProvider, Box, Appbar, Toolbar, Button, IconButton, Dialog, Rating og mer.

Dette er begrunnelsen vår til hvorfor vi mener at vi viser Videregående ferdigheter i å finne og velge gode tredjeparts komponenter.

Søk, sortering, filtrering og store sett av data

Info her

I frontend er det én komponent som har ansvar for å kalle selve søket. Det er SearchResults. Vi synes det er passende fordi det er denne komponenten som skal holde alle resultatene.

Søket blir utført gjennom redux handlingen fetchResults. Denne tar inn et parameter object er definert etter ParamsInterface:

interface ParamsInterface {
    q: string;
    page: number;
    genre?: Array<string>;
    duration?: {
        gt: number;
        lt: number;
    };
    budget?: {
        gt: number;
        lt: number;
    };
    sortBy: {
        type: "title" | "duration" | "budget";
        descending: boolean;
    };
}

(q står for query, gt for greater than og lt for less than) Dette er alle måtene man kan påvirke søktet på. fetchResults tar inn dette objectet, stringifier det ved hjelp av qs og utfører en get request med parameterne. (Se Rest API og Axios). Avhengig av svaret blir en success eller failure handling dispatchet.

Parameterne i parameter objektet er som sagt definiert i redux staten til alle tider. Når noen av disse endres i redux staten, vil SearchResults kalle fetchResults med oppdatert parameter objekt ved hjelp av useEffecthooken.

For å behandle store sett av data, bruker vi pagination. Hvert søk gir antall sider med i søket. Dette blir satt i staten, sammen med hvilken side man er på. Dette går videre til PageContainer som er et interaktivt display av sider. PageContainer kan oppdatere CurrentPage i redux staten som trigger et nytt søk.

Vi kunne i teorien hatt MANGE flere filmer i og med at frontend henter kun 12 filmer om gangen, uansett hvor mange som passer parameterne.

Dette er vår begrunnelse for hvorfor vi mener vi viser Videregående kunnskap og ferdigheter i søk, sortering, filtrering og representasjon av store sett av data.

Rest API og Axios

Info her Frontend bruker Axios for a sende get og put requests til backend. Alle kall til Rest API'et blir behandlet gjennom redux for en stabil og forutsigbar interaksjon med backend.

Vi har tre redux actions som kommuniserer med API'et, fetchResults, fetchMovie og putRatings. Siden disse kommuniserer med API'et, er alle asynkrone. Vi har derfor brukt redux-thunk i implementasjonen av disse handlingene.

Hvis noen av axios kallene failer, blir de fanget og korrekte actions for å behandle feilene blir kallt.

Design og responsivitet

Info her

Designet på siden vår blir stort sett definert av Material UI sine komponenter. Biblioteket er stilrent og moderne.

Siden vi bruker bare komponenter fra MUI, har vi muligheten til å implementere themes ved hjelp av MUIThemeProvider. Denne gir tilgang til det nåværende temaet for alle child komponenter. Dette har vi brukt til å implementere farger som går gjennom hele veien. Vi har en hovedfarge og en sekundærfarge. Begge to har definert lys og mørk versjon av seg selv.

Vi bruker også dette til å implementere darkmode/lightmode etter hva brukeren ønsker. Knappen til høyre i AppBar sørger for at darkMode staten i App.tsxblir togglet. Dette gjenspeiles da i hvert eneste child til MUIThemeProvider.

Applikasjonen er så responsiv som mulig og fungerer godt på skjermer helt ned til 320x320 px. Vi har fått til dette ved MYE bruk av flex.

Testing

End-2-end

Vi bruker Cypress for end-2-end testing av nettsiden vår.

Testene ligger i /client/cypress/integration/test.js og består av syv tester.

Testene simulerer bruk av de mest sentrale brukstilfellene av nettsiden:

  • Søk på tittel
  • Filtrering på sjanger
  • Filtrering på budsjett
  • Filtrering på varighet
  • Sortering på tittel
  • Sortering på budsjett
  • Sortering på varighet
  • Vise ekstra informasjon om valgt film
Enhetstesting

Til enhetstesting på nettsiden vår bruker vi Jest.

Testene finnes i client/src/components/__tests__/

Vi har 4 forskjellige Testsuites med 6 tester totalt:

  • App.test.tsx, som tester at appen renderer uten å krasje
  • MovieDialogTest.test.tsx, som tester at Dialogen er åpen når staten sier at den skal være det.
  • ReduxStoreTest.test.tsx, som tester at action skjedde i storen når den blir dispatchet
  • SearchResultTest.test.tsx, som tester at Result har riktig state etter at en action har blitt kjørt.

For å kjøre alle testene skriver du npm test i client

Git & kode

Git Vi har brukt git til å dele opp utviklingsprosessen i issues. Nye branches ble laget for hvert issue, og alle et uniformt navn på formen `issue-xx-beskrivelse-her`. På denne måten er det lett å se hva som er blitt jobbet på i hver branch. Merge-requester knyttes til hvilket issue det jobber på eller avslutter. Dette gir en ryddig historikk, der endringer tilbake i tid lett kan finnes, dersom det blir behov for det.

Alle merge-requester har blitt sett gjennom av et annent gruppemedlem for å forsikre oss om at koden som merges er feilfri.

Kode Koden er kommentert der det kan være utfordrende å forstå hva den gjør.

Prosjektet er delt opp i to moduler: client og server.

client inneholder alt av komponenter, redux, grensesnitt og tester.

server inneholder Rest-APIet, med medfølgende sjema, ruter og endepunkter.

Endringer i prosjekt 4

Backend Til prosjekt 4 har vi utvidet REST-apiet vår betydelig. Vi har implementert funksjonalitet for å lage brukere og logge inn som en bruker. Vi har brukt biblioteket [Passport](http://www.passportjs.org/packages/passport-jwt/) til å hashe brukernes passord på databasen, samt for å dele ut gyldige tokens til brukere som er logget inn.

Vi har brukt tokens for adgangskontroll på de forskjellige endepunktene, og har på denne måten laget et meget sikkert API.

Vi har også endret modelleringen av databasen, til å inneholde egne objekter for users og reviews.

Hvert review er koblet opp mot brukeren som skrev det og filmen den vurderer. Hver bruker har en liste med reviews den har skrevet, og alle filmer har en liste med reviews som omhandler den gitte filmen.

Objekter

De nye objektene våre ser nå slik ut:

movie: {
    title: {String},
    poster_path: {String},
    genre: {Array<String>},
    desc: {String},
    budget: {Number},
    release_date: {Date},
    duration: {Number},
    reviews: {Array<reviews>}
}
User: {
    username: {String},
    hash: {String},
    salt: {Array<String>},
    reviews: {Array<reviews>}
}
Review: {
    reting: {Number},
    text: {String},
    userID: {User},
    movieID: {Movie},
}
Endepunkter

Med to helt nye typer objekter var vi også nødt til å utvide antall endepunkter.

De nye endepunktene ser nå slik ut:

GET movie/ er ikke endret siden sist, og bruker fortsatt til søk på tittel, sorterting og filtrering av filmer.

GET movie/:id brukes til å returnere en film på ID, samt å iterere gjennom tilhørende reviews og returnere gjennomsnittsvurderingen av filmen.

GET movie/:id/reviews brukes til å returnere alle tilhørende reviews til for en gitt film.

GET review/:id returnerer et review på ID. Denne behøver ikke gyldig token, da alle brukere skal kunne se reviews.

POST review/ legger til et nytt review av en film. Denne krever gyldig token, da kun innloggede brukere skal kunne legge til nye vurderinger

DELETE review/:id sletter et valgt review på ID. Denne krever gyldig token, og at det er brukeren som skrev reviewet som sletter det.

PUT review/:id oppdaterer et valgt review på ID. Denne krever gldig token, og at det er brukeren som skrev reviewet som oppdaterer det.

GET user/:id returnerer en bruker med ID, brukernavn og tilhørende reviews.

POST user/login brukes for å logge inn om bruker. Returnerer token som er gyldig i 1 dag.

POST user/register registrerer en ny bruker, dersom valgt brukernavn ikke allerede er i bruk.

DELETE user/:idsletter en bruker. Sjekker om token er gyldig og at brukere kun kan slette sin egen bruker.

Frontend

Ny funksjonalitet Nye ting som brukeren kan gjøre:
  • Registrere bruker
  • Logge inn
  • Logge ut
  • Slette bruker
  • Skrive reviews på filmer
  • Oppdatere sine reviews på filmer
  • Slette sine reviews på filmer
  • Se alle sine egne reviews på filmer
  • Se andre brukere sine reviews
  • Se på informasjon om andre brukere
  • Se alle reviews på en film
  • Få respons i form av en alert i forhold til brukerhandlinger
  • Få korrekt side vist basert på url
Komponenter

I frontend har vi lagt til og slettet komponenter for å få implementert den nye funksjonaliteten:

Komponenter som er fjernet:

  • CustomizedRatings
    • Denne slettet vi fordi rating av filmer ble lagt inn i nye komponenter.
  • MovieDialog
    • Denne slettet vi fordi filminformasjon ble lagt flyttet til MoviePage.
  • ResultContainer
    • Ikke egentlig slettet, bare reformatert til MovieContainer.
  • SearchContainer
    • Denne slettet vi fordi den var litt unødvendig. Dens innhold ligger på i SwitchContainer.

Komponenter som er lagt til:

  • BackButton
    • Siden vi nå har begynt å bruke react-router-dom for navigasjon i frontend, la vi inn en tilbakeknapp som går til forrige side.
  • CustomSnackbar
    • Denne komponenten har ansvaret for å holde alle alerts som blir gitt til brukeren. Koblet til alert i redux.
  • LoginRegisterContainer
    • Denne komponenten har ansvaret for å logge inn/registrere brukeren med brukernavn og passord. Lagrer "currentuser" i localStorage.
  • MovieContainer
    • Ikke egentlig ny, nye versjonen av ResultContainer.
  • MoviePage
    • Denne komponenten har nå ansvaret for å vise informasjon om filmene. Vises på url movie/:id hvor :id er id til film.
  • ReviewContainer
    • Denne komponenten har ansvaret for å vise alle reviews til enten film eller bruker. "Child" av MoviePage og UserPage.
  • ReviewPage
    • Denne komponenten viser informasjon om et review og gir brukeren mulighet til å slette/oppdatere hvis brukeren er eier. Vises på url review/:id hvor :id er id til review.
  • SwitchContainer
    • Denne komponenten har ansvaret for å "rendere" riktige komponenter basert på url'en.
  • UserPage
    • Denne komponenten har ansvaret for å vise informasjon om brukere. Hvis brukeren ser på sin egen bruker, kan man logge ut eller slette bruker.
  • UserReview
    • Denne komponenten har ansvaret for å la brukeren skrive et nytt review til en film. Hvis brukeren allerede har skrevet et review til filmen, viser denne det reviewet.

Mindre endringer har også blitt gjort i (nesten alle) andre komponenter.

Redux Vi har også gjort noen endringer i redux'en vår, spesifikt lagt til flere deler.

Nytt i redux:

  • alert
    • Denne delen har ansvaret for å holde informasjon og behandle om hvilken alert som forløpig vises.
    • Kontrollerer i stor fra komponenten CustomizedSnackbar
  • movie
    • Endret result fra prosjekt-3 til movie. Denne har ansvaret for å holde og behandle informasjon om filmen som foreløpig blir sett på.
    • Oppdatert for oppdaterte objekter fra backend.
  • review
    • Denne delen har ansvaret for å holde og behandle informasjon om reviews til enten film eller bruker. Holder også informasjon om et enkelt review som man ser på.
  • user
    • Denne delen har ansvaret for å holde og behandle informasjon om bruker som er logget inn og hvilken bruker som blir sett på.
    • Henter informasjon fra localStorage hvis det eksisterer.

Mindre endringer har også blitt gjort i andre deler av redux for å passe den nye funksjonaliteten.

Tester

I prosjekt 4 har vi systematisk enhetstestet både backend og frontend. Under står det forklart hvilke teknologier vi har brukt til testing og hva som blir testet. I tillegg til enhetstester har vi lagt til flere end-2-end tester etterhvert som vi har lagt til mer funksjonalitet.

Backend

Vi har brukt Chai, Mocha og Supertest for å teste API-et vårt, og har tilsammen skrevet 36 tester.

Testene ligger i server/test, og sjekker alle endepunktene. De sjekker hovedsaklig situasjoner der API-et returnerer feilmeldinger, da vi ikke har satt opp en mock-database til å gjøre persistente endringer på.

Testene sjekker ting som å gjøre handlinger uten gyldig token, POST med ugyldig format på body, endre andre brukeres reviews osv.

Frontend For testing av frontend har vi lagt vekt på å få dekket komponenter og redux (siden håndtering av state og annen funksjonalitet hovedsaklig er gjort gjennom redux). Vi har 27 testsuites med totalt 79 tester derav 16 snapshottest og 63 enhetstester.

Vi har brukt Jest og vi har tatt i bruk React testing library + @testing-library/user-event for simulere brukerhandling.

Enhetstestene ligger i client/components/__tests__
Snapshottestene ligger client/components/__tests__/snapshotTests

Enhetstesting av Komponenter

For testing av komponentene har det blitt brukt blant annet userEvents for å simulere f.eks onClick og typing.

Diverse ting som blir testet:

  • Det sjekkes at komponenter renderer korrekt
  • Det som blir skrevet inn i input felt er det samme som blir hentet ut
  • Sjekker at onClick blir kallt ('called') på komponenter som har onClick
  • Sjekker at komponenter finnes på nettsiden etter den har renderet

Enhetstesting av Redux

For enhetstesting av redux, har vi brukt nock for mocking av api'et og redux-mock-store for mocking av redux store.

Ting som blir testet:

  • At asynkrone redux actions dispatcher rikitige redux actions og i riktig rekkefølge.
  • At redux actions har riktig effekt på en state.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published