Skip to content

Commit

Permalink
merge
Browse files Browse the repository at this point in the history
  • Loading branch information
kaylagordon committed Oct 31, 2023
2 parents 2d75feb + 601cf0d commit 812df2c
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 79 deletions.
2 changes: 1 addition & 1 deletion lessons/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ <h2>Module 2 Lessons</h2>
<p class="mod-description">Module 2 focuses on fundamental JavaScript concepts, popular patterns for writing and organizing front-end code, and learning new tools and workflows to help improve the development process for more complex applications. Projects will reinforce lesson concepts by emphasizing Object-Oriented Programming, Test-Driven Development and heavy data manipulation.</p>

<h3>Instructors</h3>
<li>Jeremiah Black (Anchor)</li>
<li>Jeremiah Black</li>
<li>Kayla Gordon</li>

<h3>Resources</h3>
Expand Down
29 changes: 1 addition & 28 deletions lessons/module-2/npm-and-tooling.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,9 @@ As developers, we use a lot of tools to facilitate building our applications - f

As our apps grow to be more complex, our toolbox is going to grow as well. So far, we've added quite a few things to your toolkit without really digging deep into what they do, why we use them, and how they work. So today we're going to shed some light on them. Specifically, we'll be talking about NPM.

## Configuration Files

Looking at the top-level, root directory of [the webpack starter kit for What's Cookin](https://github.com/turingschool-examples/whats-cookin-starter-kit), for instance, we already have quite a few files.

<section class="call-to-action">
### Turn and Talk

Based on the files in root, what tools are used to facilitate the development of our application?
</section>

<section class="answer">
### Configuration Files

* `.gitignore` - tells git not to add certain files to our repo
* `package-lock.json` - builds a dependency tree of any third-party code we are relying on and what versions of those packages our app is using
* `package.json` - describes our application to NPM and what dependencies we need in order to use and develop the app
* `webpack.config.js` - tells webpack how to gather all of the files in our application to create a file bundle

With the exception of the `README.md` file, each of these is some sort of configuration file. A **configuration file** is a file that allows you to define how a particular tool you're using should interact with your codebase.
</section>

## NPM

**The NPM Files:** `package.json` and `package-lock.json`
**The NPM Configuration Files:** `package.json` and `package-lock.json`

NPM stands for **Node Package Manager**. A package manager is a registry where developers can publish reusable pieces of code that they've written (a package), and allow other developers to download it directly into their projects (as a dependency). NPM is not the only package manager - you may see others such as Yarn or Bower.

Expand Down Expand Up @@ -139,9 +118,3 @@ filterWords(3, ['this', 'that', 'hey', 'hat', 'hi'])
// should return ['this', 'that', 'hi']
```
</section>

### Examining the package.json File In Depth

Let's explore the [package.json](https://github.com/turingschool-examples/gametime-starter/blob/master/package.json) file a bit. This is a configuration file that provides NPM with important information about our project. It is automatically generated for us when we start a new project and run the command `npm init`. (This is very similar to when you start a new git repo!)

We have some more generic information, like the title, description and author of our app, and a link to the repository and where to file issues. The more involved pieces of this file that we'll explore are the `scripts` and the `devDependencies` sections.
88 changes: 55 additions & 33 deletions lessons/module-3/intro-to-cypress-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,16 +230,27 @@ This is great and all but let's think about what we actually need to test. Reme

Now that we've identified some user flows, let's get to testing (finally)! First, let's focus on this user flow:

**As a user, I should be able to visit `http://localhost:3000` and see a title & form displayed.**
**1a. As a user, I should be able to visit `http://localhost:3000` and see a title & form displayed.**

* Write a test that asserts that a user can visit `http://localhost:3000` using the [visit](https://docs.cypress.io/api/commands/visit.html#Syntax) command.
* In the same `it` block, check to make sure that our site can [get](https://docs.cypress.io/api/commands/get.html#Syntax){:target='blank'} a form and that it [contains](https://docs.cypress.io/api/commands/contains.html){:target='blank'} the correct text on the page!
* In the same `it` block, check to make sure that our site [contains](https://docs.cypress.io/api/commands/contains.html){:target='blank'} the correct title text.
* Then, check to make sure our site can [get](https://docs.cypress.io/api/commands/get.html#Syntax){:target='blank'} the displayed form and that it [contains](https://docs.cypress.io/api/commands/contains.html){:target='blank'} the correct header text within the form.
* Run your test to ensure no errors so far. Take note of any errors that you get in the `Test Body` of the **Command Log**.

**1b. Adding onto the same flow, as a user, I can select the inputs, fill them out, as confirm that each input's value matches what I typed.**
* In the same `it` block, get the *email* input field, [type](https://docs.cypress.io/api/commands/type.html){:target='blank'} "[email protected]" into that field. This is the user action we're simulating in Cypress. Now we need to assert against the results of that action.
* Assert that the email input field [should](https://docs.cypress.io/api/commands/should.html#Syntax){:target='blank'} have the same value as whatever you typed into it.
* Get the *password* input field, type "keane20" into that field.
* Assert that the email input field [should](https://docs.cypress.io/api/commands/should.html#Syntax){:target='blank'} have the same value as whatever you typed into it.
* Take note of any errors that you get in the `Test Body` of the **Command Log**.

This test might feel a bit unneccesary and overly simple - but it's valuable. Thinking about controlled forms, what are we actually testing here?
<!-- Here is a link to [commonly used assertions](https://docs.cypress.io/guides/references/assertions.html#Common-Assertions) in Cypress! -->

<section class="note">
### Note
### Note - Your React app must be running in order for Cypress to work

You might notice that your test fails when trying to load your site. This is because Cypress is actually trying to visit your page, but your server is not running. Make sure your React server is running in a separate tab on your terminal! You do not need to have the API server running, though.
If your test fails when trying to load your site, this might be because Cypress is actually trying to visit your page, but your server is not running. Make sure your React App server is running in a separate tab on your terminal! You do not need to have the API server running, though.
</section>

<section class="answer">
Expand All @@ -249,71 +260,67 @@ You might notice that your test fails when trying to load your site. This is bec
// login_spec.js

describe('Feedback Loop login', () => {
it('Should be able to visit the page and render the correct elements', () => {
it('Should be able to visit page, render correct elements, and hold values in inputs', () => {
cy.visit('http://localhost:3000')
.contains('Feedback Loop')
.get('form')
.contains('Please Sign In');
.get('form').contains('h2', "Please Sign In")
.get("input[name='email']").type("[email protected]").should('have.value', '[email protected]')
.get("input[name='password']").type("keane20").should('have.value', 'keane20')
});
});
```

Note that we can chain multiple methods to make multiple assertions!
</section>

Before starting our next test, let's add in the following block:
Before we continue, let's add in the following block:

```js
beforeEach(() => {
cy.visit('http://localhost:3000');
});
```

This helps to ensure that we start anew before each test. A [best practice](https://docs.cypress.io/guides/references/best-practices.html#Having-tests-rely-on-the-state-of-previous-tests){:target='blank'} is that tests should always be able to run independently from one another and *still pass*.
This helps to ensure that we start anew before each test. A [best practice](https://docs.cypress.io/guides/references/best-practices.html#Having-tests-rely-on-the-state-of-previous-tests){:target='blank'} is that tests should always be able to run independently from one another and *still pass*. A **common pitfall** is adding code to the beforeEach that isn't needed by every `it` block. If it's not used by every single `it` block, it doesn't belong in the beforeEach - put it directly into `it` blocks that needed it instead.

**User flow to test:** I can select different inputs and fill them out.
<section class="note">
### Did You Know?

* Experiment with [type](https://docs.cypress.io/api/commands/type.html){:target='blank'} and [should](https://docs.cypress.io/api/commands/should.html#Syntax){:target='blank'} as you write a test that selects the `Email` and `Password` inputs and fills them with the corresponding values, `[email protected]` and `keane20`. Assert that they have the correct values.
In the test runner, you can actually hit `command + option + i` to open up your DevTools! Instead of looking at your code, use your DevTools to find the necessary elements you need to query.

Here is a link to [commonly used assertions](https://docs.cypress.io/guides/references/assertions.html#Common-Assertions) in Cypress!
To add the React Dev Tools to your cypress browser window, take a look at [this blog post](https://www.cypress.io/blog/2020/01/07/how-to-load-the-react-devtools-extension-in-cypress/){:target='blank'}.
</section>

**User flow to test:** I will receive an error message when I click the Submit button without filling out both inputs.
**2. User flow to test:** I will receive an error message when I click the Submit button without filling out both inputs.

* Write another test that asserts an error message is displayed when the Submit button is [clicked](https://docs.cypress.io/api/commands/click.html){:target='blank'} without filling both inputs.
* Write another test - in a new `it` block - that asserts an error message is displayed when the Submit button is [clicked](https://docs.cypress.io/api/commands/click.html){:target='blank'} without filling both inputs.

<section class="note">
### Did You Know?
### Note - Never end a test on a "click"

In the test runner, you can actually hit `command + option + i` to open up your DevTools! Instead of looking at your code, use your DevTools to find the necessary elements you need to query.
Why? Because to test any user flow, we need to walk Cypress through simulating some user action. *Then*, we assert against whatever the user should see on the DOM as a *result* of that action. The `click` is the action, so its only getting us halfway there. We always need to add assertions after.

To add the React Dev Tools to your cypress browser window, take a look at [this blog post](https://www.cypress.io/blog/2020/01/07/how-to-load-the-react-devtools-extension-in-cypress/){:target='blank'}.
Here is a link to [commonly used assertions](https://docs.cypress.io/guides/references/assertions.html#Common-Assertions) in Cypress!
</section>

<section class="answer">
### Solutions

```js
it('should be able to select the email and password inputs and fill them with the corresponding values', () => {
cy.get('input[type="email"]')
.type('[email protected]')
.should('have.value', '[email protected]')
.get('input[type="password"]')
.type('keane20')
.should('have.value', 'keane20')
})

it('should display an error message when a user clicks the Submit button without filling both inputs', () => {
cy.get('button').click()
cy.contains('Please fill out both inputs')
cy.get('button').click() //This is the user action we're simulating.
cy.get('p').contains('Please fill out both inputs.') //This is where we're asserting against whatever we expect as a result of that user action.
});
```
</section>



### Writing tests involving network requests

**User Story:** As a user, I can fill out the `email` and `password` inputs and click the Submit button and be directed to a different URL.
**User Story:** As a user, I can correctly fill out the `email` and `password` inputs and click the Submit button and be directed to a different URL.

* This builds off of what we have done previously, however we now want to test that when we log in successfully and visit the new url `http://localhost:3000/dashboard`. It's okay if the page doesn't display all of the data on the next page, just assert that the url has updated.
* This builds off of what we have done previously, however we now want to test that when we log in successfully, our app takes us to a new url - `http://localhost:3000/dashboard`. It's okay if the page doesn't display all of the data on the next page, just assert that the url has updated for now.

<section class="note">
### Note
Expand Down Expand Up @@ -347,11 +354,13 @@ For now (and throughout Mod 3), we will instead use [stubbing](https://docs.cypr
.url().should('include', '/dashboard')
});
```
</section>

Note that we are just intercepting the `POST` request for logging in and mocking out what the expected response would look like. Our dashboard is blank because we haven't mocked out the other network requests; this is something we'll test later on in our dashboard spec.
Note that in our solution we are just intercepting the `POST` request for logging in and mocking out what the expected response would look like. Our dashboard is blank because we haven't mocked out the other network requests; this is something we'll test later on in our dashboard spec.

All we need to worry about is that our URL has updated to the page we expect to view when we are logged in.
</section>
*How can we tell which network requests have and have not been properly stubbed?*

For now, all we are asserting is that our URL has updated to the page we expect to view when we are logged in. To thoroughly test this user flow, we'd also want to assert for all the elements and data we expect to see on the DOM.

### Testing the Sad Path to a Network Request

Expand Down Expand Up @@ -618,3 +627,16 @@ The [documentation](https://docs.cypress.io/api/api/table-of-contents.html){:tar
* What is Cypress and how is it different from other testing frameworks you've used in the past?
* Should you include tests that utilize the API (end-to-end) or should you stub the network requests? Is there an argument for both?
</section>

### Building From Here
Remember, this lesson and it's activities are just an *introduction* to the world of testing with Cypress. We've only scratched the surface. In order to build your knowledge, fluency and skill to the level needed to succeed in Mod 3 and beyond, you will need to spend significant time in the Cypress documentation and getting your hands dirty with practice. In project-based learning, your projects will be your primary platform for learning. The feedback you get from that project work is what will help guide you towards further research and really help you level up your skill.

## Resources

- The official [Cypress Documentation](https://docs.cypress.io/guides/overview/why-cypress)
- Pay particular attention to the following pages in the docs:
- [Best Practices](https://docs.cypress.io/guides/references/best-practices)
- [aliasing](https://docs.cypress.io/guides/core-concepts/variables-and-aliases)
- [waiting](https://docs.cypress.io/guides/guides/network-requests#Waiting)

- Heather's [Cypress Tips & Tricks](https://turingschool.notion.site/Cypress-Tips-Tricks-8565977029cf48faa6003046c148a048?pvs=4)
46 changes: 40 additions & 6 deletions lessons/module-3/react-router-v6.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,11 @@ The App is not fully put together. It has a series of components that will serve

## Installing Router

<section class="answer">
### 1. The first step is installing react router
```bash
npm install react-router-dom
```
</section>

<section class="answer">
### 2. Once you have React Router installed, import your chosen Router

To use React Router, we need to wrap any components that will use a React Router-provided-component in some kind of [Router component](https://reactrouter.com/en/main/router-components/router).
Expand All @@ -114,7 +111,6 @@ root.render(
);

```
</section>

## Rendering the Home component

Expand Down Expand Up @@ -312,7 +308,7 @@ Hmmm...two of those `<Route />` components are looking quite similar. I wonder i
</section>
## Dynamic Routing
In this exercise, we'll explore two ways to achieve dynamic routing in order to obtain an animal and its ID from the route: first, we'll use the `Outlet`, and then we'll show you how to implement a dynamic route without using an outlet.
<section class="answer">
### 8. Let's start by making a dynamic path
Expand Down Expand Up @@ -580,7 +576,11 @@ export default Creatures;
2. Why is the `<Creatures />` component still showing?
3. What would you have to change if you didn't want the `<Creatures />` component to render at this path?
</section>
***Why Use the `Outlet`*** ?
The Outlet component serves as a placeholder for rendering nested route content within a parent component. It's a fundamental tool that allows you to seamlessly integrate child components' content into a parent's layout while maintaining UI coherence.
***Real-World Analogy: Twitter Inbox*** <br/>
Imagine a scenario similar to the Twitter inbox. When you access your inbox, you see a list of message previews on the left side of the screen, but the right side remains blank until you select a specific conversation. This structure is where the Outlet comes into play.
</section>
<section class="answer">
Expand Down Expand Up @@ -612,11 +612,45 @@ export default CreatureDetails;
```
</section>
Now that you know how to use Outlet, let's explore other ways we can achieve dynamic routing without it.
We are going to remove our nested route and define a new separate route for `/:animal/:id` which is not directly nested within the first route `/`. Each route has it's own component.
You would use this approach when you have distinct pages or components that should be displayed separately based on the URL.
<section class="answer">
```jsx
import './App.css';
import { Routes, Route, NavLink } from 'react-router-dom';
import Home from '../Home/Home';
import Creatures from '../Creatures/Creatures';
import CreatureDetails from '../CreatureDetails/CreatureDetails';

function App() {
return (
<main className="App">
<nav>
<NavLink to="/puppies" className="nav">Puppies</NavLink>
<NavLink to="/sharks" className="nav">Sharks</NavLink>
</nav>
<h1>Puppies or Sharks?</h1>
<Routes>
<Route path="/" element={<Home />}/>
<Route path="/:animal/:id" element={<Creatures />}>
</Routes>
</main>
);
}

export default App;

```
Now it's time to remove `Outlet` from our `Creature.js` file since we don't have nested routes and we don't need `Outlet` anymore
</section>
<section class="call-to-action">
### Final Reflections
1. Why use Router?
3. Describe the following:
2. Describe the following:
- `Route`
- `Routes`
- `Link`
Expand Down
2 changes: 1 addition & 1 deletion projects/module-1/ideabox-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ You will work through the iterations listed under **Progression** below.
### Design Resources

For each iteration, you should be matching the provided design comps closely. ([What is a design comp?](https://clients.geminoscreative.com/marketing-blog/what-is-a-design-comp)) Act like you're on the job and these are the designs you've been given to match. Details and spacing matter! Here is some info to help you:
- Font: [Poppins](https://fonts.google.com/specimen/Poppins?query=poppins)
- Font: [Poppins](https://fonts.google.com/specimen/Poppins?query=poppins) - Note that this font may appear slightly different from the one shown in the provided comp
- Icons: [Found here](https://drive.google.com/drive/folders/18xpWplI0tpXIK1omBZeq04LEx2OMzzMK?usp=sharing) (Note: You will not use all of the icons in this folder. Add these icons to an `assets` folder in your repository.)
- Colors:
- Dark Purple: `#1F1F3C`
Expand Down
Loading

0 comments on commit 812df2c

Please sign in to comment.