我想测试 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.
我必须做什么才能成功运行测试