diff --git a/README.md b/README.md index 9e28d7e5ed..260958071e 100644 --- a/README.md +++ b/README.md @@ -8,64 +8,34 @@ This means that we need to be sure that you can create and deploy Full Stack app ## Challenge -In this project you will be building up a small project that allows you to share your favourite Youtube videos with the world. We will be starting up with a very small MVP (Minimal Viable Product), and built on top of it to make it nicer and more useful. +In this project, you will be building up a small project that allows you to share your favourite YouTube videos with the world. We will be starting up with a very small MVP (Minimal Viable Product), and build on top of it to make it nicer and more useful. -## Levels +## User stories ๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ’ป -The project requirements are split into several levels that you should complete during each week of this project. +Most of the core features for this project have been captured on **user story** issues. You can view all the user story issues on the project planning board: [User story issues](https://github.com/orgs/CodeYourFuture/projects/169/views/3). User story issues define a particular feature through a user story. They also link through to other issues you'll need to implement for this user story to be complete. -You can find each of the levels split into separate files, linked below. +## Requirements -**Note:** Some of the levels are optional which means that you can build a working project without them. However, to make something really impressive you will need to complete as much as you can. +All the requirements for this project are captured as issues that you can find on this planning board: [Full Stack Assessment Planner](https://github.com/orgs/CodeYourFuture/projects/169/views/2) + +**Note:** Some of the issues are optional which means that you can build a working project without them. However, to make something really impressive you will need to complete as much as you can. ### Week 1 - Minimal Viable Product -- [Level 100](./requirements/100.md) - - Defining requirements -- [Level 105](./requirements/105.md) - - Setting up the project -- [Level 110](./requirements/110.md) - - Building up the data model -- [Level 120](./requirements/120.md) - - Implementing the API -- [Level 130](./requirements/130.md) - - Implementing the frontend -- [Level 150](./requirements/150.md) - - Checking MVP adheres to the acceptance criteria -- [Level 199](./requirements/199.md) (Optional) - - Implementing code quality improvements +[Week 1 issues](https://github.com/orgs/CodeYourFuture/projects/169/views/2?filterQuery=sprint%3A1) ### Week 2 - Additional features -- [Level 200](./requirements/200.md) - - UX Improvements -- [Level 210](./requirements/210.md) - - Support for adding videos -- [Level 220](./requirements/220.md) - - Support for the removal of videos -- [Level 299](./requirements/299.md) (Optional) - - Implementing optional new features +[Week 2 issues](https://github.com/orgs/CodeYourFuture/projects/169/views/2?filterQuery=sprint%3A2) ### Week 3 - Finalizing project -- [Level 300](./requirements/300.md) - - Allowing rating of videos -- [Level 350](./requirements/350.md) - - Submitting solution for evaluation -- [Level 399](./requirements/399.md) (Optional) - - Making project viable as a portfolio piece +[Week 3 issues](https://github.com/orgs/CodeYourFuture/projects/169/views/2?filterQuery=sprint%3A3) ### Week 4 - Stretch goals -- Use this week as an extra time to implement missing required and optional features from previous weeks. -- [Level 499](./requirements/499.md) (Optional) - - Additional stretch goals to make your project really stand out - -## Getting Started - -Fork this repository and then clone it to your computer. - -Progress to [Level 100](./requirements/100.md) when you are ready. +Use extra time this week to implement missing required and optional features from previous weeks. +[Week 4 issues](https://github.com/orgs/CodeYourFuture/projects/169/views/2?filterQuery=sprint%3A4) ## Sample Solution diff --git a/guides/code-quality/readme.md b/guides/code-quality/readme.md new file mode 100644 index 0000000000..a09d66a0bd --- /dev/null +++ b/guides/code-quality/readme.md @@ -0,0 +1,106 @@ +# Code quality improvements (Optional) + +While the following work items are completely optional, they will help you to make fewer mistakes as you continue with future requirements. It is generally a good idea to have them when working on projects of any size. + +## 1) Proper error handling + +You should make your system to be designed with error handling in mind. For example if the database cannot be accessed when you call `GET /api/videos`, then your backend endpoint should return a properly formatted error message with a HTTP `500` error code. + +Here is an example response: + +```json +{ "success": false, "error": "Could not connect to the database" } +``` + +**Note:** You can design how you return error messages differently than the above example. You could also try and merge the error and non-error response styles into one. For example the standard `200` response on the same endpoint could be something like the following: + +```json +{"success":true,"videos":[(...)]} +``` + +Once you do this on the backend you should also change your frontend, to make sure it handles errors that are received. For example if your frontend receives an error like above it might show a message like `"Could not connect to the database, please reload the page at a later time"`. Remember, real users don't look in the console, so you'll need to work how where you want to display this error to the users so they see it. + +**Note:** Once you add this feature, make sure you keep handling errors properly during the week 2 and week 3 requirements as well. + +## 2) Prettying and linting + +It is also usually a good idea to make sure that your code is formatted based on a single standard throughout, and also passes basic checks. There are two projects that can usually help you with that: + +- `prettier` is a formatter that makes sure that your code is formatted the same way throughout. For example all files use `tab` characters for indenting. +- `eslint` is a linter that checks the code for common coding mistakes and warns you if it encounters any of them. It can also automatically fix some mistakes. + +Let's set up both of them! + +### `prettier` + +First install prettier into your `package.json` file: + +```sh +npm install prettier --save-dev +``` + +Next you will need a `.prettierrc` file in the root directory. We have already provided one for your convenience. + +You can now run prettier to check your files: + +```sh +npm exec prettier -- --check . +``` + +And also to automatically fix them: + +```sh +npm exec prettier -- --write . +``` + +If you don't want to type out these commands you can add them as `scripts` into your `package.json` file. For example you can add a line like: + +```json + "prettier": "prettier --write ." +``` + +to the scripts section, and then you'll be able to automatically pretty your files by typing: + +```sh +npm run prettier +``` + +### `eslint` + +Installing `eslint` is similar, but to get the most out of it you will need to install multiple projects: + +```sh +npm install eslint eslint-config-prettier eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-react-refresh eslint-plugin-react-hooks eslint-plugin-n eslint-plugin-jest eslint-plugin-jest-dom eslint-plugin-vitest eslint-plugin-testing-library @codeyourfuture/eslint-config-standard --save-dev +``` + +This will install `eslint`, and a couple plugins that help you with validating tests, JSX code and React components, like proper `useEffect` usage. + +You will also need to have multiple `.eslintrc.json` files, one for each project, tailored to that project's needs. These have also all been provided already. + +Once you have everything in place you can run the linter to check for common code mistakes: + +```sh +npm exec eslint . +``` + +You can also ask it to fix any issues it can automatically fix: + +```sh +npm exec eslint -- --fix . +``` + +Same as for `prettier`, you might want to add these commands to your `package.json` for easier access. + +### Checks during PRs + +It is a good idea to enforce running both the linter and prettier during PRs. One way to do that is to make sure GitHub runs these checks for every PR, blocking the PR in case the code doesn't pass these checks. We have already prepared the `.github/workflows/enforce-linting.yml` file that you can use to run checks on GitHub manually. If you also uncomment the `pull_request` line, you will enable GitHub to run these checks automatically on every PR. + +To confirm, the top of the file should look like this: + +```yaml +on: + workflow_dispatch: + pull_request: +``` + +**Note:** Make sure to have a full read of this file and try to figure out what it does. diff --git a/guides/db-setup/readme.md b/guides/db-setup/readme.md new file mode 100644 index 0000000000..0fd1df4a6d --- /dev/null +++ b/guides/db-setup/readme.md @@ -0,0 +1,37 @@ +# Local database setup โš™๏ธ + +## Initiating local database + +Once you have your schema ready, make sure you create a new database for yourself locally. For example, let's call it `videorec`. From a shell use `createdb` to create a new database for yourself: + +```bash +createdb videorec +``` + +Once it is created you can now try to load your file into the database using `psql`: + +```bash +psql -d videorec < db/initdb.sql +``` + +**Note:** Depending on how postgresql was installed for you, you might need to add some connectivity details to both `createdb` and `psql`: + +```bash +psql -h localhost -U username -d videorec < db/initdb.sql +``` + +In this example, we ask postgres to connect to your local database through `localhost` and use `username` as the user. + +## Re-running the script + +It is advised to make sure that the `initdb.sql` script can be run multiple times, and each run would reset the database to a known initial state. One way to do it is to add some SQL code to the start that would delete tables in case they exist, something like: + +```sql +DROP TABLE IF EXISTS videos CASCADE; +``` + +Try running your `initdb.sql` script multiple times with the `psql` code above to make sure every time you get a fresh and clean database without errors. + +## Sample data + +You will need some example video data in your database. Please check [the example data](./data/example_data.csv), and modify your `initdb.sql`. Add the relevant `INSERT INTO` calls that will add all of this example data every time you run `initdb.sql`. diff --git a/guides/e2e-tests/readme.md b/guides/e2e-tests/readme.md new file mode 100644 index 0000000000..a6f195e5e2 --- /dev/null +++ b/guides/e2e-tests/readme.md @@ -0,0 +1,74 @@ +# End-to-end tests ๐Ÿงช + +While unit and integration tests usually only check part of the stack (like the frontend tests only check the frontend but don't connect to the backend), end-to-end (E2E) tests are specifically designed to check the interaction of the entirety of the stack - frontend, backend and database. + +## Playwright + +The biggest E2E frameworks are Selenium, Cypress and Playwright. Each of them allow you to run a browser instance and automate what happens inside it. For this requirement, we picked Playwright as the framework. + +For example you can write Playwright code that opens up your application, then clicks the "Remove video" button on the page, checking that the video is indeed removed from the website. + +## Setup + +Just with the other tests, we have helped you get started by setting up a test runner for your feature tests, and adding a couple tests to `e2e/tests/features.test.js`. These tests would go through the website and check that you can do all of the required features. + +**Note:** for this to work you need to make sure you have setup the test backend database. If you haven't done so please refer to that section to set up your test database first. + +To run your end-to-end tests there are three steps you need to do: + +1. Install Playwright browsers + +Playwright will use its own browsers instead of the one installed on your computer. To install the browsers type + +```sh +npx playwright install +``` + +You'll only need to do this once. + +2. Stop any running server + +Playwright will start up your backend and frontend automatically, but it will not be able to do that properly if you're already running them + +3. Start the feature tests: + +```sh +npm run test:e2e +``` + +This command will run the test in the background. If you want to check what Playwright does in the browser you can use + +```sh +npm run test:e2e:headed +``` + +This will start up the browsers in the foreground. Both options will then click around very quickly trying to run the features - adding and deleting videos as well as ranking existing videos up and down. + +(Playwright also has a full UI mode where you can play around with your tests. This is accessible via `npm run test:e2e:ui`) + +**Note:** just like with the other pre-created tests this might fail depending on how you have implemented your frontend, backend and database parts. Please check the test code and update it to make sure it runs successfully. Some changes that you need to do will be similar to the level 299 frontend tests - like if you don't have a `"Remove video"` button but have something else you need to change the code to find that button. Similarly, the current test assumes that the HTML structure of your video components look like the one below: + +```html +
+

