├── .DS_Store ├── API_Management.md ├── BuildingResponsiveComponents.md ├── ClientSideStorage.md ├── Git.md ├── Git2.md ├── LayOutNavBar.md ├── RefiningSQLQueries.md ├── SCSS.md ├── SCSSFeatures.md ├── SCSSInYourProject.md ├── SQL1.md ├── SQL2.md ├── SuperTest.md ├── TDDWithInteractiveComponent.md ├── TDDWithTestingLibrary.md ├── TestingAnAsyncrounousComponent.md ├── TestingFEComponents.md ├── UsingBEM.md └── readme.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/werner33/AdvancedBasicsForWeb/07fca7ae269dbffe98531f7403dd3a707684aa9a/.DS_Store -------------------------------------------------------------------------------- /API_Management.md: -------------------------------------------------------------------------------- 1 | 2 | 1. API Calls Overview 3 | 4 | An API call is a request for some resources passed to us over the web. Modern web conventions have many APIs returning JavaScript Object Notation (JSON) that we can consume in a web application. 5 | 6 | In a typical React app we make an API call from the front end like this: 7 | 8 | ``` javascript 9 | 10 | fetch('https://catfact.ninja/fact') 11 | .then(res => res.json() 12 | .then(data => { 13 | console.log(data) 14 | }); 15 | 16 | ``` 17 | 18 | We might use a library like Axios to save ourselves some work, but [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) is build right into JavaScript. 19 | 20 | API calls have five HTTP Methods: GET, POST, PUT, PATCH and DELETE. We won't get into each of them now, but in very basic terms, we use GET to fetch information and we use POST to save information. The other three types are less common. 21 | 22 | A great breakdown of how an API is accessed via an HTTP request can be found [here.](https://blog.uptrends.com/technology/the-anatomy-of-an-api-call/) 23 | 24 | 25 | 2. Setting Request Headers 26 | 27 | We may want to make a call with special information or parameters. We can set a number of properties by specifying the Request Headers. Request headers are key/value pairs, passed as a second argument in a `fetch` request. 28 | 29 | ``` javascript 30 | 31 | fetch('https://catfact.ninja/fact', {method: 'POST'}) // we can add many other request headers here 32 | .then(res => res.json() 33 | .then(data => { 34 | console.log(data) 35 | }); 36 | 37 | ``` 38 | 39 | [In this article](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#supplying_request_options) you can see a more fulsome example of how you supply request options. 40 | 41 | 42 | 3. Where Should Calls Be Made in an Application? 43 | 44 | In a React application, components are structured in a heirarchy. An API calls should typically be made at the highest level where the data is needed. 45 | 46 | Here is a small example: 47 | 48 | Imagine we are writing an app that will show the names of all students in the school and also, a schedule of after-school activities. 49 | 50 | There are three main components structured like this: 51 | 52 | App\ 53 | |----- StudentCollection\ 54 | |----- Schedule 55 | 56 | The respective API calls should be made from the component showing the data. 57 | 58 | App\ 59 | |----- StudentCollection\ 60 | - fetch student data here\ 61 | |----- Schedule\ 62 | - fetch schedule of events here 63 | 64 | 4. Code Splitting in React 65 | 66 | When we send our React project to a client or browser, the whole application is sent by default. The components are not all rendered but the code is all included in the `bundle.js`. This is fine for a small application, but as our application grows, we should see if we can avoid sending code that a user may not use. One strategy we can employ is [Code Splitting](https://reactjs.org/docs/code-splitting.html). 67 | 68 | Let's look at an example where we 'split' one of our routes into its own bundle. 69 | 70 | 71 | ``` javascript 72 | const About = React.lazy(() => import('../about/About')); 73 | 74 | ... 75 | 76 | 77 | Loading...}> 78 | 79 | 80 | ``` 81 | 82 | 5. Caching in Session Storage 83 | 84 | Imagine we are working on an app that suggests 10 random coffee types to a user each time they load our app. The randomness is seen as desirable as it keeps users coming back to learn about different coffees. However, once they load the randome coffees, in their browser, we don't want the coffee selection to change until they close that tab. For this, we might use a type of short term storage available through the browser called Session storage. 85 | 86 | Session storage will store a key value pair where both the key and value are strings. This will be a bit tricky since we will be getting our coffee information back as JSON. 87 | 88 | First, let's look at the basic fetch request to get five random coffees. 89 | 90 | ``` javascript 91 | 92 | let url = 'https://random-data-api.com/api/coffee/random_coffee?size=5'; 93 | 94 | useEffect( () => { 95 | fetch(url) 96 | .then(res => res.json()) 97 | .then((result) => { 98 | setCoffees([result]); 99 | }, 100 | 101 | (error) => { 102 | console.log(error); 103 | } 104 | ); 105 | }, [] ) 106 | ``` 107 | 108 | This code should be familiar. If we include this in a React component it will grab 5 random coffees each time the component is mounted. 109 | 110 | What can we do to prevent getting 5 new random coffees on a refresh? We can save the data to session storage and load it from there. 111 | 112 | Let's modify the code above to utilise session storage: 113 | 114 | 115 | ``` javascript 116 | 117 | let url = 'https://random-data-api.com/api/coffee/random_coffee?size=5'; 118 | 119 | useEffect( () => { 120 | 121 | if(sessionStorage.coffees ){ 122 | setCoffees([...JSON.parse(sessionStorage.coffees)]) 123 | } else { 124 | fetch(url) 125 | .then(res => res.json()) 126 | .then((result) => { 127 | setCoffees([result]); 128 | sessionStorage.setItem('coffees', JSON.stringify(result)) 129 | 130 | }, 131 | (error) => { 132 | console.log(error); 133 | } 134 | ); 135 | }, [] ) 136 | ``` 137 | 138 | Right after we set our hook, we save the data to session storage. With this data saved 139 | -------------------------------------------------------------------------------- /BuildingResponsiveComponents.md: -------------------------------------------------------------------------------- 1 | # Building Responsive Components 2 | 3 | When building a React project, we will compose our page by utilizing many components. Since so many people access the internet on their cell phones, we want our site to be readable and usable on both desktop computers and cell phones. When a component is presentable and useable on desktop and mobile, we call this responsive. 4 | 5 | We can make our component responsive by applying different styles through our SCSS files. In order to decide what styles to attach, we will use media queries. 6 | 7 | # Media Queries 8 | 9 | Media queries are conditional statements in our SCSS or CSS files that look at the size of the screen of a given user, and then conditionally attaches styles. Generally, we will query the pixel width of a screen to decide what styles to apply. 10 | 11 | Let's look at a basic media query. 12 | 13 | ``` CSS 14 | @media only screen and (max-width: 440px) { 15 | p { 16 | color: blue; 17 | } 18 | } 19 | ``` 20 | 21 | This query is saying on any device, with a width of 440px or less, the text color of a `

` element would be blue. On any screen wider than 440px, the color would be the default black. 22 | 23 | You can read more about media queries [here](https://www.w3schools.com/css/css_rwd_mediaqueries.asp). 24 | 25 | # Building a Responsive Nav Bar 26 | 27 | In this lesson, we will create a new React app and build a responsive nav bar with a logo and a list of nav links. 28 | 29 | To begin: 30 | 31 | 1. Open a terminal and start a new React project: `npx create-react-app responsive-navbar`. 32 | 33 | 2. Move into the directory you just created: `cd responsive-navbar` 34 | 35 | 3. Install SCSS: `npm install sass` 36 | 37 | 4. Run the project: `npm start` 38 | 39 | 5. After you have verified that the project is running properly, remove all the code in the `

