0

I have a component Student component as follows

import axios from 'axios';
import React from 'react';
import { useEffect, useState } from 'react';

function Student(props) {
  const [studentRecord, setStudentRecord] = useState(props.stRecord);
  const [studentSubjects, setStudentSubjects] = useState(null);
  function getStudentSubjects() {
    let apicalladdress = '/studentapi/GetStudentSubjects/' + studentRecord.studentNumber;
    axios.get(apicalladdress).then((result) => {
      setStudentSubjects(result.data);
    });
  }
  useEffect(() => {
    getStudentSubjects();
  }, [studentRecord]);

  return (
    <div>
      <div>{studentRecord.studentNumber}</div>
      <div>{setStudentSubjects[0].subjectName}</div>
    </div>
  );
}

I have a test created as below

import {StudentSubjectsData} from "../globalDataProvider";
import AxiosMock from "axios"

it("make sure student renders",async ()=>{
  const mockStudentSubjects=await Promise.resolve({data: StudentSubjectsData()});
  AxiosMock.get.mockResolvedValue(mockStudentSubjects);
  
  render (<Student stRecord={StudentRecord}/>);
}

But I am getting following errors

Error 1. An update to Student component inside a test was not wrapped in act(...) for line :setStudentSubjects(result.data);

Error 2. For following print line, I am getting error TypeError: Cannot read properties of undefined (reading subjectName)

<div>{setStudentSubjects[0].subjectName}</div>

Any suggestions please...

Lin Du
  • 88,126
  • 95
  • 281
  • 483
V R
  • 133
  • 1
  • 8

1 Answers1

0

I didn't see how you mock the axios.get() method, I will use jest.spyOn() to mock it.

For the second error, the studentSubjects state is null for the first render. It's better to give an empty array instead of null as its initial value. Besides, you can use optional chain to access the value.

Student.tsx:

import axios from 'axios';
import React from 'react';
import { useEffect, useState } from 'react';

export function Student(props) {
  const [studentRecord, setStudentRecord] = useState(props.stRecord);
  const [studentSubjects, setStudentSubjects] = useState<{ subjectName: string }[]>([]);
  function getStudentSubjects() {
    let apicalladdress = '/studentapi/GetStudentSubjects/' + studentRecord.studentNumber;
    axios.get(apicalladdress).then((result) => {
      setStudentSubjects(result.data);
    });
  }
  useEffect(() => {
    getStudentSubjects();
  }, [studentRecord]);

  return (
    <div>
      <div>{studentRecord.studentNumber}</div>
      <div>{studentSubjects[0]?.subjectName}</div>
    </div>
  );
}

Student.test.tsx:

import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import axios from 'axios';
import React from 'react';
import { Student } from './Student';

describe('75502126', () => {
  test('should pass', async () => {
    const axioGetSpy = jest.spyOn(axios, 'get').mockResolvedValue({ data: [{ subjectName: 'a' }] });
    render(<Student stRecord={{ studentNumber: 1 }} />);
    expect(await screen.findByText('a')).toBeInTheDocument();
    axioGetSpy.mockRestore();
  });
});

Test result:

 PASS  stackoverflow/75502126/Student.test.tsx (8.98 s)
  75502126
    ✓ should pass (34 ms)

-------------|---------|----------|---------|---------|-------------------
File         | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------|---------|----------|---------|---------|-------------------
All files    |     100 |      100 |     100 |     100 |                   
 Student.tsx |     100 |      100 |     100 |     100 |                   
-------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        9.508 s
Lin Du
  • 88,126
  • 95
  • 281
  • 483
  • Thank you Lin Du, for pointing out the solution. I have accepted your answer. You have clarified on couple of things which I wanted. Only thing in the same issue I am having is I am still getting a message for this line "setStudentSubjects(result.data);" which says "when testing, code that causes react state update should be wrappered into act(...) ". Any suggestions here please.... – V R Feb 20 '23 at 13:56