Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rick Mansfield's Pull/push Trail for U3.3 M1 Testing React #65

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"workbench.colorCustomizations": {
"activityBar.background": "#0D3507",
"titleBar.activeBackground": "#124A0A",
"titleBar.activeForeground": "#F3FDF1"
}
}
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

This module explored passing props into test components, rerendering components and using mocks to both monitor functional props and override the functionality of external modules. In this project, you will practice each of these practices in the testing of an application that displays TV show data.

- [Unit Testing React Module Project: Stranger Things](#unit-testing-react-module-project-stranger-things)
- [Objectives](#objectives)
- [Introduction](#introduction)
- [Instructions](#instructions)
- [Task 1: Project Set Up](#task-1-project-set-up)
- [Task 2: Project Requirements](#task-2-project-requirements)
- [The Episode Component](#the-episode-component)
- [The Show Component](#the-show-component)
- [The Display Component](#the-display-component)
- [Stretch goals](#stretch-goals)
- [Rick Mansfield's Pull/push trail for Project Testing React](#rick-mansfields-pullpush-trail-for-project-testing-react)
- [class Questions](#class-questions)
- [Questions to ask yourself to create good Tests](#questions-to-ask-yourself-to-create-good-tests)
- [What are some Possible unit Tests for MissionFrom.js?](#what-are-some-possible-unit-tests-for-missionfromjs)
- [Arrange Act Assert](#arrange-act-assert)

## Objectives
- Understand how to test the effects of passing specific props into a component
- Understand how to monitor the behavior of functional mock props.
Expand Down Expand Up @@ -60,3 +76,43 @@ Get the project fired up and start using it as a user would. Try to go through t
- Look up the `TVMaze` API. Add a dropdown with the titles of some other popular shows. Add the user sequence of choosing a different show to fetch data for different shows.

- Add React Router, and add the functionality to click an episode and navigate to an episode page.

## Rick Mansfield's Pull/push trail for Project Testing React

- [Link for convenience](https://github.com/LambdaSchool/web-module-project-testing-react/pull/65)

## class Questions
1. **What is end to end testing?**
1. End-to-end testing is a technique that tests the entire software product from beginning to end to ensure the application flow behaves as expected. It defines the product’s system dependencies and ensures all integrated pieces work together as expected. The main purpose of End-to-end (E2E) testing is to test from the end user’s experience by simulating the real user scenario and validating the system under test and its components for integration and data integrity. End-To-End (E2E) testing is a technique used to test an entire flow as if we were an actual user by simulating their actions (clicks, pressing certain keys, typing into a field, etc).
2. Simulates a user Clicking through a site
3. evaluates Entrie Applications
4. **_Cypress_**

2. **What is integration Testing , and whay is it used?** [TestingXperts](https://www.testingxperts.com/blog/what-is-integration-testing)
1. What it is = Integration testing is one of the agile methodologies of software testing where individual components or units of code are tested to validate interactions among different software system modules. In this process, these system components are either tested as a single group or organized iteratively.
2. Why used = to validate the performance of the entire software system as a whole.
3. Verify several components work together
4. Evaluates Application Systems
5. **_React-Testing-Library_**

3. **Unit Tests**
1. Test Individual Functions/components
2. Evaluates Small Units of Code (not UI)
3. **_Jest_**
## Questions to ask yourself to create good Tests
1. Does the component render by default without errors?
2. How does the component changed depending on the props passed in?
3. Does the component respond to user input?
4. Does the compnent respont o state change (async calls / redux)?
5. Does the component have error states?

## What are some Possible unit Tests for MissionFrom.js?
1. Does MissionForm Render Correctly without errors
2. Does it render the message "We are fetching data" correctly when isFetchingData is True?
3. Does the button render correctly when isfetchingData is false?
4. Does it correctly call props.getData() when button is clicked?

## Arrange Act Assert
1. Arrange: Setup the react components to be tested.
2. Act: Execute the behaviour (if there is one) and extract what is being tested.
3. Assert: Check to see if the expected responses occur.
4 changes: 2 additions & 2 deletions src/api/fetchShow.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ const formatSeasons = (allEpisodes) => {

const fetchShow = () => {
return axios
.get("https://api.tvmaze.com/singlesearch/shows?q=stranger-things&embed=episodes")
.get("https://api.tvmaze.com/singlesearch/shows?q=stranger+things&embed=episodes")
.then(res => {
const { data } = res;

console.log('FETSH SHOW DATA',data);
return {
name: data.name,
image: data.image,
Expand Down
2 changes: 1 addition & 1 deletion src/components/Show.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const Show = (props) => {
<p>{show.summary}</p>

<label htmlFor="seasons">Select A Season</label><br/>
<select onChange={handleSelect} name="seasons" id="seasons">
<select onChange={handleSelect} name="seasons" id="seasons" data-testid="seasons">
<option value="none"></option>
{
show.seasons.map(season=>{
Expand Down
74 changes: 69 additions & 5 deletions src/components/tests/Display.test.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,79 @@
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Display from './../Display';
// mockFetchShow is used in the last 2 tests, where it is called indirectly
import mockFetchShow from '../../api/fetchShow';
jest.mock('../../api/fetchShow');

//3. Rebuild or copy a show test data element as used in the previous set of tests.
const testShow = {
//add in approprate test data structure here.
name: "Test Show",
image:{
medium: "https://static.tvmaze.com/uploads/images/medium_portrait/200/501942.jpg",
original: "https://static.tvmaze.com/uploads/images/original_untouched/200/501942.jpg"
},
seasons: [{id: 0, name: "Test Season 1", episodes: []},
{id: 1, name: "Test Season 2", episodes: [{
//Add in approprate test data structure here.
id:1,
name: "",
image: null,
season: 1,
number: 1,
summary: "Text to test if correct content is passed.",
runtime: 1
}]},
{id: 2, name: "Test Season 3", episodes: []}],
summary: "Test summary text. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nisi pariatur ratione quos itaque, tempore dolore iste aut veritatis provident dolorem debitis, amet accusamus, quam adipisci distinctio quod eligendi similique ipsum!"
}
//2. Test that the Display component renders without any passed in props.
test('Display component renders without any passed in props', ()=>{
render(<Display />);
const imageSelector = screen.queryByAltText("header image");
expect(imageSelector).toBeInTheDocument();
});
//4. Test that when the fetch button is pressed, the show component will display. Make sure to account for the api call and change of state in building your test.

test('when the fetch button is pressed, the show component will display with correct # of seasons', async ()=>{
// Arrange
render(<Display />);
mockFetchShow.mockResolvedValueOnce(testShow);
// Act
const button = screen.getByRole("button");
userEvent.click(button);
// Assert the show-container div displays
await waitFor(()=> {
const showContainer = screen.getByTestId("show-container");
expect(showContainer).toBeInTheDocument();
});
//5. Test that when the fetch button is pressed, the amount of select options rendered is equal to the amount of seasons in your test data.
// Assert number of seasons equal to test data (3)
const seasonOptions = screen.getAllByTestId("season-option");
expect(seasonOptions).toHaveLength(3);

});

test("calls displayFunc when button is clicked", async ()=>{
mockFetchShow.mockResolvedValue(testShow);
const mockDisplayFunc = jest.fn();

//Arrange: renders component
render(<Display displayFunc={mockDisplayFunc}/>)

//Act: Click button
const button = screen.getByRole("button");
userEvent.click(button);






// //Assert: ?
await waitFor(()=>{
expect(mockDisplayFunc.mock.calls.length === 1).toBeTruthy();
expect(mockDisplayFunc.mock.calls.length).toBe(1);
expect(mockDisplayFunc.mock.calls).toHaveLength(1);
expect(mockDisplayFunc).toHaveBeenCalled();
});
});



Expand Down
38 changes: 30 additions & 8 deletions src/components/tests/Episode.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,49 @@ const testEpisode = {
image: "http://static.tvmaze.com/uploads/images/medium_landscape/67/168918.jpg",
season: 1,
number: 1,
summary: "",
summary: "Test for Passing Text Correctly",
runtime: 1
}

const testEpisodeWithoutImage = {
//Add in approprate test data structure here.
id:1,
name: "",
image: null,
season: 1,
number: 1,
summary: "",
runtime: 1
}

//1. Complete a test that shows the Episode component renders. Pass in the provided example episode data as a test prop.
test("renders without error", () => {

render(<Episode episode={testEpisode}/>)
});

//2. Modify the test data to display a specific summary statement. Complete a test that shows that the summary value passed in to the Episode component displays as expected. Use no more then 3 different expect statements to test the the existance of the summary value.
test("renders the summury test passed as prop", ()=>{

//Arrange
//Also See Above //Add in appropriate test data to testEpisode summary
render(<Episode episode={testEpisode}/>)

//Act (Const's to find data)
const summary = screen.queryByText(/Test for Passing Text Correctly/i);
//Assert
expect(summary).toHaveTextContent(/Test for Passing Text Correctly/i);
expect(summary).toBeTruthy();
expect(summary).toBeInTheDocument();
});


//3. The episode component displays a default value ('./stranger_things.png') when a image url is not provided. Create a new piece of test data with the image property set to null. Test that the alt tag of the image displayed is set to './stranger_things.png'.
test("renders default image when image is not defined", ()=>{
//Arrange (render)
render(<Episode episode={testEpisodeWithoutImage}/>);
//Action (const/screen)
const image = screen.getByAltText("./stranger_things.png");
//Assert (expect)
expect(image).toBeInTheDocument();
expect(image).toBeTruthy();

})

//Tasks
//1. Complete a test that shows the Episode component renders. Pass in the provided example episode data as a test prop.
//2. Modify the test data to display a specific summary statement. Complete a test that shows that the summary value passed in to the Episode component displays as expected. Use no more then 3 different expect statements to test the the existance of the summary value.
//3. The episode component displays a default value ('./stranger_things.png') when a image url is not provided. Create a new piece of test data with the image property set to null. Test that the alt tag of the image displayed is set to './stranger_things.png'.
94 changes: 84 additions & 10 deletions src/components/tests/Show.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,104 @@ import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import Show from './../Show';

//1. Build an example data structure that contains the show data in the correct format. A show should contain a name, a summary and an array of seasons, each with a id, name and (empty) list of episodes within them. Use console.logs within the client code if you need to to verify the structure of show data.
//NOTE NOTE NOTE I had to console.log('FETSH SHOW DATA',data); on line 29 of fetchShow.js to get the proper structure. I started by mimicking the format from lines 24-37 of fetchShow.js and expanding that to inclue the data I found on the console.log
const testShow = {
//add in approprate test data structure here.

image: {
medium: "https://static.tvmaze.com/uploads/images/medium_portrait/200/501942.jpg",
original: "https://static.tvmaze.com/uploads/images/original_untouched/200/501942.jpg"
},//I retrieved this image data from the chrome console from the res data
name: "Test Show",
summary: "Test Summary blah blah blah",
//note seasons is from fetchShow.js line 34 seasons: formatSeasons(data._embedded.episodes). Which is becuase the res data returns _embedded as episodes: Array
seasons: [
{ id: 0, name: "Test Season 1", episodes: [] },
{ id: 1, name: "Tet Season 2", episodes: [] },
{ id: 2, name: "Test Season 3", episodes: [] },
{
id: 3, name: "Test Season 4", episodes: [{
id: 3,
image: null,
name: "",
number: 3,
runtime: 3,
season: 3,
summary: "Text to test if passed or not"
}]
}],//the res data has more to it but this is all our app is useing. I put it in the same order as the chrome console.log of the response data just as can see it there on in postman.
}

test('renders testShow and no selected Season without errors', ()=>{

//2. Test that the Show component renders when your test data is passed in through show and "none" is passed in through selectedSeason.
test('renders testShow and no selected Season without errors', () => {
render(<Show show={testShow} selectedSeason="none" />);
});


//3. Test that the Loading component displays when null is passed into the show prop (look at the Loading component to see how to test for it's existance)
test('renders Loading component when prop show is null', () => {
//Arrange
render(<Show show={null} selectedSeason="none" />);
//Act
const loadingComponent = screen.getByTestId("loading-container");
//Assert
expect(loadingComponent).toBeInTheDocument();
expect(loadingComponent).toBeTruthy();
expect(loadingComponent).toHaveTextContent(/fetching data.../i);

});


//4. Test that when your test data is passed through the show prop, the same number of season select options appears as there are seasons in your test data.
test('renders same number of options seasons are passed in', () => {
//Arrange - render
render(<Show show={testShow} selectedSeason="none" />);
//Act - const/screen
const seasonSelection = screen.getAllByTestId("season-option");//found in Show.js
//Assert - expect
expect(seasonSelection.length).toBe(4);
expect(seasonSelection.length === 4).toBeTruthy();
});

test('renders same number of options seasons are passed in', ()=>{
//My Own extra test out of curiosity...
test('Episode component is not loaded when no season is selected', () => {
render(<Show show={testShow} selectedSeason="none" />);
const theEpisodeDiv = document.getElementsByClassName("episode");
expect(theEpisodeDiv.length).toBe(0);
});

//5. Test that when an item is selected, the handleSelect function is called. Look at your code to see how to get access to the select Dom element and userEvent reference materials to see how to trigger a selection.
test('handleSelect is called when an season is selected', () => {
//Arrange - render - becomes a mock function as the prop this time.
const mockHandleSelect = jest.fn(() => { return ("TEST") });
render(<Show show={testShow} selectedSeason="3" handleSelect={mockHandleSelect} />);
//Act - const/screen - could pick anything. Tried Season 3.
const season3Option = screen.getByTestId("seasons");//had to add data-testid="seasons" to Show.js line 16
//Assert - expect
userEvent.selectOptions(season3Option, [2]);
});

//6. Test that the episode component DOES NOT render when the selectedSeason props is "none" and DOES render the episode component when the selectedSeason prop has a valid season index.
test('component renders when no seasons are selected and when rerenders with a season passed in', () => {
//Arrange
const { rerender } = render(<Show show={testShow} selectedSeason="none" />);
//Act
let episodeDiv = document.getElementsByClassName("episode");
//Assert
expect(episodeDiv.length).toBe(0);

//Arrange
rerender(<Show show={testShow} selectedSeason={3} />)//remember above I selected season 3
//Act
episodeDiv = document.getElementsByClassName("episode");//already defined above useing let
//Assert
expect(episodeDiv.length).toBe(1);
});

//Tasks:
//1. Build an example data structure that contains the show data in the correct format. A show should contain a name, a summary and an array of seasons, each with a id, name and (empty) list of episodes within them. Use console.logs within the client code if you need to to verify the structure of show data.
//2. Test that the Show component renders when your test data is passed in through show and "none" is passed in through selectedSeason.
//3. Test that the Loading component displays when null is passed into the show prop (look at the Loading component to see how to test for it's existance)
//4. Test that when your test data is passed through the show prop, the same number of season select options appears as there are seasons in your test data.
//5. Test that when an item is selected, the handleSelect function is called. Look at your code to see how to get access to the select Dom element and userEvent reference materials to see how to trigger a selection.
//6. Test that the episode component DOES NOT render when the selectedSeason props is "none" and DOES render the episode component when the selectedSeason prop has a valid season index.