Skip to content

Rick Mansfield's Push/Pull trail for Testing Web Apps Project #71

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

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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": "#142F4C",
"titleBar.activeBackground": "#1B426A",
"titleBar.activeForeground": "#F8FAFD"
}
}
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

This module explored the basics of the react-testing library and ideas behind the integration testing methodology. In this project you will practice how to build tests that follow the arrange-act-assert model, different methods of querying for DOM elements in a test, the use of different expect types and using async/await to test for changes in state.

- [Integration Testing React Module Project : Contact Form - Testing](#integration-testing-react-module-project--contact-form---testing)
- [Testing Web Applications](#testing-web-applications)
- [Objectives](#objectives)
- [Introduction](#introduction)
- [Instructions](#instructions)
- [Task 1: Project Set Up](#task-1-project-set-up)
- [Task 2: Project Requirements](#task-2-project-requirements)
- [Test Brainstorming](#test-brainstorming)
- [Complete a case that tests if:](#complete-a-case-that-tests-if)
- [Stretch goals](#stretch-goals)
- [Rick Mansfield's PUll Request Link](#rick-mansfields-pull-request-link)
- [Resources](#resources)

## Testing Web Applications

## Objectives
Expand Down Expand Up @@ -56,3 +69,13 @@ As a developer, you will be writing tests for every component. As we've learned,
- Look at your test cases in Understanding-questions and see if there are any that you have not completed.
- From the this list or from your own mind, add in at least one more new testcase.
- There is alot of state management within our component in this project! See if you can separate the form and error validation code into their own hooks.


## Rick Mansfield's PUll Request Link

- [Link for Convenience](https://github.com/LambdaSchool/web-module-project-testing-web-apps/pull/71)

## Resources
- [React Testing Library Cheatsheet](https://testing-library.com/docs/react-testing-library/cheatsheet/)
- [Regex](https://regexr.com)
- [jest](https://jestjs.io/docs/en/expect.html)
42 changes: 42 additions & 0 deletions notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
this file contains notes from the video regarding options on waiting for a promist to be completed. Use the preview for an easier read.
```javascript
test("User can add multiple animals", async () => {
// Arrange: render & grab the elements we need
render(<AnimalForm />);

const speciesInput = screen.getByLabelText(/species/i);
const ageInput = screen.getByLabelText(/age/i);
const notesInput = screen.getByLabelText(/notes/i);
const submitButton = screen.getByRole('button', { name: /submit/i });

// Act: fill out the form and click the button (simulating user behavior with userEvent)
userEvent.type(speciesInput, "Deer");
userEvent.type(ageInput, "98");
userEvent.type(notesInput, "I'm the first animal and I love 98 Degrees");
userEvent.click(submitButton);

// Intermediate assertion: now we should have just deer, no llamas
expect(screen.getByText(/deer/i)).toBeInTheDocument();
expect(screen.queryByText(/llama/i)).toEqual(null);

//async assertion:

// if you are changing state you may want to "wait" for the change... such as a change handler
//THE PROMISE WAY ...
// const newItemPromise = screen.findByText("deer");
// console.log(newItemPromise);
// newItemPromise.then(newItem=>{
// console.log(newItem);
// expect(newItem).toBeInTheDocument();
// });

//THE AWAIT WAY
// 1)
// const newItem = await screen.findByText("deer");//did you put "async" in first line?
// console.log(newItem);
// 2)
await waitFor(() => {
const newItem = screen.findByText("deer");
expect(newItem).toBeInTheDocument();
});
```
151 changes: 134 additions & 17 deletions src/components/ContactForm.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,155 @@ import userEvent from '@testing-library/user-event';

import ContactForm from './ContactForm';

test('renders without errors', ()=>{

test("does the test 1", ()=>{
// throw new Error("This is an error")
console.log('doing a sanity test 1');
});

test('renders the contact form header', ()=> {


it('renders without errors', ()=>{
render(<ContactForm />);
});

test('renders ONE error message if user enters less then 5 characters into firstname.', async () => {

test('2 renders the contact form header', ()=> {
render(<ContactForm />);
const header = screen.queryByText(/contact form/i);
console.log(header);
expect(header).toBeInTheDocument();//can use either
expect(header).toBeVisible();//can use any of these
expect(header).toHaveTextContent(/contact form/i);
expect(header).toBeTruthy();
expect(header).not.toBeFalsy();
//another example to just have plenty of options
const h1 = screen.queryByTestId('testh1');
expect(h1).toBeInTheDocument();//can also tag with an id and use any of these
});

test('renders THREE error messages if user enters no values into any fields.', async () => {


test('3 renders ONE error message if user enters less then 5 characters into firstname.', async () => {
render(<ContactForm />);
const firstName = "Ric";
const firstNameInput = screen.getByLabelText(/first name/i);
userEvent.type(firstNameInput, firstName);
const errorMessage = screen.queryAllByText(/error/i);
expect(errorMessage).toHaveLength(1);
expect(errorMessage).toBeTruthy();//same thing
});

test('renders ONE error message if user enters a valid first name and last name but no email.', async () => {


test('4 renders THREE error messages if user enters no values into any fields.', async () => {
render(<ContactForm />);
const submitButton = screen.getByRole('button');//arrange
userEvent.click(submitButton);
const errorMessages = screen.queryAllByTestId(/error/i);
expect(errorMessages).toHaveLength(3);

});

test('renders "email must be a valid email address" if an invalid email is entered', async () => {

test('5 renders ONE error message if user enters a valid first name and last name but no email.', async () => {
render(<ContactForm />);
//enters first name
const firstName = "Ricster";
const firstNameInput = screen.getByLabelText(/first name/i);
userEvent.type(firstNameInput, firstName);
//enters last name
const lastName = "Mansfield";
const lastNameInput = screen.getByLabelText(/Last Name/i);
userEvent.type(lastNameInput, lastName);
//uses submit button before entering email
const button = screen.getByRole('button');
userEvent.click(button);
//should see error for email
const errorMessages = screen.queryAllByText(/error/i);
expect(errorMessages).toHaveLength(1);
//alternative check for email error message using preestablished variable from test 4
const emailErrorMessage = screen.queryAllByTestId(/error/i);
expect(emailErrorMessage).toHaveLength(1);

});

test('renders "lastName is a required field" if an last name is not entered and the submit button is clicked', async () => {

test('6 renders "email must be a valid email address" if an invalid email is entered', async () => {
render(<ContactForm />);
//Arrange = create bad email and retrieve email input field
const email = 'badEmail';
const emailInput = screen.getByLabelText(/email/i);
//Act = input bad email into field just like a user might do & use submitt button
userEvent.type(emailInput, email);
const submitButton = screen.getByRole('button');//arrange
userEvent.click(submitButton);
//Assert = expect to get error message for email
const errorMessage = screen.queryByText(/email must be a valid email address/i);
expect(errorMessage).toBeVisible();

});

test('renders all firstName, lastName and email text when submitted. Does NOT render message if message is not submitted.', async () => {
test('7 renders "lastName is a required field" if an last name is not entered and the submit button is clicked', async () => {
render(<ContactForm />);
//ARRANGE - The message prints upon using submit without doing anything So We only need to screen for the button
const submitButton = screen.getByRole('button');
//ACT - user then clicks the button
userEvent.click(submitButton);
//ASSERT - error message for last name is expected
const errorMessage = screen.queryByText(/lastName is a required field/i);
expect(errorMessage).toBeVisible();

});

test('renders all fields text when all fields are submitted.', async () => {
test('8 renders all firstName, lastName and email text when submitted. Does NOT render message if message is not submitted.', async () => {

render(<ContactForm />);
//Arrange Need good first, last and email and screen for each field
const firstName = 'William';
const lastName = 'Mansfield';
const email = 'RicksMyCodeGuy@gmail.com';

const firstNameInput = screen.getByLabelText(/first name/i);
const lastNameInput = screen.getByLabelText(/Last Name/i);
const emailInput = screen.getByLabelText(/email/i);
//Act user inputs each and clicks submit button no message until after clicked
userEvent.type(firstNameInput, firstName);
userEvent.type(lastNameInput, lastName);
userEvent.type(emailInput, email);

const messageDiv = screen.queryByText(/you submitted/i);
expect(messageDiv).toBeFalsy();//starts falsy

const button = screen.getByRole('button');
userEvent.click(button);
//Assert - should get affimative You Submitted: card back with all details rendered back
// expect(messageDiv).toBeTruthy();//ends truthy couldn't get this to work. seeing help

const firstNameDisplay = screen.queryByTestId('firstnameDisplay');
const lastNameDisplay = screen.queryByTestId('lastnameDisplay');
const emailDisplay = screen.queryByTestId('emailDisplay');

expect(firstNameDisplay).toBeVisible();
expect(lastNameDisplay).toBeVisible();
expect(emailDisplay).toBeVisible();

test('9 renders all fields text when all fields are submitted.', async () => {
render(<ContactForm />);
//Arranged need good first, last, email, scan for each field
const firstName = 'Wiliam';
const lastName = 'Mansfield';
const email = 'RicksMyCodeGuy@gmail.com';

const firstNameInput = screen.getByLabelText(/first name/i);
const lastNameInput = screen.getByLabelText(/last name/i);
const emailInput = screen.getByLabelText(/email/i);

//ACT - user enters each as arranged above and uses submit button
userEvent.type(firstNameInput, firstName);
userEvent.type(lastNameInput, lastName);
userEvent.type(emailInput, email);

const button = screen.getByRole('button');
userEvent.click(button);

//Assert - must utilize a delay method | Per Warrens video the "Await" vs the "Promise" is shorter. I've included the notes from class an an extra file called notes.md attached next to the readme.md file.
const firstNameDisplay = await screen.findByTestId('firstnameDisplay');

});
expect(firstNameDisplay).toBeVisible();
expect(screen.getByText(/mansfield/i)).toBeTruthy();
screen.getByText(/mansfield/i);
});