` element of `app.js` and everything inside `app.css` 40 | 41 | With that, we are ready to start building our navbar! Let's move to the [next section](). 42 | -------------------------------------------------------------------------------- /ClientSideStorage.md: -------------------------------------------------------------------------------- 1 | # Client Side Storage 2 | 3 | In order to give users the best experience possible, we may want to store some data in the browser. This could be something relatively simple such as a set of user preferences or some JSON data, stored as a string. In this course, we looked at one example of this through using session storage to cut down on unneccessary API calls. 4 | 5 | Each of the four ways to store data in the browser has its pros and cons. Through this lesson, we'll look at the best way to work with each of them. 6 | 7 | Let's begin with creating a new React project: `npx create-react-app client-side-storage`. 8 | 9 | 10 | # Cookies 11 | 12 | Cookies are the smallest most restrictive pieces of data we save to the client. All of our cookie are passed along with any API calls we make to the server. With this in mind, we should only save things as a cookie if we absolutely need them to make successful API calls. 13 | 14 | While there are many great libraries to help us set and get cookies, let's write our own functions now. 15 | 16 | Create a directory called `utils` and inside of it, let's make a file called `cookies.js`. 17 | 18 | First, let's write two functions called `setCookie` and `getCookie` and then export both. Your file should look like this: 19 | 20 | ``` javascript 21 | 22 | const setCookie = () => { 23 | 24 | } 25 | 26 | const getCookie = () => { 27 | 28 | } 29 | 30 | module.exports = {setCookie, getCookie}; 31 | 32 | ``` 33 | 34 | When we create a cookie, it is composed of three parts: a key, a value and an expiration. Keys and values are likely familiar to you from working with Objects or JSON. One thing to note is that a cookie can only store a string as its value. Remember that for many datatypes, you can cast them to a string by called `toString` on them. 35 | -------------------------------------------------------------------------------- /Git.md: -------------------------------------------------------------------------------- 1 | # intermediate_git 2 | 3 | Git is one of the most fundamental tools for managing collaboration when writing software. Although you surely have worked with Git since early on in your education at Pursuit. Git is a powerful and varied tool. There is always more to learn to manage workflow, increase harmony in collaboration and make sure that we don't lose important code. 4 | 5 | At a simple level, Git is a file that lives inside a software project that stores 'save points' as we go. We can jump to any save point at any time. Save points are generally called 'commits'. We'll start out by looking at a project and perusing the previous commits. 6 | 7 | # git log 8 | 9 | Please fork and checkout [this repo](https://github.com/werner33/Sonnet). 10 | 11 | One thing to note, is that we can just as well use Git to collaborate on an essay as on a website. This repo is a poem from William Shakespeare. Let's take a look at the commits that have been made until this point. We can do this by typing `git log` on the command line. 12 | 13 | Git log will reveal a scrollable list of all previous commits, including their time, date and author. When you are done looking at the commits, feel free to press `q` to exit the log. 14 | 15 | The log keeps track of all committed changes, noting by whom and when they were committed. 16 | 17 | # git reflog 18 | 19 | As we work on an assignment, we may find ourselves sometimes thinking 'Where am I? How did I get here?' Or we realize we made a change that we really don't want to add to the codebase. For this we don't care so much about `git log` but rather `git reflog`. The reflog is a record of where we *personally* have been in a particular project. 20 | 21 | We haven't done much yet, but let's go head and check out the reflog. In the terminal type `git reflog`. 22 | 23 | We don't have much to see here yet, but we'll see that this reflog grows as we work through the class. 24 | 25 | # Resolving a Git Conflict 26 | 27 | This next section may be a review, but it's important so I wanted to review it. 28 | 29 | Generally when we take on assignment, we are working on a git `branch`. This allows us to do our own work without running into other changes that coworkers may be making. Often, your project managment software will automatically create branches, but if you need to create one from scratch, you can type `git branch `. Let's do that now. 30 | 31 | `git branch first-branch` 32 | 33 | We've created the branch but now we need to move to that branch: 34 | 35 | `git checkout first-branch` 36 | 37 | On the first line of the poem, go ahead and add a new line with whatever text you would like. Add this code and create a commit. 38 | 39 | Now, while you are working on your branch, your coworkers are working on their own branches. Let's simulate that. First, let's go back to the master. `git checkout master`. Now, let's browse existing branches by typing `git branch`. We see that the astirik tells us that we are currently on `*master`. 40 | 41 | Let's create a second branch: `git branch second-branch`. Note: we can create and checkout a branch at the same time by typing `git checkout -b second-branch'. Otherwise just move to that branch with `git checkout second-branch`. 42 | 43 | Since we never merged our `first-branch`, you'll see that the line that you added is not reflected on master or this new `second-branch`. Let's add a different first line on this `second-branch`. Type whatever you want. 44 | 45 | Now, let's move back to master and we'll decide we're totally happy with the text we added. Let's merge it into master. 46 | 47 | Type: `git merge second-branch` 48 | 49 | This should merge with no issues. However, we still have our `first-branch` hanging out with a different change in the same place. Before we merge `first-branch` lets delete `second-branch` since we're done with it now. To delete a branch type: `git branch -d second-branch`. Let's type `git branch` to confirm that we still have `master` and `first-branch` but `second-branch` is gone. 50 | 51 | Finally, we want to merge the work from `first-branch`. Go ahead and type: `git merge first-branch`. 52 | 53 | You will see something like this: 54 | ``` 55 | Auto-merging test.js 56 | CONFLICT (content): Merge conflict in test.js 57 | Automatic merge failed; fix conflicts and then commit the result. 58 | ``` 59 | 60 | Let's open this in VSCode and resolve the commit. Once we've chosen the change we want, we can type `get merge --continue` and complete the merge. 61 | 62 | 63 | # Revisiting Reflog 64 | 65 | Now, that we've moved around quite a bit, let's look back at the reflog. We see we have many markers that we can revisit if we want to. Where as log only really tracks commits, reflog tracks commits as well as any time we merge, rebase, change branches and more. 66 | -------------------------------------------------------------------------------- /Git2.md: -------------------------------------------------------------------------------- 1 | # Amend a Commit 2 | 3 | Do you ever finish a ticket and think, "Finally, Done! Let me commit and push this real quick." And then, a few minutes go by and you think of one more small thing you need to add. Or that debugger you forgot to take out... 4 | 5 | Amending a commit is a great way to make a small update to the code you just pushed - without creating a new commit. 6 | 7 | First, make any additional changes to your code. 8 | 9 | Then, type `git add .`, followed by `git commit --amend --no-edit`. When you include `--no-edit`, the commit message will not change. If you exclude that flag, you will get the chance to revise your commit message. This can be useful if your ammendment meaningfully changes the nature of your commit. 10 | 11 | 12 | # Squash Unnecessary Commits 13 | 14 | Sometimes you might be working on a particular task and you make several commits. However, when you look back at many commits, you feel that some of them are not useful and don't point to a place where you would ever want to go back to. As an example: 15 | 16 | first commit - "added a user profile page" 17 | second commit - "laid out user image and summary" 18 | third commit - "removed console.log" 19 | fourth commit - "added a contact me section" 20 | 21 | One of these is not like the other... Let's see how we could use git to get rid of the third commit and 'squash' it into the fourth commit. 22 | 23 | Let's start with `git rebase i HEAD~4`. This will open an interactive rebase view in VIM. We can re-write the keyword beside the commit we don't want and change it to `squash`. This will squash it into the fourth commit. We could also potentially drop it - though that is a bit more risky since we are letting go of the code completely. 24 | 25 | # Interactive Rebase to Remove Old Code 26 | 27 | We're going to end our journey through Git with an interactive rebase. Sometimes, you may look back and see that several commits ago, you included something in your code that has since been removed, but it't not enough to remove it from the active code. Rather, you need to remove it from the whole commit history. For this, we also use interactive rebase, but now, we want to use the `edit` keyword. Once we save this interactive rebase, it will essentially create a script that plays back each of our commits, allowing us to edit any of them we labeled with the `edit` key word. 28 | 29 | # More Resources 30 | 31 | [Git for Four Year Olds](https://www.youtube.com/watch?v=1ffBJ4sVUb4&ab_channel=HackersOnBoard) 32 | -------------------------------------------------------------------------------- /LayOutNavBar.md: -------------------------------------------------------------------------------- 1 | # Layout of Nav Bar 2 | 3 | Before we 4 | -------------------------------------------------------------------------------- /RefiningSQLQueries.md: -------------------------------------------------------------------------------- 1 | ### Getting Specific with Selectors 2 | 3 | SQL is a powerful language with all kinds of syntax to help us tailor our queries. Let's look at a couple you may not be familiar with: 4 | 5 | [LIKE](https://www.w3schools.com/sql/sql_like.asp) - LIKE is used to match text patterns in a particular column. It is somewhat similar to a regular expression in Javascript and other programing languages. Keep in mind that the text you are looking to match is case-insensitive. 6 | 7 | Challenge: Write a query that returns any customers where the contactName has an a in the second and fifth position. 8 | 9 | [BETWEEN](https://www.w3schools.com/sql/sql_between.asp) - BETWEEN is used to search for a value, usually a number, that lies in a bounded range. The query would look something like this : 10 | 11 | `SELECT * FROM users WHERE accountTotal BETWEEN 1000 AND 9999;` 12 | 13 | Challenge: On the order details table, write a query that returns all orders where the quantity is between 17 and 20. 14 | 15 | ### Grouping 16 | 17 | When we want to see certain records collapsed into a single row, for example, when we would like to see the number of users in a certain country, we can use `GROUP BY`, passing a column. All records that have that column in common will be grouped together. 18 | 19 | [GROUP BY](https://www.w3schools.com/sql/sql_groupby.asp) 20 | 21 | Challenge: On the W3 orderDetail table, write a query that gets the number of products in each order. 22 | 23 | ### Challenges 24 | -------------------------------------------------------------------------------- /SCSS.md: -------------------------------------------------------------------------------- 1 | # SCSS And BEM 2 | 3 | As a web project grows, it can be quite difficult to manage ever growing CSS files and nested HTML elements. In this lesson, we're going to learn some approaches and tools that can help us manage this complexity. 4 | 5 | # Prerequisites 6 | 7 | Before beginning this lesson, you should be familiar with
8 | [HTML](https://github.com/joinpursuit/Pursuit-Core-Web/tree/master/html_css_dom/html_introduction_combined)
9 | [CSS](https://github.com/joinpursuit/Pursuit-Core-Web/tree/master/html_css_dom/css_intro)
10 | [Building a React Application](https://github.com/joinpursuit/Pursuit-Core-Web/blob/master/react/README.md) 11 | 12 | You can review any of those things at their respective links. 13 | 14 | # SCSS 15 | 16 | SCSS (called Sass, as in, don't give me that sass!) is a CSS engine that allows us to nest our css, similar to how we nest HTML elements. Before we implement it in a React project, let's give it try by starting out on [Codepen](https://codepen.io/). 17 | 18 | First, in the CSS box, select the gear icon: 19 | 20 | Screen Shot 2023-10-02 at 2 52 37 PM 21 | 22 | This will open a settings panel. You can see this is in the following image: 23 | 24 | Screen Shot 2023-10-02 at 2 52 48 PM 25 | 26 | Click the dropdown and select SCSS from the list of pre-processors. 27 | 28 | 29 | Let's build a simple component with a title and a bit of text: 30 | 31 | Screen Shot 2022-01-13 at 2 30 45 PM 32 | 33 | First, let's write out all the HTML. We'll use the component we built in the first part of this lession: 34 | 35 | ``` HTML 36 | 37 |
38 |
Info Card
39 |
40 | This is an info card with some content. 41 |
42 |
43 | 44 | ``` 45 | 46 | Next we move to the styling with CSS. Without SCSS, we would need to write our styles like this: 47 | 48 | ``` CSS 49 | 50 | .info-card { 51 | text-align: center; 52 | border: 1px solid black; 53 | width: 250px; 54 | margin: 0 auto; 55 | padding: 20px; 56 | } 57 | 58 | .info-card .info-card__title { 59 | font-weight: 600; 60 | padding: 10px; 61 | } 62 | ``` 63 | 64 | However, as long as we have selected the SCSS from the dropdown (as shown above), we can start to use one of the features of SCSS - nested styling. 65 | 66 | ``` CSS 67 | .info-card { 68 | text-align: center; 69 | border: 1px solid black; 70 | width: 250px; 71 | margin: 0 auto; 72 | padding: 20px; 73 | 74 | &__title { 75 | font-weight: 600; 76 | padding: 10px; 77 | } 78 | } 79 | ``` 80 | 81 | We have only scratched the surface of what is possible through SCSS, but hopefully this demonstrates that it is just CSS with a few extra capabilities. 82 | 83 | NOTE: You can always run vanilla CSS in a file ending with `.scss`. In other words, you can change the file extension without having to re-write the whole file. 84 | 85 | Before we move into working on a React project, [let's improve our Info Card by using BEM notation](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/UsingBEM.md). 86 | 87 | -------------------------------------------------------------------------------- /SCSSFeatures.md: -------------------------------------------------------------------------------- 1 | # What More Can SCSS Do? 2 | 3 | The reality is that SCSS doesn't take long to learn and significatly improves your front-end work flow. We're going to spend the rest of class looking at a few more SCSS features. 4 | 5 | # Variables 6 | 7 | Let's imagine we want to set a background color for our `InfoCard`. Lets set a background color of `#99d6ff`. It's basically a light blue. 8 | 9 | Let's update our `InfoCard.scss` file: 10 | 11 | ``` css 12 | .info-card { 13 | text-align: center; 14 | border: 1px solid black; 15 | width: 250px; 16 | margin: 0 auto; 17 | padding: 20px; 18 | background-color: #99d6ff; 19 | 20 | &__title { 21 | font-weight: 600; 22 | padding: 10px; 23 | } 24 | } 25 | 26 | ``` 27 | 28 | We often use the same colors in many places in an application. At the same time, it can be difficult to remember the hex number that represents a particular color. Just like with any other code, we may have values that are easier to access and remember when they are set to variables. Let's use SASS to set a variable for this color. 29 | 30 | A variable name in SASS always starts with a `$` followed by a string. Let's call this color `$sky-blue`. 31 | 32 | `$sky-blue: #99d6ff;` 33 | 34 | In order to use this variable, lets set it at the top of our `InfoCard.scss` file and then use it like this: 35 | 36 | ``` css 37 | $sky-blue: #99d6ff; 38 | 39 | .info-card { 40 | text-align: center; 41 | border: 1px solid black; 42 | width: 250px; 43 | margin: 0 auto; 44 | padding: 20px; 45 | background-color: $sky-blue; 46 | 47 | &__title { 48 | font-weight: 600; 49 | padding: 10px; 50 | } 51 | } 52 | 53 | ``` 54 | 55 | We can now use this variable any number of times in this file. 56 | 57 | # Partials 58 | 59 | CSS files can get very large as your project grows. Just like JavaScript files, you may want to share parts of CSS between more than one file. If you have a piece of styling, that you want to use in more than one file, you can set up a shared CSS file, known as a Partial, by naming it with a `_` to start. 60 | 61 | Let's make an example based on what we just learned with variables. 62 | 63 | First, we'll create a file called `_colors.scss`. Note that because it will be imported into another SASS file, the file name starts with `_`. 64 | 65 | Let's move our variable `$sky-blue` into this `_colors.scss` file. 66 | 67 | ``` css 68 | $sky-blue: #99d6ff; 69 | 70 | ``` 71 | 72 | For now, that is all we will put here, but we can build out a palatte of colors as our project grows. 73 | 74 | 75 | Next, we will remove the `$sky-blue` variable from `InfoCard.scss` and import our `_colors.scss` file: 76 | 77 | ``` css 78 | @import './colors.scss' 79 | 80 | .info-card { 81 | text-align: center; 82 | border: 1px solid black; 83 | width: 250px; 84 | margin: 0 auto; 85 | padding: 20px; 86 | background-color: $sky-blue; 87 | 88 | &__title { 89 | font-weight: 600; 90 | padding: 10px; 91 | } 92 | } 93 | 94 | ``` 95 | 96 | (Depending on how your project is layed out, you may need to alter the import path.) 97 | 98 | Although the partial is written with an underscore at the beginning of the name, the underscore is omitted when the file is imported. 99 | 100 | We are now set up to include and use this and any other variables we create throughout the application. 101 | 102 | # Continuing with SCSS 103 | 104 | SCSS offers some additional wonderful features. You can learn more about them at [SASS Basics](https://sass-lang.com/guide) 105 | -------------------------------------------------------------------------------- /SCSSInYourProject.md: -------------------------------------------------------------------------------- 1 | # How to Include SCSS in your Project 2 | 3 | You can add SCSS into an existing react project or create a new project. If you are working in an existing project, feel free to skip the next section. 4 | 5 | # Creating a new React App 6 | 7 | If you don't have an app that you are currently working on, you can create a new project by opening your terminal and using `create-react-app`. 8 | 9 | `$ npx create-react-app scss_exercise` 10 | 11 | `$ cd scss_exercise` 12 | 13 | Then you can start your server with `$ npm start`. 14 | 15 | # Installing SCSS 16 | 17 | We can install SCSS for React through NPM just like many other packages. Go to [Install SCSS](https://www.npmjs.com/package/sass) to learn more about this library. When you're ready, go ahead and run `npm install sass` in your project. 18 | 19 | Once the instlation is completed, go ahead and rename one of the files ending with `.css` file to `.scss`. Once you have made this change, make sure you also change the import statement for the css file. 20 | 21 | Once you've made these changes, check to see that your application is still running correctly. If there are any errors, take time to resolve those now. 22 | 23 | 24 | # Nesting our SCSS 25 | 26 | If you are working in an existing project, pick a small section of CSS that you can nest inside another, as we did when using jsfiddle. If you would rather build a new component, let's build an InfoCard based off the card we built earlier in this lesson. 27 | 28 | Make a file called `InfoCard.js` with the following content: 29 | 30 | ``` javascript 31 | 32 | import React from 'react'; 33 | 34 | import './InfoCard.scss' 35 | 36 | const InfoCard = () => { 37 | 38 | return ( 39 |
40 |
Info Card
41 |
42 | This is an info card with some content. 43 |
44 |
45 | ) 46 | 47 | } 48 | 49 | ``` 50 | 51 | Then create a `.scss` file that you import into the previous component: 52 | 53 | 54 | ``` css 55 | 56 | .info-card { 57 | text-align: center; 58 | border: 1px solid black; 59 | width: 250px; 60 | margin: 0 auto; 61 | padding: 20px; 62 | 63 | &__title { 64 | font-weight: 600; 65 | padding: 10px; 66 | } 67 | } 68 | 69 | ``` 70 | 71 | Finally, import and render the InfoCard into your `App.js` file that was generated when you created your app. 72 | 73 | ``` js 74 | 75 | import React from 'react' 76 | 77 | import InfoCard from './InfoCard'; 78 | 79 | function App() { 80 | 81 | return ( 82 |
83 | 84 |
85 | ); 86 | } 87 | 88 | export default App; 89 | 90 | ``` 91 | 92 | # Run the App 93 | 94 | You should now have the `InfoCard` running in your browser with the `InfoCard.scss` file imported and the styles applied correctly to your component. 95 | 96 | Now that we have our app running with SCSS. Let's finish by [looking at a couple more things SCSS can do](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/SCSSFeatures.md). 97 | -------------------------------------------------------------------------------- /SQL1.md: -------------------------------------------------------------------------------- 1 | # SQL Lesson 2 | 3 | ### SQL Course Overview 4 | 5 | SQL and other query languages are used to interact with databases. As long as you work with software, you can be sure that a database - and probably more than one - is not far away. Some of you likely work with SQL on a daily basis where others might only write queries occasionally. In this class, we will review some of the basic aspects of SQL, but since you have already learned SQL basics, we will move on to some of the more advanced concepts quickly. 6 | 7 | If you would like to review basic SQL, you can always return to the Core curriculum in [Module 4](https://github.com/joinpursuit/Pursuit-Core-Web/blob/master/full_stack_express/README.md). 8 | 9 | Throughout this two part class, we will lean heavily on [W3's Sql lessons and live database](https://www.w3schools.com/sql/default.asp). NOTE: You'll want to access W3 through Chrome. Some issues have been reported with Safari. 10 | 11 | ### SQL as it Relates to the Web 12 | 13 | Given that we come at SQL as application developers, it is helpful to review how SQL relates to an overall application. First, SQL is a full language that we use when communicating with the database. However much, you use SQL, it's instructive to remember that there are whole career paths such as Data Science and Database Administration where SQL is a core skill. It is a large and robust language. 14 | 15 | As a web developer, we may write SQL queries, but we also have the option of including one or more pieces of software to abstract the SQL and keep us working in a more familiar language. Software that allows us to access our data in a language other than SQL are called Object Relational Mapping (ORM) programs. These exist in every web stack. With Node for example, we might use Sequelize or with Ruby, we could use Active Record. 16 | 17 | For a developer that would like to have more control over how a SQL query is composed, they might choose to use software generally called a query manager or composer. An example of this with Node would be pg-promise. With this, we are still using javascrip but when it comes to writing the actual query, it is esentially SQL with a bit of string interpolation. We need to understand SQL better to work effectively with this tool, but it gives a developer more control over how a query is structured. 18 | 19 | There is no right or wrong here, only tradeoffs in how a web application is interacting with a database. One of the main tradeoffs is whether an ORM should be engaged to make the interations with data to be as easy as possible for the developer or whether a deeper knowledge of SQL is expected with the hope that is results in a lighter application with more efficient queries. 20 | 21 | ### Basic Review of SQL 22 | 23 | Let's quickly review one of the bedrocks of any web application CRUD: CREATE, READ, UPDATE and DELETE. Almost everything we do in a web application is one of thesefour types of actions. Now, just as a quick reminder, let's see how CRUD maps to the HTTP methods and the SQL commands: 24 | 25 | | CRUD | HTTP | SQL | 26 | |------- |-------|--------------| 27 | | CREATE | POST | INSERT INTO | 28 | | READ | GET | SELECT | 29 | | UPDATE | PUT | UPDATE | 30 | | DELETE | DELETE| DELETE FROM | 31 | 32 | And to review SQL syntax quickly, our query is usually composed by starting with one of these key words. For example: 33 | 34 | `SELECT name, age, height FROM users` or 'INSERT INTO users SET score=100 WHERE age > 14' 35 | 36 | We won't spend too much time reviewing these more simple queries, but you can practice with each of them here: 37 | 38 | [SELECT](https://www.w3schools.com/sql/sql_select.asp) 39 | [UPDATE](https://www.w3schools.com/sql/sql_update.asp) 40 | [INSERT INTO](https://www.w3schools.com/sql/sql_insert.asp) 41 | [DELETE](https://www.w3schools.com/sql/sql_delete.asp) 42 | 43 | ### Articles on SQL, Query Management and ORMS 44 | 45 | [Why You Should Avoid ORMs](https://blog.logrocket.com/why-you-should-avoid-orms-with-examples-in-node-js-e0baab73fa5/). 46 | 47 | [ORMS are Awesome](https://chanind.github.io/2020/01/13/awesome-orms.html) 48 | 49 | ### Fun SQL Resources 50 | 51 | [W3 SQL](https://www.w3schools.com/sql/default.asp) - This is a real treasure as a reference. 52 | 53 | [LeetCode](https://leetcode.com/problemset/database/) 54 | 55 | [SQL Murder Mystery](https://mystery.knightlab.com/) - a great free game with lots of practice in more complex SQL queries. 56 | 57 | [SQL ZOO](https://sqlzoo.net/wiki/SQL_Tutorial) - lots of practice starting with very easy SQL to much more advanced. 58 | 59 | [SQL Police Department](https://sqlpd.com/) - This game only has a few levels for free and can feel a bit elementary, but fun none-the-less. 60 | 61 | 62 | -------------------------------------------------------------------------------- /SQL2.md: -------------------------------------------------------------------------------- 1 | ### Joins 2 | 3 | When we are composing a database, data will inevitably be spread across multiple tables. These tables will be related to each other through shared data. For example, we may have a User Table: 4 | 5 | | UserId | Name | Commits | 6 | |------- |-------|--------------| 7 | | 01 | Jenny | 1 | 8 | | 02 | Jose | 2 | 9 | | 03 | Magnolia | 0 | 10 | | 04 | Rosa| 1 | 11 | 12 | And a Commits table: 13 | 14 | | CommitId | UserId | CommitMessage | 15 | |------- |-------|--------------| 16 | | 01 | 01 | Added analytics for the product detail page | 17 | | 02 | 02 | Fixed Bug in adding digital products to cart | 18 | | 03 | 02 | Implemented new design for home page | 19 | | 04 | 04| Handled Bug in User Profile | 20 | 21 | So here we have two tables that have a clear relationship one to the other: Users have 0 or more commits. We can see the number of commits that a User has made without accessing the Commits table, but if we want to see the messages we need to `JOIN` the two tables. We can do that like this: 22 | 23 | ``` SQL 24 | 25 | SELECT Users.Name, Commit.id, Commit.CommitMessage 26 | FROM Users 27 | JOIN Commits 28 | ON Users.UserId = Commits.UserId 29 | ``` 30 | 31 | And our output will look like this: 32 | 33 | | Name | CommitId | CommitMessage | 34 | |------- |-------|--------------| 35 | | Jenny | 01 | Added analytics for the product detail page | 36 | | Jose | 02 | Fixed Bug in adding digital products to cart | 37 | | Jose | 03 | Implemented new design for home page | 38 | | Rosa | 04| Handled Bug in User Profile | 39 | 40 | We've used `JOIN` to connect this data in a helpful way. As with any other query, we can further refine this by sorting or filtering the data. 41 | 42 | ## Types of Joins 43 | 44 | When joining two tables, we might want to pull from records that only have data present on the two tables, or some other selection. You can think of this like Venn diagram where we may want to pull only from records that join with another, ie. all Users who Have one or more Commits. This is called an `INNER JOIN` since it looks at the part of the Venn diagram where the circles overlap. 45 | 46 | Let's imagine we want to find all Users with theit related Commit messages, but we still want to include Users, like Magnolia in the table above, who have made no commits. We can use a `LEFT JOIN`. ie give me all users and include their Commit information if there is any: 47 | 48 | ``` SQL 49 | SELECT User.Name, Commit.CommitMessage 50 | FROM Users 51 | LEFT JOIN Commits 52 | ON User.id = Commit.UserId; 53 | 54 | ``` 55 | 56 | | Name | CommitId | CommitMessage | 57 | |------- |-------|--------------| 58 | | Jenny | 01 | Added analytics for the product detail page | 59 | | Jose | 02 | Fixed Bug in adding digital products to cart | 60 | | Jose | 03 | Implemented new design for home page | 61 | | Magnolia | null | null | 62 | | Rosa | 04| Handled Bug in User Profile | 63 | 64 | Magnolia has been included because she is part of the 'Left' part of our join, the Users, even though there is nothing on the 'right' that corresponds to her UserId. 65 | 66 | Here is a handy chart to visualize different types of Joins: 67 | 68 | ![SQL_Joins](https://user-images.githubusercontent.com/692461/143931929-a3524469-c0ff-4b51-901a-a98f66c74858.jpeg) 69 | 70 | W3's dataset has lots of related tables that you can join to get different data. Try some of the exersizes below: 71 | 72 | ### JOIN Exercises 73 | 74 | 1) Create a query to join Customers with their respective Orders and create a table with: OrderDate, CustomerName and OrderId. 75 | 76 | The beginning of the result will look like this: 77 | 78 | Screen Shot 2021-11-29 at 3 51 10 PM 79 | 80 | 2) Create a query to join Order with OrderDetail, getting the sum of the quantity of total items in the order. 81 | 82 | The beginning of the result will look like this: 83 | 84 | Screen Shot 2021-11-29 at 3 54 29 PM 85 | 86 | ## Questions about Joins 87 | 88 | 1) Given a database with Customers and Orders, where each order has a CustomerId, What kind of join would you use to find all Customers who have never placed an order? 89 | 90 | 2) What is the difference between a Left Join and a Right Join? 91 | 92 | 93 | ### More Exercises for W3 94 | 95 | 1. The boss has offered a prize to whichever employee packed more items in the month of August of 1996. Please write a query that shows all employees by their first and last names and how many total items (not unique items, but overall quantity) that they packed in August from most to least packed. 96 | 97 | ![Screen Shot 2021-11-22 at 4 43 40 PM](https://user-images.githubusercontent.com/692461/142939566-383e5bf9-32a6-412a-b54e-9693907f3db1.png) 98 | 99 | 100 | ### Articles on SQL, Query Management and ORMS 101 | 102 | [Why You Should Avoid ORMs](https://blog.logrocket.com/why-you-should-avoid-orms-with-examples-in-node-js-e0baab73fa5/). 103 | 104 | [ORMS are Awesome](https://chanind.github.io/2020/01/13/awesome-orms.html) 105 | 106 | ### Fun SQL Resources 107 | 108 | [W3 SQL](https://www.w3schools.com/sql/default.asp) - This is a real treasure as a reference. 109 | 110 | [LeetCode](https://leetcode.com/problemset/database/) 111 | 112 | [SQL Murder Mystery](https://mystery.knightlab.com/) - a great free game with lots of practice in more complex SQL queries. 113 | 114 | [SQL ZOO](https://sqlzoo.net/wiki/SQL_Tutorial) - lots of practice starting with very easy SQL to much more advanced. 115 | 116 | [SQL Police Department](https://sqlpd.com/) - This game only has a few levels for free and can feel a bit elementary, but fun none-the-less. 117 | -------------------------------------------------------------------------------- /SuperTest.md: -------------------------------------------------------------------------------- 1 | Generate express app 2 | 3 | Install jest as global dev dependency 4 | 5 | Set up utils directory with one simple function 6 | 7 | Set up test directory with one test 8 | 9 | run test 10 | 11 | make pass 12 | 13 | write tests/make pass 14 | 15 | Move onto harder problem, follow same pattern 16 | 17 | Create a route taking in query params and printing out some data 18 | 19 | incorporate util function 20 | 21 | add supertest 22 | 23 | write a test for the route 24 | 25 | make pass 26 | 27 | do this for several variations 28 | 29 | done. 30 | -------------------------------------------------------------------------------- /TDDWithInteractiveComponent.md: -------------------------------------------------------------------------------- 1 | # Testing an Interactive Component 2 | 3 | So far we've looked at the basic react app out of the box, then we moved on to testing a custom component. In this section, let's move into testing a component that has some interactivity. In the last section we'll include interactivity. 4 | 5 | 1. Create a New Component for a Counter 6 | 7 | You already know the drill: in the same project create a new directory called `/counter`. Like last time, let's start with the nested folder called `__test__`. And of course next well create our test file called `Counter.test.js`. 8 | 9 | As with last time, we'll start by just writing a test to make sure our component renders properly, however, this time we will integrate one more Jest function, `describe`: 10 | 11 | ``` javascript 12 | import { render } from '@testing-library/react'; 13 | import Counter from '../Counter'; 14 | 15 | describe('the counter has a button to increment the count by one each time its clicked', () => { 16 | 17 | test('renders Counter', () => { 18 | render(); 19 | }); 20 | 21 | }) 22 | 23 | ``` 24 | Not much has changed here - we've simply wrapped our test function inside a describe function. This can be useful for grouping certain tests together and prefacing them with a general message describing our component. 25 | 26 | Follow the same steps as last time to get this test to pass. 27 | 28 | 2. Write Tests for the Static Elements 29 | 30 | We want our component to have two parts: a presentation for the current count, with a testid of 'counter__display', starting at 0 and a button with some text that says 'click me'. On every click, the counter should increment by one. 31 | 32 | So first, use your knowledge from the previous lesson to write tests making sure the component has a '0' when it loads and a button with the text 'click me'. 33 | 34 | You know what to do. If you feel stuck, check the [previous lesson for clues](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/TDDWithTestingLibrary.md). 35 | 36 | 3. Introducing Interactivity 37 | 38 | Now that we have the tests inplace for the static elements lets look at how to mock events like a user clicking on the button. 39 | 40 | Lets grab the button by its text, click it one time, then check that the counter is displaying 1. 41 | 42 | ``` javascript 43 | ... 44 | describe('the counter has a button to increment the count by one each time its clicked', () => { 45 | 46 | ... 47 | 48 | test('counter increments by one when button is clicked' , () => { 49 | const {getByText, getByTestId} = render(); 50 | 51 | getByText('click me').click(); 52 | 53 | expect(getByTestId('counter__display')).toHaveTextContent('1') 54 | }) 55 | 56 | }) 57 | ``` 58 | 59 | Modify the component to make this test pass. 60 | 61 | 4. One Last Test 62 | 63 | Given that we want our clicker to be able to increment several times, lets add a test similar to the last, but click the button three times and check that the display is equal to 3. 64 | 65 | ``` javascript 66 | test('counter increments by one when button is clicked' , () => { 67 | const {getByText, getByTestId} = render(); 68 | 69 | getByText('click me').click(); 70 | getByText('click me').click(); 71 | getByText('click me').click(); 72 | 73 | expect(getByTestId('counter__display')).toHaveTextContent('3') 74 | }) 75 | ``` 76 | 77 | That one should pass right away. 78 | 79 | 5. Conclusion 80 | 81 | If you would like to learn more about how to simulate interactivity in testing your components, testing library you can check out [Firing Events](https://testing-library.com/docs/dom-testing-library/api-events/). 82 | 83 | We've now looked at testing a static component and a dynamic but syncronous component. We'll now move onto [testing an asyncronous component](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/TestingAnAsyncrounousComponent.md). 84 | -------------------------------------------------------------------------------- /TDDWithTestingLibrary.md: -------------------------------------------------------------------------------- 1 | # Test Driven Development with Testing Library 2 | 3 | We worked with the provided test folder and test that comes built into a `create-react-app` project. Now, we will delete those starter tests and write tests for a custom component. 4 | 5 | To that end, please delete `App.test.js` and go ahead and delete all the boiler plate jsx in App.js. 6 | 7 | We will start by building an InfoCard component that will included a title and small block of text. This will be a static component with no user interaction. 8 | 9 | 1. Create Directory to Hold Component and Tests 10 | 11 | Create a new directory called infoCard. 12 | 13 | Inside this directory, create a second directory called `__test__`. This is the folder that will hold our test suite. Go ahead and create a file inside `/__test__` called InfoCard.test.js. 14 | 15 | We Should have a file structure that looks like this: 16 |
 17 |     .
 18 |     +-- src
 19 |     |   +-- infoCard
 20 |             +-- __test__
 21 |                 +-- InfoCard.test.js
 22 |     
23 | 24 | 2. Let's Write Our First Test 25 | 26 | Open `InfoCard.test.js`. Let's follow the example of our previous code and write our first test just to test if the component is rendering properly. 27 | 28 | ``` javascript 29 | import { render, screen } from '@testing-library/react'; 30 | import InfoCard from '.././InfoCard'; 31 | 32 | test('renders InfoCard', () => { 33 | render(); 34 | }); 35 | 36 | ``` 37 | 38 | We know we haven't even set up our component yet, so we expect this test to fail. 39 | 40 | And here it is: 41 | 42 | ``` javascript 43 | 44 | 1 | import { render, screen } from '@testing-library/react'; 45 | > 2 | import InfoCard from '.././InfoCard'; 46 | | ^ 47 | 3 | 48 | 4 | test('renders InfoCard', () => { 49 | 5 | render(); 50 | ``` 51 | 52 | Notice the carrot pointing to where this test has stopped. It can't import InfoCard because we haven't created it yet. Lets do that. 53 | 54 | 3. Create `InfoCard` 55 | 56 | Let's create InfoCard and run the test again. It fails again, but we see the pointers have moved down to line that says `render()`. 57 | 58 | 4. Let's Write the Barebones of the InfoCard 59 | 60 | Inside InfoCard.js add: 61 | 62 | ``` javascript 63 | import React from 'react'; 64 | 65 | function InfoCard(props) { 66 | return ( 67 |
68 | 69 |
70 | ); 71 | } 72 | 73 | export default InfoCard; 74 | ``` 75 | 76 | If you haven't stopped your test, you'll see that the test runs automatically and now, it passes! 77 | 78 | ``` javascript 79 | PASS src/components/infoCard/__test__/InfoCard.test.js 80 | ✓ renders InfoCard (15 ms) 81 | 82 | Test Suites: 1 passed, 1 total 83 | Tests: 1 passed, 1 total 84 | Snapshots: 0 total 85 | Time: 1.527 s 86 | Ran all test suites related to changed files. 87 | 88 | Watch Usage: Press w to show more. 89 | ``` 90 | 91 | As soon as we have a passing test, it's time to write a new test! 92 | 93 | 5. Write a Test for the Card Title 94 | 95 | Until now, we have checked that a component renders properly or we've checked for specific test on the screen. With our info card, we want to be able to pass the title and body text as props when the component is first rendered. Let's make sure we check for both the element that will hold the text as well as the text itself. 96 | 97 | When we want to target a specific element, we have the option of using `data-testid` as a property on our html element. 98 | 99 | Write a second test like this: 100 | 101 | ``` javascript 102 | test('it has an element to hold the title text', () => { 103 | const {getByTestId} = render(); 104 | expect(getByTestId('infoCard__title')).toBeInTheDocument(); 105 | }) 106 | ``` 107 | 108 | And of course, that will fail! Always exciting. Notice that the failing test is telling us exactly what we need to do next. 109 | 110 | 6. Add an Element with data-testid 111 | 112 | We return to our InfoCard component and we'll add a `h3` element with the data-testid property. 113 | 114 | ``` javascript 115 | ... 116 | return ( 117 |
118 |

); 132 | expect(getByText('Info Card Title')).toBeInTheDocument(); 133 | }) 134 | ``` 135 | 136 | Add a title prop to your conponent and render it inside the H3 element. 137 | 138 | 8. Repeat both Tests for the Content Area 139 | 140 | Follow the example of the previous two tests except this time, test for a data-testid of 'infoCard__content' and then test that the prop content takes some text and renders it in the component. 141 | 142 | I'll leave this implementation to you. 143 | 144 | Lastly, change your component such that all the tests pass. You should have five tests at this point. 145 | 146 | Our test file should look like this 147 | 148 | 9. Conclusion 149 | 150 | We've written a nice test suite for this rather static component. One thing to keep in mind is that we should never delete tests that we've previously written unless the requirements for the component change or if we discover we made some mistake in writing our tests. Tests build on one another as a sort of scafolding to ensure that the component does everything we expect it to do. 151 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /TestingAnAsyncrounousComponent.md: -------------------------------------------------------------------------------- 1 | # Testing an Asynchronous Component 2 | 3 | We've come very far in understanding how to test our frontend components. Many times, a frontend component calls out to an API for some data to show to the user. We don't know how long the response will take or if we will get exactly what we expected. In this case, we need our test to pause while we wait for the response and then assert that we got the expected response. 4 | 5 | 1. Render a New Component Called CatFact 6 | 7 | Let's set up a directory for a new component called `CatFact`. As with the previous exercises in this section, the directory should have a component called `CatFact.js` and a directory to hold the test file, `__test__`. 8 | 9 | As always, lets follow a Test Driven Development approach to building this component. We'll start with a test file called `catFact.test.js`. and the contents should look like this: 10 | 11 | ``` javascript 12 | 13 | import { render } from '@testing-library/react'; 14 | 15 | import CatFact from '../CatFact'; 16 | 17 | describe('CatFact displays random catfact on mount and a new one on each button click', () => { 18 | 19 | it('renders CatFact component', () => { 20 | render(); 21 | }); 22 | 23 | } 24 | ``` 25 | 26 | Go ahead and run your tests at the command line with `npm test catFact`. 27 | 28 | Fix the failing test, by putting together a basic functional component. 29 | 30 | 2. Component Layout 31 | 32 | This component will have two basic elements. First, there will be an area to display a cat fact and second, a button that will load a new cat fact. Let's write the tests for each of these now. 33 | 34 | ``` javascript 35 | 36 | import { render } from '@testing-library/react'; 37 | 38 | import CatFact from '../CatFact'; 39 | 40 | describe('CatFact displays random catfact on mount and a new one on each button click', () => { 41 | 42 | ... 43 | it('has an element to display the text of a cat fact', () => { 44 | const {getByTestId} = render(); 45 | 46 | expect(getByTestId('catFact__textContainer')).toBeInTheDocument() 47 | }) 48 | 49 | it('has a button to load a new cat fact', () => { 50 | const {getByTestId} = render(); 51 | 52 | expect(getByTestId('catFact__button')).toBeInTheDocument(); 53 | }); 54 | 55 | } 56 | 57 | ``` 58 | 59 | Write the code to make these tests pass. 60 | 61 | Remember that setting up a testid on any HTML element looks like this: 62 | 63 | ``` HTML 64 |
65 | ``` 66 | 67 | 3. Writing the Tests for Initial Mount 68 | 69 | When our component initially loads, we need to query the API on mount to bring in the first random cat fact. Until the fact is returned, we want our button to display 'Loading...' and we expect our text container to be empty. 70 | 71 | Let's write a test that asserts that the button should say 'Loading...' when we first render our component: 72 | 73 | ``` javascript 74 | ... 75 | 76 | describe('CatFact displays random catfact on mount and a new one on each button click', () => { 77 | ... 78 | 79 | it('button text initializes to "Loading..."', () => { 80 | 81 | const{getByText} = render(); 82 | 83 | expect(getByText('Loading...')).toBeInTheDocument(); 84 | 85 | }); 86 | } 87 | 88 | ``` 89 | 90 | That's it. We are simply asserting that before anything happens, out button says 'Loading...'. If you run this in the browser when calling the API correctly, you may not even see the loading text. But our test is fast and will verify that the button defaults to 'Loading...' even if the API call is very fast. 91 | 92 | Now, we don't have a fact when the component initially loads, so we expect our text container to be empty. Let's write a test for this: 93 | 94 | ``` javascript 95 | ... 96 | 97 | describe('CatFact displays random catfact on mount and a new one on each button click', () => { 98 | ... 99 | 100 | it('has no text in textContainer on mount', () => { 101 | const{getByTestId} = render(); 102 | 103 | expect(getByTestId('catFact__textContainer')).toBeEmptyDOMElement() 104 | }) 105 | } 106 | 107 | ``` 108 | 109 | Write the code to make this test pass. Note that you do not need to set up an API call, nor change the button text for this test to pass. 110 | 111 | 4. Writing Tests for Asynchronous Behaviour On Mount 112 | 113 | As soon as the component mounts, lets call out cat fact api. You can reach it here: `call to `https://catfact.ninja/fact`. The response from the API will look something like this: 114 | 115 | ``` json 116 | { 117 | "fact":"All cats have three sets of long hairs that are sensitive to pressure - whiskers, eyebrows,and the hairs between their paw pads.", 118 | "length":128 119 | } 120 | ``` 121 | 122 | We want to do two thigs and we need a test to assert each of them. First, we want our button text to change to 'Load Cat Fact' once our API response is returned. 123 | 124 | ``` javascript 125 | ... 126 | 127 | describe('', () => { 128 | ... 129 | it('changes button text to "Load Cat Fact" on successful mount', async () => { 130 | const{getByText, findByText, queryByText} = render(); 131 | 132 | expect(getByText('Loading...')).toBeInTheDocument(); 133 | 134 | await findByText('Load Cat Fact'); 135 | 136 | expect(queryByText('Loading...')).not.toBeInTheDocument(); 137 | }) 138 | }) 139 | 140 | ``` 141 | 142 | Note that with this test, since we are testing something asynchronous, we need to preface our callback with the `async` keyword. 143 | 144 | We need to check that once the call is returned, the button text is back to 'Load Cat Fact' and then fact itself has changed. We will use a new Jest method called `findByText` to do this. Using `findByText` tells our test to look for something and to remain looking for it for up to 4 seconds. If it is not found after 4 seconds, the test will fail. Otherwise the test will pass. Under any normal circumstances, our API should return the expected result in less than 4 seconds. 145 | 146 | To make this test pass, create a hook called `loading` that starts as true but is set to false when the API returns. Then make the text on the button dependent on the hook. When `loading` is true, the button test should be 'Loading...' and then when it is false, the button text should be 'Load Cat Fact'. 147 | 148 | We also introduce an assertion modifier here: `expect(queryByText('Loading...')).not.toBeInTheDocument();` We use not to say that we are looking for the opposite of the assertion. 149 | 150 | Let's move on to asserting that on a successful API call, we place the text of the cat fact in the text container. 151 | 152 | describe('', () => { 153 | ... 154 | it('displays a catfact on successful mount', async () => { 155 | const {getByTestId, findByText} = render(); 156 | 157 | await findByText('Load Cat Fact'); 158 | 159 | expect(getByTestId('catFact__textContainer')).not.toBeEmptyDOMElement(); 160 | }) 161 | }) 162 | 163 | ``` 164 | 165 | Here we assert that after the successful API call, the text container is not empty. You can handle this by setting a hook called `catFact`, setting it to an empty string when you start and set it to the cat fact when the API returns. 166 | 167 | 5. Writing the Tests for Asynchronous Behavior on User Interaction 168 | 169 | Finally, we will wrap up our testing by making assertions for the asynchronous behaviors of our component when the button is clicked. The component should make a call to `https://catfact.ninja/fact` and replace the old fact with the new one. 170 | 171 | We need to check that when the button is clicked, the text changes to 'Loading...'. Once the call is returned, the button text is back to 'Load Cat Fact'. 172 | 173 | Additionally, the fact itself will have changed. 174 | 175 | Let's start by writing the test for the button text changing and then returning to 'Load Cat Fact'. We will use the `click()` event here that we used in the last chapter. 176 | 177 | ``` javascript 178 | ... 179 | 180 | describe('CatFact displays random catfact on mount and a new one on each button click', () => { 181 | ... 182 | 183 | it('changes button text on button click until API responds', async () => { 184 | 185 | const{getByTestId, findByText, queryByText} = render(); 186 | 187 | await findByText('Load Cat Fact'); 188 | 189 | let button = getByTestId('catFact__button'); 190 | 191 | button.click(); 192 | 193 | await findByText('Load Cat Fact'); 194 | 195 | expect(queryByText("Loading...")).not.toBeInTheDocument(); 196 | }) 197 | } 198 | 199 | ``` 200 | 201 | Write the code to make this test pass. 202 | 203 | Finally, we want to write a test to make sure the text changes when a new fact is loaded. Since the facts are randomly loaded, we will save the current fact text and then make sure that it is no longer in the DOM after a new fact is loaded. Let's do that now: 204 | 205 | ``` javascript 206 | ... 207 | 208 | describe('CatFact displays random catfact on mount and a new one on each button click', () => { 209 | ... 210 | 211 | it('changes cat fact text on button click', async () => { 212 | const{getByTestId, findByText, queryByText, queryByTestId} = render(); 213 | 214 | await findByText('Load Cat Fact'); 215 | 216 | let firstCatFact = getByTestId("catFact__textContainer").innerHTML; 217 | 218 | let button = getByTestId('catFact__button'); 219 | 220 | button.click(); 221 | 222 | await findByText('Load Cat Fact'); 223 | 224 | expect(queryByText(firstCatFact)).not.toBeInTheDocument(); 225 | expect(queryByTestId("catFact__textContainer")).not.toBeEmptyDOMElement(); 226 | }) 227 | }) 228 | ``` 229 | 230 | Write code to change the cat fact on a successful API response and this test should pass just fine. We don't know what text we are expecting, but we can test that the old text is no longer shown. 231 | 232 | We have now written a good set of comprehensive tests for an asynchronous component. If you would like to go further, you can test for unsuccessful responses that result in errors and make sure your component is properly handling those as well. 233 | 234 | 5. Conclusion 235 | 236 | Testing is a deep subject and we have only gotten started here. Take a look at the Jest or Testing Library documentation to learn more about what you can do with frontend testing. 237 | 238 | 239 | -------------------------------------------------------------------------------- /TestingFEComponents.md: -------------------------------------------------------------------------------- 1 | # Testing Front-End Components in React 2 | 3 | Writing tests can help up define what we want a component to do, even before we've written the first line of code. A simple component may be used to render some static text. Still we should write a test to make sure that now, and in the future, the component has the elements we expect it to have. 4 | 5 | As we move into more dynamic components, such as those that query an API, wait for the data to be returned and then show that data, our tests need to account for what is happening with the component at each step. 6 | 7 | When working with React, the testing framework is included when we initialize our app with `npm create-react-app app-name`. This framework is called [Testing Library](https://testing-library.com/) and it is built on top of [Jest](https://jestjs.io/). 8 | 9 | Let's go ahead and test our first component. We will largely follow a [Test Driven Development](https://www.guru99.com/test-driven-development.html) methodology when leaning to test. 10 | 11 | 1. Create a new React Application 12 | 13 | In your terminal enter: `npm create-react-app learning-to-test` 14 | 15 | 2. Testing is Built In 16 | 17 | Run `npm test` and voila, just like that you will run your first test and see it pass. 18 | 19 | You should see something like this: 20 | 21 | ``` javascript 22 | PASS src/App.test.js 23 | ✓ renders learn react link (35 ms) 24 | 25 | Test Suites: 1 passed, 1 total 26 | Tests: 1 passed, 1 total 27 | Snapshots: 0 total 28 | Time: 3.666 s 29 | Ran all test suites related to changed files. 30 | 31 | Watch Usage: Press w to show more. 32 | ``` 33 | 34 | We see that 1/1 tests has passed! Go ahead and press `ctrl + c` to stop the testing process. 35 | 36 | 3. Let's Look at the First Test 37 | 38 | Go ahead and open `src/App.test.js`. You'll see code like this: 39 | 40 | ``` javascript 41 | 42 | import { render, screen } from '@testing-library/react'; 43 | import App from './App'; 44 | 45 | test('renders learn react link', () => { 46 | render(); 47 | const linkElement = screen.getByText(/learn react/i); 48 | expect(linkElement).toBeInTheDocument(); 49 | }); 50 | 51 | ``` 52 | 53 | Let's breakdown what is happening with this code: 54 | 55 | ` import { render, screen } from '@testing-library/react';` 56 | 57 | We are importing the testing library methods that we'll use. 58 | 59 | `import App from './App';` 60 | 61 | We then import the component that we plan to test. 62 | 63 | ``` javascript 64 | test('renders learn react link', () => { 65 | ... 66 | }); 67 | ``` 68 | 69 | Here we see the primary building block of testing. We have a function called `test` that takes two arguments: 70 | 71 | 1. A human readable message describing what the test is looking for. Here we have the message 'renders react link'. 72 | 73 | 2. A call back function that usually starts by setting up the component and checking some expectation of that component. 74 | 75 | ``` javascript 76 | test('renders learn react link', () => { 77 | render(); 78 | const linkElement = screen.getByText(/learn react/i); 79 | expect(linkElement).toBeInTheDocument(); 80 | }); 81 | ``` 82 | 83 | Finally, we look at the content of the callback function. First we render the component. Then, we set a variable called `linkElement` and we grab this element by searching the 'screen' for the text 'learn react'. 84 | On the last line, we complete the test with our `expect` function. Expect takes one argument that is some element we want to target. Then we use one of several methods, `toBeInTheDocument()`, in this case to express what we expect. 85 | 86 | So if we were to translate this to plain english we might say: 87 | "Go ahead and render the App component. Search that component for an element that includes the text 'learn react' and give it a name of `linkElement`. At last, check to make sure that the element is in the component that we rendered. 88 | 89 | 4. Let's Write a New Test 90 | 91 | Inside the same test file, let's add a new test. Given that we are now following Test Driven Development (TDD), we expect this test to fail after we write it. 92 | 93 | Add this to the end of `src/App.test.js`: 94 | 95 | ``` javascript 96 | test('renders learn react link', () => { 97 | render(); 98 | const linkElement = screen.getByText(/Hello Friend/i); 99 | expect(linkElement).toBeInTheDocument(); 100 | }); 101 | ``` 102 | 103 | After you have added this, go ahead and run `npm test`. 104 | 105 | You should see something like this: 106 | 107 | ``` javascript 108 | Test Suites: 1 failed, 1 total 109 | Tests: 1 failed, 1 passed, 2 total 110 | Snapshots: 0 total 111 | Time: 3.786 s 112 | Ran all test suites related to changed files. 113 | 114 | Watch Usage 115 | › Press a to run all tests. 116 | › Press f to run only failed tests. 117 | › Press q to quit watch mode. 118 | › Press p to filter by a filename regex pattern. 119 | › Press t to filter by a test name regex pattern. 120 | › Press Enter to trigger a test run. 121 | ``` 122 | 123 | This time, we see that we have two total tests, where one is successful and one has failed. 124 | 125 | Simlar to last time, let's close our test runner by pressing `ctrl + c`. 126 | 127 | 4. Making the Test Pass 128 | 129 | We've created a failing test, now how do we make it pass? 130 | 131 | Open App.js. Somewhere in the return statement, create an element like this: 132 | `
Hello Friend
` 133 | 134 | Let's run the tests again: `npm test`. 135 | 136 | You should now see something like this: 137 | 138 | ``` javascript 139 | PASS src/App.test.js 140 | ✓ renders learn react link (34 ms) 141 | ✓ renders learn react link (6 ms) 142 | 143 | Test Suites: 1 passed, 1 total 144 | Tests: 2 passed, 2 total 145 | Snapshots: 0 total 146 | Time: 4.213 s 147 | Ran all test suites related to changed files. 148 | 149 | Watch Usage 150 | › Press a to run all tests. 151 | › Press f to run only failed tests. 152 | › Press q to quit watch mode. 153 | › Press p to filter by a filename regex pattern. 154 | › Press t to filter by a test name regex pattern. 155 | › Press Enter to trigger a test run. 156 | ``` 157 | 5. Conclusion 158 | 159 | Great! We've started a new project, we've run the first test that comes with the project. We then added an addtional test and saw it failing. Finally, we added an element to our App component that satisfied our second test and see that both of our tests are passing. 160 | 161 | Let's move one to building a custom component following [TDD With Testing Library](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/TDDWithTestingLibrary.md). 162 | 163 | -------------------------------------------------------------------------------- /UsingBEM.md: -------------------------------------------------------------------------------- 1 | # Using BEM in Your Project 2 | 3 | It can be a challenge to set a consistent standard for how you are using class names across a web application. While there are many possible patterns you can follow, we will be learning one called BEM. BEM is an acronym standing for Block Element Modifier. 4 | 5 | # Block 6 | 7 | A block represents a piece of HTML that must stay together for it to be useful. As an example, usually a form is made up lables, inputs and a submit button. If we separate the inputs from the labels or the submit button from the form, it would no longer work properly. We can then say that our form is a block. 8 | 9 | We give blocks a class name that represent what it is. We already followed this with our info card. 10 | 11 | ``` HTML 12 |
13 |
Info Card
14 |
15 | This is an info card with some content. 16 |
17 |
18 | ``` 19 | 20 | We write our class names in camel case. Usually, this class name will match the component name when working in React. 21 | 22 | # Element 23 | 24 | An element is one of the pieces that make up the block. For example, our info card has two elements: the title and the text. 25 | 26 | When using class names like 'title' or 'text', we run the risk of accidentally colliding with the same name in a different component. When following BEM, we will give each of them a class name made of three parts: 27 | 28 | 1) the block name - 'info-card' 29 | 2) two underscores '__' 30 | 3) its own identifier = 'title' 31 | 32 | When we put it all together it looks like this: 'info-card__title' and 'info-card__test'. By following this pattern, we have largely reduced our chances of duplicating a style somewhere else in the application to 0. 33 | 34 | Here's what it looks like when we've changed the class names on each element: 35 | 36 | ``` HTML 37 |
38 |
Info Card
39 |
40 | This is an info card with some content. 41 |
42 |
43 | ``` 44 | 45 | # SCSS 46 | 47 | Now that we've changed our class names to match the BEM paradigm, let's get our SCSS working again. We didn't change the class name of our parent div and we didn't apply any styling to the text on our card, so we have no worries with either of those. Our title has changed however. We previously had a class name of 'title' and now we are using 'info-card__title'. SCSS allows us to use the `&` character to represent all previous nested css selectors. This sounds more complicated than it is. First, here is what it looks like: 48 | 49 | ``` css 50 | .info-card { 51 | text-align: center; 52 | border: 1px solid black; 53 | width: 250px; 54 | margin: 0 auto; 55 | padding: 20px; 56 | 57 | &__title { 58 | font-weight: 600; 59 | padding: 10px; 60 | } 61 | } 62 | ``` 63 | 64 | So what is happening here? By the time the SCSS engine has run, it sees that the title is nested under '.info-card' and also that it has `&` meaning it should replace the `&` with the previous class. The result is css that looks like this: 65 | 66 | ``` css 67 | 68 | .info-card { 69 | text-align: center; 70 | border: 1px solid black; 71 | width: 250px; 72 | margin: 0 auto; 73 | padding: 20px; 74 | } 75 | 76 | .info-card .info-card__title { 77 | font-weight: 600; 78 | padding: 10px; 79 | } 80 | ``` 81 | 82 | Don't worry if it doesn't make sense right away. It will become natural with repetition. 83 | 84 | # BEM 85 | 86 | To learn more about BEM, head over to [Get BEM](http://getbem.com/naming/) 87 | 88 | Let's move into [implementing this into a React project](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/SCSSInYourProject.md). 89 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Advanced Basics for Web 2 | 3 | ### Section 1: SCSS and BEM 4 | 5 | Learning Objectives: 6 | 7 | 1. Understand the BEM naming convention 8 | 2. Understand SCSS nesting, partials and variables 9 | 3. Be able to Implement SCSS in a React Project 10 | 11 | [Video recording](https://us06web.zoom.us/rec/share/rNUjdMBTVDzfy4nXCCPinBSRLUET4DI_6do1vSCszQ1a5GxLo1hTf73pocGNuRNB.qR5h4dfwGSXmvK1X) 12 | 13 | 1. [What is BEM](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/UsingBEM.md) 14 | 2. [What is SCSS](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/SCSS.md) 15 | 3. [Using SCSS in Your React Project](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/SCSSInYourProject.md) 16 | 4. [Other SCSS Features](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/SCSSFeatures.md) 17 | 18 | 19 | ### Section 2: Building Responsive Components 20 | 21 | Learning Objectives: 22 | 23 | 1. Able to explain what a responsive component is 24 | 2. Able to use Media Queries to conditionally attach styles to the DOM 25 | 3. Able to build responsive components in a React project 26 | 27 | [Video recording](https://us06web.zoom.us/rec/share/XOdkPa1YWKnTllJ0GNMlYh4Mz9C90v0WMcjbkXuzl8x1YgSmsOFIBzUB7IE8ngLQ.s743OcrH7F9vsPdH) 28 | 29 | [Source Code](https://github.com/werner33/react-responsive-navbar) 30 | 31 | 1. [What is a Responsive Component](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/BuildingResponsiveComponents.md) 32 | 2. [Laying Out a Nav Bar](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/LayOutNavBar.md) 33 | 3. [Introducing Media Queries]() 34 | 4. [Using Hooks to Toggle Our Responsive Nav Bar]() 35 | 36 | ### Section 3: UX for Asynchronous Components 37 | 38 | [Video recording](https://us06web.zoom.us/rec/share/YKboI4HnNvvUJJ71qfw3AE8E_1oXbyd5XzvTcuAHGyIdubfxftUQRDNN6c7Rn-GU.MpXjApcQuwhGbPg1) 39 | 40 | [Source Code](https://github.com/werner33/button-loader) 41 | 42 | ### Section 4: Testing Components with Jest 43 | 44 | [Video recording](https://us06web.zoom.us/rec/share/OO03gD39Z1UdGvPmry08BlYbsGTduUjTvYx4kOY42JZdYsb3WKDdyyecpNPLijFa.mecKR7_UJo3K_qnK) 45 | 46 | [Source Code](https://github.com/werner33/testing_components_with_jest) 47 | 48 | 1. [Adding Your First Test](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/TestingFEComponents.md) 49 | 2. [TDD With Testing Library](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/TDDWithTestingLibrary.md) 50 | 3. [TDD with Interactive Component](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/TDDWithInteractiveComponent.md) 51 | 4. [Testing an Asyncronous Component](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/TestingAnAsyncrounousComponent.md) 52 | 53 | ### Section 5: Managing API calls and Caching 54 | 55 | Learning objectives: 56 | 57 | 1. Understand how and where API's should be called in a React Application 58 | 2. Able to split code in React for better user experience and faster loading times 59 | 3. Able to save and access data in session storage 60 | 61 | [Video recording](https://us06web.zoom.us/rec/share/i139O6kgdlQVmKy_U-HZmjES4Os2fXc7y1qqm1NrJcT7gf0kYlWvN-b0OfMnZ_On.510fvVrueHcg7S3J) 62 | 63 | 1. [API Calls Overview](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/API_Management.md) 64 | 2. Where Should Calls Be Made in an Application? 65 | 3. Code Splitting in React 66 | 4. Caching in Session Storage 67 | 68 | ### Section 6: Testing APIs with Jest and Supertest 69 | 70 | Learning Objectives: 71 | 72 | 1. Implement Jest and Supertest in Express app 73 | 2. Write and run unit tests 74 | 3. Write and run integration tests on specific routes 75 | 76 | [Video recording](https://us06web.zoom.us/rec/share/ZpEzyy8cN0iFowpvbtWWoPZQehwFdI-ySxgWoV81xQUlAnyBtBMWuGoJ7MtXWk8V.BPNdCc-Q7sj7lLcp) 77 | OR 78 | [Video recording](https://us06web.zoom.us/rec/play/TOcmrzeqI1ZjOUTRbEs7HiZ08-nij_KjqWrpji4UKXWlrfkHOZn-dMyaDP87G298gKmc_TX5yTTuuwCQ.LAL-8gwgVlrobDVN?startTime=1643643373000) 79 | 80 | [Source Code](https://github.com/werner33/unit-testing-be) 81 | 82 | [Outline](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/SuperTest.md) 83 | 84 | ### Section 7: Client Side Storage 85 | 86 | Learning Objectives: 87 | 88 | 1. Able to reason about when and how data should be stored in the browser 89 | 2. Able to talk about the difference between ways to store data in the browser 90 | 91 | [Video Recording](https://us06web.zoom.us/rec/share/gHDtJXabuim1J3-1BpguS8fV9w0FEt_cc8rC9nLwpGbb8Qt7z6azuytaDXt699RL.VtUdMW-eVz7ha7tf) 92 | [Source Code]() 93 | 94 | 1. [Overview of Client Side Storage](https://github.com/werner33/AdvancedBasicsForWeb/new/main) 95 | 2. [Cookies]() 96 | 3. [Session Storage]() 97 | 4. [Local Storage]() 98 | 99 | ### Section 8: SQL 1 100 | 101 | Learning Objectives: 102 | 103 | 1. Review how SQL relates to web developement including SQL commands and http protocols 104 | 2. Review or learn to use BETWEEN, LIKE, GROUP BY, BETWEEN, SORT BY and LIMIT 105 | 106 | [Video Recording](https://us06web.zoom.us/rec/share/FLWyETb6OCNRM7k25wOTTj7WW1gZDP1jxEgr7AfodzXJssvIqa-zo88jizNFSYCb.tJ1PWknVaagh7tou?startTime=1645457925000) 107 | 108 | 1. [Understanding the Connection between SQL and Web Development](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/SQL1.md) 109 | 2. [Refining Selectors when Making a Query](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/RefiningSQLQueries.md) 110 | 111 | ### Section 9: SQL 2 112 | 113 | [Video Recording](https://us06web.zoom.us/rec/share/BoB8IpCa5Uoa7jzI_Knd19fvypL81L4SkuV6O92oUGMNN_ylMaeJPK4DIFxcTGGB.l9cel_oP2W5xv_Pz) 114 | 115 | 1. [Joins](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/SQL2.md) 116 | 117 | ### Section 10: Git 118 | 119 | Learning Objectives: 120 | 121 | 1. Able to explain the difference between `git log` and `git reflog` 122 | 2. Able to resolve conflicts when merging 123 | 3. Able to use git stash including stashing, poping and writing messages 124 | 125 | [Video recording](https://us06web.zoom.us/rec/share/egfytomWNFusx5OuK3XA_z3EzJG8umH8Rkaah-DlpC-O96_qFA6Z0qsIj9-IsLDH.U5U8fswTfEz57Ugm) 126 | 127 | 1. [Review of Git](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/Git.md) 128 | 2. [Amending Commits](https://github.com/werner33/AdvancedBasicsForWeb/blob/main/Git2.md) 129 | 130 | 131 | 132 | ### Section 11: Contributing to Open Source 1 133 | 134 | Learning Objectives 135 | 136 | 1. Able to explain what open source software is and give examples 137 | 2. Able to explore open source software including reviewing issues that are open for resolution 138 | 3. Able to fork and clone a repo to commence work on an issue 139 | 140 | [Video Recording](https://us06web.zoom.us/rec/share/qlWbQFFTKtwkqgINa4GvKUYUFt7dxpiqaWBGhD6IMFeEUT9-ncKTjQE3EUN1orhM.1K2r56Ps6b9Ly-Rs) 141 | 142 | 1. [What is Open Source?]() 143 | 2. [Find a Project to Contribute To]() 144 | 3. [Reviewing Open Issues]() 145 | 4. [Forking, Cloning and Getting Started]() 146 | 147 | 148 | ### Section 12: Contributing to Open Source 2 149 | 150 | Learning Objectives 151 | 152 | 1. Selects 1-2 issues that they would like to resolve 153 | 2. Begins the process of resolving the issue 154 | 155 | 1. Resolving an Issue Locally 156 | 2. Opening a Pull Request 157 | 3. Resolving a Bounced Pull Request 158 | 4. Adding an Open Source Contribution to Your Resume 159 | 160 | 161 | --------------------------------------------------------------------------------