diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..031aa104 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "workbench.colorCustomizations": { + "activityBar.background": "#0D3507", + "titleBar.activeBackground": "#124A0A", + "titleBar.activeForeground": "#F3FDF1" + } +} \ No newline at end of file diff --git a/README.md b/README.md index 06fd745b..8149699b 100644 --- a/README.md +++ b/README.md @@ -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. @@ -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. \ No newline at end of file diff --git a/src/api/fetchShow.js b/src/api/fetchShow.js index ab70e5bc..05408b3c 100644 --- a/src/api/fetchShow.js +++ b/src/api/fetchShow.js @@ -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, diff --git a/src/components/Show.js b/src/components/Show.js index 1cd25f06..a4a00b6c 100644 --- a/src/components/Show.js +++ b/src/components/Show.js @@ -13,7 +13,7 @@ const Show = (props) => {

{show.summary}


- { show.seasons.map(season=>{ diff --git a/src/components/tests/Display.test.js b/src/components/tests/Display.test.js index 5a01416b..79729657 100644 --- a/src/components/tests/Display.test.js +++ b/src/components/tests/Display.test.js @@ -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(); + 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(); + 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() + //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(); + }); +}); diff --git a/src/components/tests/Episode.test.js b/src/components/tests/Episode.test.js index 24b4c2dc..aa86aa78 100644 --- a/src/components/tests/Episode.test.js +++ b/src/components/tests/Episode.test.js @@ -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() }); +//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() + + //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(); + //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'. \ No newline at end of file diff --git a/src/components/tests/Show.test.js b/src/components/tests/Show.test.js index 5d030167..2b333b52 100644 --- a/src/components/tests/Show.test.js +++ b/src/components/tests/Show.test.js @@ -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(); }); + +//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(); + //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(); + //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(); + 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(); + //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(); + //Act + let episodeDiv = document.getElementsByClassName("episode"); + //Assert + expect(episodeDiv.length).toBe(0); + + //Arrange + rerender()//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. \ No newline at end of file + + + + +