+ The title of the Video +

+ +
+``` + +Here to get from the title to the video container you need to go two levels up. First from `` to `

`, then from this `

` to `
`. If your website is structured differently you will need to update this in the tests. + +## Enable PR tests + +Tests are useful to run every time you create a PR to make sure you don't accidentally add or change code that breaks existing functionality. You can go to `.github/workflows/run-e2e.yml` and remove the comment from the line that says `pull_request:`. This will run the `npm run test:e2e` call every time you create a new PR blocking merging in case tests fail. + +## Add new test cases + +You might want to add tests to cover some additional scenarios. For example if you have opted into doing the ordering feature you might want to add a test that checks that sorting by ascending and descending really updates the page to sort accordingly. + +## Next Level + +Once finished please check if you have missed any optional features before, and finish them. If you have done all of them, then congratulations, you have finished this exercise 100%! + +Feel free to use this project as part of your portfolio. You might also use it as a base project to start with testing out new ideas, frameworks or deployment services. diff --git a/guides/setup/readme.md b/guides/setup/readme.md new file mode 100644 index 0000000000..6fccf9f875 --- /dev/null +++ b/guides/setup/readme.md @@ -0,0 +1,62 @@ +## Setting up the project ๐Ÿงฐ + +We have set up an initial project for you to help with some of the complexities of the assessment. This project requires Node.JS version 20 or later. Make sure you have at least Node version 20 running: + +```sh +node -v +``` + +The version number should be `v20.6.0` or higher: + +``` +v20.8.0 +``` + +If this is lower, like `v18.18.2`, or `v20.5.5` you will need to install a more recent version of Node.JS. Refer to the [node installation guides](https://nodejs.org/en/download/package-manager) for your operating system. For Ubuntu based systems [NodeSource](https://github.com/nodesource/distributions) is usually a good way to do it. + +Once you have confirmed that your node version is recent enough you can install the requirements. Change directory to the root of your monorepo. Then run the following commands: + +```sh +npm install +``` + +Then to start up your frontend and backend locally, you can run + +```sh +npm run dev +``` + +To confirm your server is running go to + +```url +http://127.0.0.1:3100/health +``` + +in your browser. If the server is running you'll see a message saying + +```json +OK +``` + +## Before you commit your changes + +Read this [article on .gitignore](https://sabe.io/blog/git-ignore-node_modules). We have set up a basic `.gitignore` file for you. + +## Frontend setup + +Since we are using a monorepo, you can launch the frontend the same way you launch the backend. Run the following command in the root of your repo: + +```sh +npm run dev +``` + +The code you put under `client/src` will then be accessible on http://localhost:3000 + +## Monorepo + +The project is set up to run as a monorepo, where both the [`client`](../../client/) and [`server`](../../server/) source code live in the same git repository and are linked together. When using monorepos, there is some boilerplate code required to make sure both the frontend and the backend application can work at the same time and are accessible on the same URL. To kickstart your development we have set up this boilerplate code for you already. Feel free to look at the code, but generally you won't need to edit them if you follow the proposals in this guide. + +If you are interested you can read more about what they do in the following places: + +- [Client vite settings](../client/vite.config.js) +- [Server frontend middleware](../server/app.js) diff --git a/guides/testing/readme.md b/guides/testing/readme.md new file mode 100644 index 0000000000..3d3547d4f8 --- /dev/null +++ b/guides/testing/readme.md @@ -0,0 +1,86 @@ +# Automated tests (Optional) + +The below points are improvement ideas that you can add to your project to become a great project. If you want this project to be part of your portfolio we suggest that you implement at least some of the optional features. You don't need to do all of them during this week, you are free to revisit this list later + +## 1) Backend unit tests + +Automated tests are code that, when run, will check that your code adheres to some pre-set conditions, usually your acceptance criteria. With the help of automated tests you can make sure that even if you add new features to your code, your existing features remain working. Breaking existing features when adding new ones is very common in the engineering world, there is a word for it as well: "regression". + +Unit tests only check a small subset (a unit) of your application at a time. These tests can usually be both written and run quickly so they are a good way of determining that the application is doing what it should be doing. + +You can test your backend in isolation, your frontend in isolation and you can also have tests that check both of them at the same time. For this level, we will start by adding tests for your backend. + +### Setting up backend unit tests โš™๏ธ + +We have helped you get started by setting up a test runner for your backend systems and adding a couple tests to `server/api.test.js`. These tests would check that the list and delete endpoints works as expected. + +First you need to set up the tests. To do that make sure you create a separate database for tests. For example let's call it `videorec_test`: + +```sh +createdb videorec_test +``` + +Afterwards edit your `.env` file and change the `TEST_DATABASE_URL` to point to this database. + +**Note:** we are using a different database to make sure that we don't accidentally modify your normal database every time when you run your tests. + +Once you have set up the database settings you can now run the tests by calling + +```sh +npm run test:server +``` + +Check the response, it will tell you if the tests have succeeded or not. It is possible that you will need to update the test to cater for how you have implemented your backend. + +### Transactional tests + +The test runner above is set up to have transactional tests. What this means is that whenever you start the testing session, the code will reset your (test) database using `initdb.sql`. Afterwards it will run each test in a database transaction, rolling it back at the end of the test. Database transactions are a feature of most relational databases that allows you to run SQL commands in a temporary environment first, and only if you are happy with the results will they be saved to the database. It's a bit like editing a file and not saving it until you are happy with the result. + +We use this feature during test runs. We effectively ask the database to never save our changes at the end of the tests. This allows each test case to start with the exact same, initial database as every other test. For example when testing the video removal features, during the test the video will be removed, but once the tests are run, the database is reset, and subsequent tests will still be able to access the deleted video. + +### Enable PR tests + +Tests are made much more useful if they run every time you create a PR. This way GitHub will make sure to run them and let you know if your latest code is not working anymore based on the tests. To enable backend tests you should to `.github/workflows/run-server-tests.yml` and remove the comment from the line that says `pull_request:`. This will run the `npm run test:server` call every time you create a new PR blocking merging in case tests fail. + +To confirm, the top of the file should look like this: + +```yaml +on: + workflow_dispatch: + pull_request: +``` + +This will allow GitHub to run the defined action on each pull request, and you can also run it ad-hoc from the "Actions" page whenever you wish. + +**Note:** Make sure to have a full read of this file and try to figure out what it does. + +### Adding additional tests + +Based on the existing tests in the system you could try and create one that checks the add video functionality. It should verify that videos are added if the request is formatted properly, but fail if the request is missing the title, or the URL is incorrect. + +## 2) Frontend unit tests + +Similar to the backend unit tests we can create tests that verify that the frontend is working as expected in an automated way. + +### Setting up frontend unit tests โš™๏ธ + +To setup the frontend tests we have helped you get started by adding a couple tests to `client/test/App.test.js`. These would check that the page, after loading, contains enough `