0

我想测试 React App 功能

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

function App () {
    
    const [message, setMessage] = useState('')
    
    useEffect(() => {
           async function getMessage () {
             const url = process.env.REACT_APP_BACKEND_URL  +"/helloworld" 
                console.log(url)
                try { 
                      const headers = new Headers()
                            headers.append('Access-Control-Allow-Origin','*')
                      console.log(headers.get('Access-Control-Allow-Origin'))
                      const response = await fetch(url, { 
                                       mode: 'cors',
                                       headers: {'Access-Control-Allow-Origin':'*'}
                                                        }
                                                   )
                      console.log(response.status)
                      console.log(response)
                      const text = await response.text()
                      console.log(text)
                       setMessage(text)
                    } catch(error){
                          console.log('fetch error')
                          console.error('There has been a problem with', error);
                    }
         }
  getMessage()
}, [])
    return ( <div>{message}</div>)
 }

export default  App ;

与喷气机测试

import React from 'react'
import App from './App' 
import {render,screen} from '@testing-library/react'

it('should display hello world', async () => {
     render(<App />);
     const linkElement = await screen.getByText('Hello World')
     expect(linkElement).toBeInTheDocument()
 })

调用的 fetch 使用 Mock Service Worker Handler 进行模拟

import { rest } from 'msw'

export const handlers = [
  rest.get(process.env.REACT_APP_BACKEND_URL+"/helloworld" , (reg, res, ctx ) => {
         console.log('mock get')
         console.log(process.env.REACT_APP_BACKEND_URL)
        return res(
           ctx.status(200),
           ctx.text("Hello World"),
           ctx.set({
                     'Access-Control-Allow-Origin':'*',
                     'Content-type':'text/plain'
                   })
    )
})
]

使用服务器

// src/mocks/server.js
import { setupServer } from 'msw/node'
import { handlers } from './handlers'

// This configures a request mocking server with the given request handlers.
export const server = setupServer(...handlers)

服务器在文件 setUpTestJs 中设置

import '@testing-library/jest-dom'
import { server } from './mocks/server.js'

beforeAll(() => {  console.log("befor all server listen")
                   server.listen()
                }
          )
afterEach(() => {   console.log("after each server reset handlers ")
                    server.resetHandlers()
                }
         )
// Clean up after the tests are finished.
afterAll(() => {  console.log("after all  server closed")
                  server.close()
               }
         )

index.js 看起来像这样

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

if (process.env.REACT_APP_USE_MSW_MOCK_API === 'yes') { // eslint-disable-line
  const { worker } = require('./mocks/worker'); // eslint-disable-line
  worker.start();
  console.log("worker started")
}

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

package.json 看起来像这样

{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.12.0",
    "@testing-library/react": "^11.2.7",
    "dotenv": "^10.0.0",
    "eslint-plugin-jest": "^24.3.6",
    "npm": "^7.24.2",
    "react": "^17.0.0",
    "react-async": "^10.0.1",
    "react-dom": "^17.0.0",
    "react-scripts": "^5.0.0",
    "snyk": "^1.639.0",
    "web-vitals": "^1.1.2"
  },
  "scripts": {
    "start": "react-scripts start",
    "start:msw": "REACT_APP_USE_MSW_MOCK_API=yes react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "docgen": "react-docgen src -e [src/*.test.js,src/setupTests.js,src/reportWebVitals.js,src/index.js ]",
    "lint": "eslint src",
    "auth": "snyk auth xxxxxxxxxxxx",
    "wizard": "snyk wizard",
    "snyk": "snyk test",
    "sonar": "sonar-scanner -Dsonar.host.url=https://sonarcloud.io/ -Dsonar.login= xxxxxxxxxxxx-Dsonar.organization=steinko-github -Dsonar.projectKey=frontend-CI-CD"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@testing-library/dom": "^8.11.1",
    "@testing-library/react-hooks": "^7.0.2",
    "@testing-library/user-event": "^13.5.0",
    "babel-eslint": "^10.1.0",
    "eslint-plugin-react": "^7.24.0",
    "eslint-plugin-testing-library": "^4.6.0",
    "jest-fetch-mock": "^3.0.3",
    "msw": "^0.36.4",
    "react-docgen": "^5.4.0",
    "sonarqube-scanner": "^2.8.1"
  },
  "msw": {
    "workerDirectory": "public"
  }
}

当我运行测试时,我得到以下结果

console.log
    befor all server listen

      at src/setupTests.js:8:28

  console.log
    http://localhost:3000/helloworld

      at getMessage (src/App.jsx:11:25)

  console.log
    *

      at getMessage (src/App.jsx:15:31)

  console.log
    mock get

      at src/mocks/handlers.js:7:18

  console.log
    http://localhost:3000

      at src/mocks/handlers.js:8:18

  console.log
    after each server reset handlers

      at Object.<anonymous> (src/setupTests.js:14:29)

  console.log
    after all  server closed

      at src/setupTests.js:19:27

 FAIL  src/App.test.jsx
  ✕ should display hello world (117 ms)

  ● should display hello world

    TestingLibraryElementError: Unable to find an element with the text: Hello World. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

    <body>
      <div>
        <div />
      </div>
    </body>

      5 | it('should display hello world', async () => {
      6 |      render(<App />);
    > 7 |      const linkElement = await screen.getByText('Hello World')
        |                                       ^
      8 |      expect(linkElement).toBeInTheDocument()
      9 |  })

      at Object.getElementError (node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/config.js:37:19)
      at node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:90:38
      at node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:62:17
      at getByText (node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:111:19)
      at Object.<anonymous> (src/App.test.jsx:7:39)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        3.441 s
Ran all test suites related to changed files.

Watch Usage: Press w to show more.

我必须做什么才能成功运行测试

4

1 回答 1

0

尝试await screen.findByText('Hello World')改用。

getByText同步的,而您的“Hello World”文本来自 API 调用(您正确地模拟了该响应)。换句话说,getBy*如果不满足条件,查询将立即抛出。

每当您想要断言依赖于异步状态的 UI 时,请使用findBy*. 因为否则会发生您的测试断言您的组件接收到响应之前运行,所以还没有呈现响应文本。

另外,很好地阅读了 React 测试库中的查询

于 2022-02-12T01:04:25.507 回答