我正在測驗一個具有 textarea 元素的組件。我使用 loremText 獲取元素并嘗試使用其中的 loremText 是一個保存文本的變數screen.getByRole('textbox')
來輸入它。await userEvent.type(textbox, loremText)
Jest 測驗通過,但文本從未輸入到 textarea 元素中。為什么會這樣?
這是測驗:
import { screen, render } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import TextEditor from '../components/textEditor'
const loremText =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum'
const renderTextEditor = (content, setContent, autoFocus) => {
return render(
<TextEditor
content={content}
setContent={setContent}
autoFocus={autoFocus}
/>
)
}
test('type text into textbox', async () => {
renderTextEditor('content', jest.fn(), true)
const textbox = screen.getByRole('textbox')
await userEvent.type(textbox, loremText)
screen.debug(textbox)
})
這是具有 textarea 元素的組件:
import { useState } from 'react'
import MarkdownIt from 'markdown-it'
type Props = {
content: string
setContent: (value: string) => void
autoFocus?: boolean
}
enum TextStyle {
Bold,
Italic,
Strike,
Code,
Quote,
List,
}
const markdown = new MarkdownIt({
breaks: true,
html: false,
linkify: true,
})
const TextEditor = ({ content, setContent, autoFocus }: Props) => {
const [isPreview, setIsPreview] = useState<boolean>(false)
const [contentHtml, setContentHtml] = useState<string>(
markdown.render(content)
)
const handleContentInput = (event: any) => {
setContent(event.target.value)
setContentHtml(markdown.render(event.target.value))
}
const addListItem = (
previousText: string,
text: string,
start: number,
end: number
): string => {
const listIndex = text.indexOf('\n')
if (end === 0) {
return previousText text
}
if (listIndex === -1 || listIndex > end) {
return previousText '* ' text
}
if (listIndex < start) {
return addListItem(
previousText text.substring(0, listIndex 1),
text.substring(listIndex 1),
Math.max(start - listIndex - 1, 0),
Math.max(end - listIndex - 1, 0)
)
}
return addListItem(
previousText '* ' text.substring(0, listIndex 1),
text.substring(listIndex 1),
Math.max(start - listIndex - 1, 0),
Math.max(end - listIndex - 1, 0)
)
}
const addStyle = (style: TextStyle) => {
const sel = document.getElementById(
'inputTextArea'
) as HTMLTextAreaElement
const start = sel.selectionStart
const end = sel.selectionEnd
let newContent: string = content
if (style === TextStyle.Italic) {
newContent =
content.substring(0, start)
'*'
content.substring(start, end)
'*'
content.substring(end)
} else if (style === TextStyle.Bold) {
newContent =
content.substring(0, start)
'**'
content.substring(start, end)
'**'
content.substring(end)
} else if (style === TextStyle.Strike) {
newContent =
content.substring(0, start)
'~~'
content.substring(start, end)
'~~'
content.substring(end)
} else if (style === TextStyle.Code) {
newContent =
content.substring(0, start)
'`'
content.substring(start, end)
'`'
content.substring(end)
} else if (style === TextStyle.Quote) {
newContent =
content.substring(0, start)
'> '
content.substring(start, end)
'\n'
content.substring(end)
} else if (style === TextStyle.List) {
newContent = addListItem('', content, start, end)
}
setContent(newContent)
setContentHtml(markdown.render(newContent))
}
const insertImage = () => {
const sel = document.getElementById(
'inputTextArea'
) as HTMLTextAreaElement
const start = sel.selectionStart
const end = sel.selectionEnd
const newContent =
content.substring(0, start)
``
content.substring(end)
setContent(newContent)
setContentHtml(markdown.render(newContent))
}
const insertLink = () => {
const sel = document.getElementById(
'inputTextArea'
) as HTMLTextAreaElement
const start = sel.selectionStart
const end = sel.selectionEnd
const newContent =
content.substring(0, start)
`[${content.substring(start, end)}](https://)`
content.substring(end)
setContent(newContent)
setContentHtml(markdown.render(newContent))
}
return (
<div>
<div>
<div className="buttons">
<div className="group basic">
<button onClick={() => addStyle(TextStyle.Bold)}>
<img
src={require('../../public/images/bold.svg')}
/>
</button>
<button onClick={() => addStyle(TextStyle.Italic)}>
<img
src={require('../../public/images/italic.svg')}
/>
</button>
<button onClick={() => addStyle(TextStyle.Strike)}>
<img
src={require('../../public/images/strike.svg')}
/>
</button>
<button onClick={() => addStyle(TextStyle.Code)}>
<img
src={require('../../public/images/codeblock.svg')}
/>
</button>
<button onClick={() => addStyle(TextStyle.Quote)}>
<img
src={require('../../public/images/quote.svg')}
/>
</button>
<button onClick={() => addStyle(TextStyle.List)}>
<img
src={require('../../public/images/bullet.svg')}
/>
</button>
<button onClick={insertLink}>
<img
src={require('../../public/images/link.svg')}
/>
</button>
<button onClick={insertImage}>
<img src={require('../../public/images/img.svg')} />
</button>
</div>
<div className="group">
<button
onClick={() =>
window.open(
'https://commonmark.org/help/',
'__blank'
)
}
>
<img
src={require('../../public/images/info_small.svg')}
/>
</button>
<button
className="button-border"
onClick={() => setIsPreview(!isPreview)}
>
{isPreview ? 'Edit' : 'Preview'}
</button>
</div>
</div>
{isPreview && (
<div className="block-content preview-box">
<div className="content">
<div
dangerouslySetInnerHTML={{
__html: contentHtml,
}}
/>
</div>
</div>
)}
{!isPreview && (
<textarea
id="inputTextArea"
onChange={handleContentInput}
value={content ?? ''}
autoFocus={autoFocus}
/>
)}
</div>
</div>
)
}
export default TextEditor
當我screen.debug(textbox)
用來查看是否輸入了文本時,終端輸出是:
<textarea
id="inputTextArea"
>
content
</textarea>
uj5u.com熱心網友回復:
您正在使用content
TextEditor 的道具來呈現文本區域的內容。由于您只放了一個靜態值“內容”,因此該值將覆寫文本區域的內容。
您可以使用包裝元素來實作content
andsetContent
道具:
const TestWrapper = () => {
const [content, setContent] = useState("");
return <TextEditor
content={content}
setContent={setContent}
autoFocus={true}
/>
}
const renderTextEditor = () => {
return render(
<TestWrapper />
)
}
test('type text into textbox', async () => {
renderTextEditor();
const textbox = screen.getByRole('textbox')
userEvent.type(textbox, loremText) // userEvent.type is not an async function
await waitFor(() => {
expect(textbox).toHaveValue(loremText);
});
})
uj5u.com熱心網友回復:
這是一個使用 Promise 的更簡潔的實作:
const loremText =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum'
const TestWrapper = () => {
const [content, setContent] = useState('')
return (
<TextEditor
content={content}
setContent={setContent}
autoFocus={true}
/>
)
}
const renderTextEditor = () => {
return render(<TestWrapper />)
}
test('type text into textbox', async () => {
renderTextEditor()
const textbox = screen.getByRole('textbox')
// using promises...
userEvent
.type(textbox, loremText)
.then(() => expect(textbox).toHaveValue(loremText))
})
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/507619.html
下一篇:如何解決編碼挑戰的時間限制