Search code examples
reactjsreact-bootstrap

How to dynamically set values of a component and test them


I have created a register component using react-bootstrap. It has email, password and submit button fields in a form. At the end, it has an Alert component which should not be visible initially but should show success/failure once the form has been submitted

import React from 'react';
import {Col, Row, Container, Card,Button, Alert} from 'react-bootstrap'
import Form from 'react-bootstrap/Form';
import { useState } from 'react';
import User from '../models/user';

let Register = () => {

    let [state,setState] = useState(new User('',''));

    let submitresponse='';
    let alertvariant='';

    let updateInput = (e) =>{
        setState({
                ...state, //state defined above in useState call. Expand the current state and then override the propoerty which target represents
                [e.target.name] : e.target.value
        })
    }

    let register = (e) =>{
        e.preventDefault();
        console.log(`registerclick: ${JSON.stringify(state)}`)

        fetch(process.env.REACT_APP_REGISTER_USER_URL,{
            method: 'POST',
            headers:{
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(state)
            }) //move to separate funcion in separate file to make it easy to test and reuse?
            .then((res) => {
                console.log(`got response: ${JSON.stringify(res)}`);
                return res.json();  //return json from res
            })
            .then((data) => { //data is the json returned previously. Promise chaining
                console.log(`data after register user request: ${JSON.stringify(data)}`);  
                if(data.result == "success") {
                    setState(new User(data.user,data.email)) //override previous value of data object with value of received json object. 
                    this.submitresponse = "User Registered"
                } else {
                    setState(new User('','')) //override previous value of data object with value of received json object. 
                    this.submitresponse = "User Couldn't be Registered"
                }     
            });
    }

    return (
        <>
            <Container className='mt-3'>
                <Row>
                    <Col xs={3}>
                        <Card className="shadow-lg">
                            <Card.Header className='p-3'>
                                 Register
                            </Card.Header>
                            <Card.Body>
                                <Form>
                                    <Form.Group className="mb-3">
                                        <Form.Control name="email" onChange={updateInput} type="text" placeholder="email" aria-label="aria-email" />
                                    </Form.Group>
                                    <Form.Group className="mb-3">    
                                        <Form.Control name="password" onChange={updateInput} type="password" placeholder="password" aria-label="aria-password" />
                                    </Form.Group>                                    
                                    <Form.Group className="mb-3">    
                                        <Button onClick={register} type="submit" name="submit-button" aria-label="aria-submit">Register Button</Button>
                                    </Form.Group>
                                    <Form.Group className="mb-3">    
                                        <Alert name="submit-response-alert" key={this.alertvariant} variant={this.alertvariant} >{this.submitresponse}</Alert>
                                    </Form.Group>
                                </Form>
                            </Card.Body>
                        </Card>
                    </Col>
                </Row>
            </Container>
            
        </>
    )
}

export default Register;

How could I

  1. Hide the Alert initially? What is the way to dynamically set display:none for example
  2. Make it visible when server response is received?

In the tests, I want to test

  1. Alert shouldn't be in document initially

    it('Should not show Alert field', async () => { render(); expect(screen.getByName("submit-response-alert")).not.toBeInTheDocument(); //Is this the right way? });

  2. Once server response is received (mocked), Alert should be visible with right message

    it('Should successfully submit the form', async () => { const { getByText } = render();

     await act(async () => {
       fireEvent.click(getByText("Register Button"))
     })  
     expect(screen.getByName("submit-response-alert")).toBeInTheDocument();
    

    //how to test that the Alert has the right message });


Solution

  • set a state that tracks the progress of the request You can also add a message to it.

    const [requestState , setRequestState] = useState({completed:false , message:""})
    

    add this condition into jsx

    {requestState.completed && <Alert name="submit-response-alert" key={this.alertvariant} variant={this.alertvariant} >{this.submitresponse}</Alert>}