mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 20:31:37 -05:00
Merge pull request #6 from RooVetGit/feature/addTerminateTaskButton
This commit is contained in:
Binary file not shown.
@@ -2,7 +2,7 @@
|
|||||||
"name": "roo-cline",
|
"name": "roo-cline",
|
||||||
"displayName": "Roo Cline",
|
"displayName": "Roo Cline",
|
||||||
"description": "Autonomous coding agent right in your IDE, capable of creating/editing files, running commands, using the browser, and more with your permission every step of the way.",
|
"description": "Autonomous coding agent right in your IDE, capable of creating/editing files, running commands, using the browser, and more with your permission every step of the way.",
|
||||||
"version": "1.0.3",
|
"version": "1.0.4",
|
||||||
"icon": "assets/icons/icon.png",
|
"icon": "assets/icons/icon.png",
|
||||||
"galleryBanner": {
|
"galleryBanner": {
|
||||||
"color": "#617A91",
|
"color": "#617A91",
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
|||||||
setClineAsk("resume_task")
|
setClineAsk("resume_task")
|
||||||
setEnableButtons(true)
|
setEnableButtons(true)
|
||||||
setPrimaryButtonText("Resume Task")
|
setPrimaryButtonText("Resume Task")
|
||||||
setSecondaryButtonText(undefined)
|
setSecondaryButtonText("Terminate")
|
||||||
setDidClickCancel(false) // special case where we reset the cancel button state
|
setDidClickCancel(false) // special case where we reset the cancel button state
|
||||||
break
|
break
|
||||||
case "resume_completed_task":
|
case "resume_completed_task":
|
||||||
@@ -316,6 +316,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
|||||||
switch (clineAsk) {
|
switch (clineAsk) {
|
||||||
case "api_req_failed":
|
case "api_req_failed":
|
||||||
case "mistake_limit_reached":
|
case "mistake_limit_reached":
|
||||||
|
case "resume_task":
|
||||||
startNewTask()
|
startNewTask()
|
||||||
break
|
break
|
||||||
case "command":
|
case "command":
|
||||||
|
|||||||
171
webview-ui/src/components/chat/__tests__/ChatView.test.tsx
Normal file
171
webview-ui/src/components/chat/__tests__/ChatView.test.tsx
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
import { render, screen, act } from '@testing-library/react'
|
||||||
|
import userEvent from '@testing-library/user-event'
|
||||||
|
import { ExtensionStateContextType } from '../../../context/ExtensionStateContext'
|
||||||
|
import ChatView from '../ChatView'
|
||||||
|
import { vscode } from '../../../utils/vscode'
|
||||||
|
import * as ExtensionStateContext from '../../../context/ExtensionStateContext'
|
||||||
|
|
||||||
|
// Mock vscode
|
||||||
|
jest.mock('../../../utils/vscode', () => ({
|
||||||
|
vscode: {
|
||||||
|
postMessage: jest.fn()
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Mock all components that use problematic dependencies
|
||||||
|
jest.mock('../../common/CodeBlock', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: () => <div data-testid="mock-code-block" />
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('../../common/MarkdownBlock', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: () => <div data-testid="mock-markdown-block" />
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('../BrowserSessionRow', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: () => <div data-testid="mock-browser-session-row" />
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Update ChatRow mock to capture props
|
||||||
|
let chatRowProps = null
|
||||||
|
jest.mock('../ChatRow', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: (props: any) => {
|
||||||
|
chatRowProps = props
|
||||||
|
return <div data-testid="mock-chat-row" />
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
// Mock Virtuoso component
|
||||||
|
jest.mock('react-virtuoso', () => ({
|
||||||
|
Virtuoso: ({ children }: any) => (
|
||||||
|
<div data-testid="mock-virtuoso">{children}</div>
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Mock VS Code components
|
||||||
|
jest.mock('@vscode/webview-ui-toolkit/react', () => ({
|
||||||
|
VSCodeButton: ({ children, onClick }: any) => (
|
||||||
|
<button onClick={onClick}>{children}</button>
|
||||||
|
),
|
||||||
|
VSCodeProgressRing: () => <div data-testid="progress-ring" />
|
||||||
|
}))
|
||||||
|
|
||||||
|
describe('ChatView', () => {
|
||||||
|
const mockShowHistoryView = jest.fn()
|
||||||
|
const mockHideAnnouncement = jest.fn()
|
||||||
|
|
||||||
|
let mockState: ExtensionStateContextType
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
|
||||||
|
mockState = {
|
||||||
|
clineMessages: [],
|
||||||
|
apiConfiguration: {
|
||||||
|
apiProvider: 'anthropic',
|
||||||
|
apiModelId: 'claude-3-sonnet'
|
||||||
|
},
|
||||||
|
version: '1.0.0',
|
||||||
|
customInstructions: '',
|
||||||
|
alwaysAllowReadOnly: true,
|
||||||
|
alwaysAllowWrite: true,
|
||||||
|
alwaysAllowExecute: true,
|
||||||
|
openRouterModels: {},
|
||||||
|
didHydrateState: true,
|
||||||
|
showWelcome: false,
|
||||||
|
theme: 'dark',
|
||||||
|
filePaths: [],
|
||||||
|
taskHistory: [],
|
||||||
|
shouldShowAnnouncement: false,
|
||||||
|
uriScheme: 'vscode',
|
||||||
|
|
||||||
|
setAlwaysAllowReadOnly: jest.fn(),
|
||||||
|
setAlwaysAllowWrite: jest.fn(),
|
||||||
|
setCustomInstructions: jest.fn(),
|
||||||
|
setAlwaysAllowExecute: jest.fn(),
|
||||||
|
setApiConfiguration: jest.fn(),
|
||||||
|
setShowAnnouncement: jest.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock the useExtensionState hook
|
||||||
|
jest.spyOn(ExtensionStateContext, 'useExtensionState').mockReturnValue(mockState)
|
||||||
|
})
|
||||||
|
|
||||||
|
const renderChatView = () => {
|
||||||
|
return render(
|
||||||
|
<ChatView
|
||||||
|
isHidden={false}
|
||||||
|
showAnnouncement={false}
|
||||||
|
hideAnnouncement={mockHideAnnouncement}
|
||||||
|
showHistoryView={mockShowHistoryView}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Streaming State', () => {
|
||||||
|
it('should show cancel button while streaming and trigger cancel on click', async () => {
|
||||||
|
mockState.clineMessages = [
|
||||||
|
{
|
||||||
|
type: 'say',
|
||||||
|
say: 'task',
|
||||||
|
ts: Date.now(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'say',
|
||||||
|
say: 'text',
|
||||||
|
partial: true,
|
||||||
|
ts: Date.now(),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
renderChatView()
|
||||||
|
|
||||||
|
const cancelButton = screen.getByText('Cancel')
|
||||||
|
await userEvent.click(cancelButton)
|
||||||
|
|
||||||
|
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||||
|
type: 'cancelTask'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should show terminate button when task is paused and trigger terminate on click', async () => {
|
||||||
|
mockState.clineMessages = [
|
||||||
|
{
|
||||||
|
type: 'ask',
|
||||||
|
ask: 'resume_task',
|
||||||
|
ts: Date.now(),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
renderChatView()
|
||||||
|
|
||||||
|
const terminateButton = screen.getByText('Terminate')
|
||||||
|
await userEvent.click(terminateButton)
|
||||||
|
|
||||||
|
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||||
|
type: 'clearTask'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should show retry button when API error occurs and trigger retry on click', async () => {
|
||||||
|
mockState.clineMessages = [
|
||||||
|
{
|
||||||
|
type: 'ask',
|
||||||
|
ask: 'api_req_failed',
|
||||||
|
ts: Date.now(),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
renderChatView()
|
||||||
|
|
||||||
|
const retryButton = screen.getByText('Retry')
|
||||||
|
await userEvent.click(retryButton)
|
||||||
|
|
||||||
|
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||||
|
type: 'askResponse',
|
||||||
|
askResponse: 'yesButtonClicked'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user