diff --git a/.github/workflows/pr_checks.yaml b/.github/workflows/pr_checks.yaml
index e5f44c03e3..c41c57f72b 100644
--- a/.github/workflows/pr_checks.yaml
+++ b/.github/workflows/pr_checks.yaml
@@ -96,7 +96,7 @@ jobs:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
install-gui:
- needs: [install-root, install-core]
+ needs: [ install-root, install-core ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -157,7 +157,7 @@ jobs:
npx tsc --noEmit
binary-checks:
- needs: [install-root, install-core]
+ needs: [ install-root, install-core ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -193,7 +193,7 @@ jobs:
npx tsc --noEmit
install-vscode:
- needs: [install-root, install-core]
+ needs: [ install-root, install-core ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -277,7 +277,7 @@ jobs:
vscode-get-test-file-matrix:
runs-on: ubuntu-latest
- needs: [install-root, install-vscode]
+ needs: [ install-root, install-vscode ]
outputs:
test_file_matrix: ${{ steps.vscode-get-test-file-matrix.outputs.test_file_matrix }}
steps:
@@ -306,7 +306,7 @@ jobs:
vscode-package-extension:
runs-on: ubuntu-latest
- needs: [install-vscode, install-core]
+ needs: [ install-vscode, install-core ]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
@@ -338,7 +338,7 @@ jobs:
vscode-download-e2e-dependencies:
runs-on: ubuntu-latest
- needs: [install-vscode, install-core]
+ needs: [ install-vscode, install-core ]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
@@ -445,7 +445,7 @@ jobs:
path: extensions/vscode/e2e/storage/screenshots
gui-tests:
- needs: [install-gui, install-core]
+ needs: [ install-gui, install-core ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -476,7 +476,7 @@ jobs:
npm test
jetbrains-tests:
- needs: [install-root, install-core]
+ needs: [ install-root, core-checks ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -573,3 +573,5 @@ jobs:
name: jb-failure-report
path: |
${{ github.workspace }}/extensions/intellij/build/reports
+
+
diff --git a/core/protocol/passThrough.ts b/core/protocol/passThrough.ts
index 756b3db54e..c4b999521d 100644
--- a/core/protocol/passThrough.ts
+++ b/core/protocol/passThrough.ts
@@ -61,6 +61,8 @@ export const WEBVIEW_TO_CORE_PASS_THROUGH: (keyof ToCoreFromWebviewProtocol)[] =
];
// Message types to pass through from core to webview
+// Note: If updating these values, make a corresponding update in
+// extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/constants/MessageTypes.kt
export const CORE_TO_WEBVIEW_PASS_THROUGH: (keyof ToWebviewFromCoreProtocol)[] =
[
"configUpdate",
diff --git a/extensions/intellij/.gitignore b/extensions/intellij/.gitignore
index ac787e9369..2be56cfd9e 100644
--- a/extensions/intellij/.gitignore
+++ b/extensions/intellij/.gitignore
@@ -3,4 +3,6 @@ src/main/resources/webview
src/main/resources/bin
src/main/resources/config_schema.json
src/main/resources/continue_rc_schema.json
-video
\ No newline at end of file
+video
+src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/test-continue/*
+!src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/test-continue/config.json
\ No newline at end of file
diff --git a/extensions/intellij/.run/Run IDE for UI Tests.run.xml b/extensions/intellij/.run/Run IDE for UI Tests.run.xml
deleted file mode 100644
index 5f7eb46c85..0000000000
--- a/extensions/intellij/.run/Run IDE for UI Tests.run.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/extensions/intellij/.run/Run Test IDE.run.xml b/extensions/intellij/.run/Run Test IDE.run.xml
new file mode 100644
index 0000000000..80a2a251f8
--- /dev/null
+++ b/extensions/intellij/.run/Run Test IDE.run.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ false
+ false
+
+
+
+
+
\ No newline at end of file
diff --git a/extensions/intellij/.run/Run Tests.run.xml b/extensions/intellij/.run/Run Tests.run.xml
new file mode 100644
index 0000000000..bdff34d6dd
--- /dev/null
+++ b/extensions/intellij/.run/Run Tests.run.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ false
+ false
+
+
+
\ No newline at end of file
diff --git a/extensions/intellij/.run/Run e2e tests.run.xml b/extensions/intellij/.run/Run e2e tests.run.xml
new file mode 100644
index 0000000000..2280aece02
--- /dev/null
+++ b/extensions/intellij/.run/Run e2e tests.run.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extensions/intellij/CONTRIBUTING.md b/extensions/intellij/CONTRIBUTING.md
index d37aaa2c46..836eaa7b62 100644
--- a/extensions/intellij/CONTRIBUTING.md
+++ b/extensions/intellij/CONTRIBUTING.md
@@ -101,7 +101,9 @@ toolbar.
_Run | Debugging Actions | Reload Changed Classes`_
- This will often fail on new imports, schema changes etc. In that case, you need to stop and restart the extension
- `gui`: Changes will be reloaded automatically
-- `core`: Run `npm run build` from the `binary` directory (requires restarting the `Start Core Dev Server` task)
+- `core`: Run `npm run build -- --os [darwin | linux | win32]` from the `binary` directory (requires
+ restarting the
+ `Start Core Dev Server` task)
### Setting breakpoints
diff --git a/extensions/intellij/build.gradle.kts b/extensions/intellij/build.gradle.kts
index 25d2fb361c..ee7dce8bea 100644
--- a/extensions/intellij/build.gradle.kts
+++ b/extensions/intellij/build.gradle.kts
@@ -130,7 +130,10 @@ tasks {
// Configure UI tests plugin
// Read more: https://github.com/JetBrains/intellij-ui-test-robot
runIdeForUiTests {
- environment("CONTINUE_GLOBAL_DIR", "src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/test-continue")
+ environment(
+ "CONTINUE_GLOBAL_DIR",
+ "${rootProject.projectDir}/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/test-continue"
+ )
systemProperty("robot-server.port", "8082")
systemProperty("ide.mac.message.dialogs.as.sheets", "false")
systemProperty("jb.privacy.policy.text", "")
@@ -141,6 +144,7 @@ tasks {
systemProperty("idea.trust.all.projects", "true")
systemProperty("ide.show.tips.on.startup.default.value", "false")
systemProperty("ide.browser.jcef.jsQueryPoolSize", "10000")
+ systemProperty("ide.browser.jcef.contextMenu.devTools.enabled", "true")
// This is to ensure we load the GUI with OSR enabled. We have logic that
// renders with OSR disabled below a particular IDE version.
@@ -180,6 +184,5 @@ tasks {
test {
useJUnitPlatform()
- environment("CONTINUE_GLOBAL_DIR", "src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/test-continue")
}
}
diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt
index 2dc6ba021d..b6eaeacbf5 100644
--- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt
+++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt
@@ -294,12 +294,13 @@ class AutocompleteService(private val project: Project) {
}
private fun isInjectedFile(editor: Editor): Boolean {
- val psiFile = runReadAction { PsiDocumentManager.getInstance(project).getPsiFile(editor.document) }
- if (psiFile == null) {
- return false
- }
- val response = runReadAction { psiFile.isInjectedText() }
- return response
+ return ApplicationManager.getApplication().executeOnPooledThread {
+ ApplicationManager.getApplication().runReadAction {
+ val psiFile =
+ PsiDocumentManager.getInstance(project).getPsiFile(editor.document) ?: return@runReadAction false
+ return@runReadAction psiFile.isInjectedText()
+ }
+ }.get()
}
fun hideCompletions(editor: Editor) {
diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/constants/MessageTypes.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/constants/MessageTypes.kt
index b309cbbc68..585dd716f0 100644
--- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/constants/MessageTypes.kt
+++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/constants/MessageTypes.kt
@@ -50,13 +50,78 @@ class MessageTypes {
"showToast",
)
+ // Note: If updating these values, make a corresponding update in
+ // core/protocol/passThrough.ts
val PASS_THROUGH_TO_WEBVIEW = listOf(
"configUpdate",
"getDefaultModelTitle",
- "indexProgress",
+ "indexProgress", // Codebase
+ "indexing/statusUpdate", // Docs, etc.
+ "addContextItem",
"refreshSubmenuItems",
+ "isContinueInputFocused",
"didChangeAvailableProfiles",
- "addContextItem"
+ "setTTSActive",
+ "getWebviewHistoryLength",
+ "getCurrentSessionId",
+ "signInToControlPlane",
+ "openDialogMessage",
+ "docs/suggestions",
+ )
+
+ // Note: If updating these values, make a corresponding update in
+ // core/protocol/passThrough.ts
+ val PASS_THROUGH_TO_CORE = listOf(
+ "abort",
+ "history/list",
+ "history/delete",
+ "history/load",
+ "history/save",
+ "devdata/log",
+ "config/addModel",
+ "config/addContextProvider",
+ "config/newPromptFile",
+ "config/ideSettingsUpdate",
+ "config/getSerializedProfileInfo",
+ "config/deleteModel",
+ "config/listProfiles",
+ "config/openProfile",
+ "context/getContextItems",
+ "context/getSymbolsForFiles",
+ "context/loadSubmenuItems",
+ "context/addDocs",
+ "context/removeDocs",
+ "context/indexDocs",
+ "autocomplete/complete",
+ "autocomplete/cancel",
+ "autocomplete/accept",
+ "command/run",
+ "tts/kill",
+ "llm/complete",
+ "llm/streamComplete",
+ "llm/streamChat",
+ "llm/listModels",
+ "streamDiffLines",
+ "chatDescriber/describe",
+ "stats/getTokensPerDay",
+ "stats/getTokensPerModel",
+ // Codebase
+ "index/setPaused",
+ "index/forceReIndex",
+ "index/forceReIndexFiles",
+ "index/indexingProgressBarInitialized",
+ // Docs, etc.
+ "indexing/reindex",
+ "indexing/abort",
+ "indexing/setPaused",
+ "docs/getSuggestedDocs",
+ "docs/initStatuses",
+ //
+ "completeOnboarding",
+ "addAutocompleteModel",
+ "profiles/switch",
+ "didChangeSelectedProfile",
+ "tools/call",
)
}
}
\ No newline at end of file
diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/toolWindow/ContinueBrowser.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/toolWindow/ContinueBrowser.kt
index 5523bdeffc..b43cf62c98 100644
--- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/toolWindow/ContinueBrowser.kt
+++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/toolWindow/ContinueBrowser.kt
@@ -2,6 +2,7 @@ package com.github.continuedev.continueintellijextension.toolWindow
import com.github.continuedev.continueintellijextension.activities.ContinuePluginDisposable
import com.github.continuedev.continueintellijextension.constants.MessageTypes
+import com.github.continuedev.continueintellijextension.constants.MessageTypes.Companion.PASS_THROUGH_TO_CORE
import com.github.continuedev.continueintellijextension.factories.CustomSchemeHandlerFactory
import com.github.continuedev.continueintellijextension.services.ContinueExtensionSettings
import com.github.continuedev.continueintellijextension.services.ContinuePluginService
@@ -18,58 +19,6 @@ import org.cef.browser.CefBrowser
import org.cef.handler.CefLoadHandlerAdapter
class ContinueBrowser(val project: Project, url: String) {
- private val PASS_THROUGH_TO_CORE = listOf(
- "abort",
- "history/list",
- "history/delete",
- "history/load",
- "history/save",
- "devdata/log",
- "config/addModel",
- "config/addContextProvider",
- "config/newPromptFile",
- "config/ideSettingsUpdate",
- "config/getSerializedProfileInfo",
- "config/deleteModel",
- "config/listProfiles",
- "config/openProfile",
- "context/getContextItems",
- "context/getSymbolsForFiles",
- "context/loadSubmenuItems",
- "context/addDocs",
- "context/removeDocs",
- "context/indexDocs",
- "autocomplete/complete",
- "autocomplete/cancel",
- "autocomplete/accept",
- "command/run",
- "tts/kill",
- "llm/complete",
- "llm/streamComplete",
- "llm/streamChat",
- "llm/listModels",
- "streamDiffLines",
- "chatDescriber/describe",
- "stats/getTokensPerDay",
- "stats/getTokensPerModel",
- // Codebase
- "index/setPaused",
- "index/forceReIndex",
- "index/indexingProgressBarInitialized",
- // Docs, etc.
- "indexing/reindex",
- "indexing/abort",
- "indexing/setPaused",
- "docs/getSuggestedDocs",
- "docs/initStatuses",
- //
- "completeOnboarding",
- "addAutocompleteModel",
- "profiles/switch",
- "didChangeSelectedProfile",
- "tools/call",
- )
-
private fun registerAppSchemeHandler() {
CefApp.getInstance().registerSchemeHandlerFactory(
"http",
@@ -82,13 +31,8 @@ class ContinueBrowser(val project: Project, url: String) {
init {
val isOSREnabled = ServiceManager.getService(ContinueExtensionSettings::class.java).continueState.enableOSR
- this.browser = JBCefBrowser.createBuilder().setOffScreenRendering(isOSREnabled).build()
-
- browser.jbCefClient.setProperty(
- JBCefClient.Properties.JS_QUERY_POOL_SIZE,
- JS_QUERY_POOL_SIZE
- )
+ this.browser = JBCefBrowser.createBuilder().setOffScreenRendering(isOSREnabled).build()
registerAppSchemeHandler()
browser.loadURL(url);
diff --git a/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/Autocomplete.kt b/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/Autocomplete.kt
new file mode 100644
index 0000000000..fdb271639f
--- /dev/null
+++ b/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/Autocomplete.kt
@@ -0,0 +1,73 @@
+package com.github.continuedev.continueintellijextension.e2e
+
+import com.automation.remarks.junit5.Video
+import com.github.continuedev.continueintellijextension.fixtures.dialog
+import com.github.continuedev.continueintellijextension.fixtures.idea
+import com.github.continuedev.continueintellijextension.fixtures.welcomeFrame
+import com.github.continuedev.continueintellijextension.utils.RemoteRobotExtension
+import com.github.continuedev.continueintellijextension.utils.StepsLogger
+import com.intellij.remoterobot.RemoteRobot
+import com.intellij.remoterobot.fixtures.ComponentFixture
+import com.intellij.remoterobot.search.locators.byXpath
+import com.intellij.remoterobot.steps.CommonSteps
+import com.intellij.remoterobot.utils.keyboard
+import com.intellij.remoterobot.utils.waitFor
+import com.intellij.remoterobot.utils.waitForIgnoringError
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import java.time.Duration.ofMinutes
+import java.time.Duration.ofSeconds
+
+@ExtendWith(RemoteRobotExtension::class)
+class Autocomplete {
+ init {
+ StepsLogger.init()
+ }
+
+ @BeforeEach
+ fun waitForIde(remoteRobot: RemoteRobot) {
+ waitForIgnoringError(ofMinutes(3)) { remoteRobot.callJs("true") }
+ }
+
+ @AfterEach
+ fun closeProject(remoteRobot: RemoteRobot) = CommonSteps(remoteRobot).closeProject()
+
+ // @Test
+ @Video
+ fun displayCompletion(remoteRobot: RemoteRobot): Unit = with(remoteRobot) {
+ welcomeFrame {
+ createNewProjectLink.click()
+ dialog("New Project") {
+ findText("Java").click()
+ checkBox("Add sample code").select()
+ button("Create").click()
+ }
+ }
+
+ // Wait for the default "Main.java" tab to load
+ // Our "continue_tutorial.java.ft" tab loads first, but then "Main.java" takes focus.
+ waitFor(ofSeconds(20)) {
+ findAll(
+ byXpath("//div[@accessiblename='Main.java' and @class='EditorTabLabel']")
+ ).isNotEmpty()
+ }
+
+ idea {
+ with(textEditor()) {
+ val userMsg = "TEST_USER_MESSAGE_0"
+ editor.insertTextAtLine(0, 0, userMsg)
+ editor.clickOnOffset(userMsg.length)
+
+ keyboard {
+ enterText(" ")
+ }
+
+ waitFor(ofSeconds(10)) {
+ editor.hasText("TEST_LLM_RESPONSE_0")
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/GUI.kt b/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/GUI.kt
new file mode 100644
index 0000000000..5672debba5
--- /dev/null
+++ b/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/GUI.kt
@@ -0,0 +1,96 @@
+/**
+ * Currently we can't test any actions in the GUI that involve clicks.
+ * See this open issue for details: https://github.com/JetBrains/intellij-ui-test-robot/issues/491
+ */
+package com.github.continuedev.continueintellijextension.e2e
+
+import com.automation.remarks.junit5.Video
+import com.github.continuedev.continueintellijextension.fixtures.*
+import com.github.continuedev.continueintellijextension.utils.RemoteRobotExtension
+import com.github.continuedev.continueintellijextension.utils.StepsLogger
+import com.github.continuedev.continueintellijextension.utils.getMetaKey
+import com.intellij.remoterobot.RemoteRobot
+import com.intellij.remoterobot.fixtures.ComponentFixture
+import com.intellij.remoterobot.search.locators.byXpath
+import com.intellij.remoterobot.steps.CommonSteps
+import com.intellij.remoterobot.stepsProcessing.step
+import com.intellij.remoterobot.utils.keyboard
+import com.intellij.remoterobot.utils.waitFor
+import com.intellij.remoterobot.utils.waitForIgnoringError
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import java.awt.event.KeyEvent.*
+import java.time.Duration.ofMinutes
+import java.time.Duration.ofSeconds
+
+@ExtendWith(RemoteRobotExtension::class)
+class GUI {
+ init {
+ StepsLogger.init()
+ }
+
+ @BeforeEach
+ fun waitForIde(remoteRobot: RemoteRobot) {
+ waitForIgnoringError(ofMinutes(3)) { remoteRobot.callJs("true") }
+ }
+
+ @AfterEach
+ fun closeProject(remoteRobot: RemoteRobot) = CommonSteps(remoteRobot).closeProject()
+
+ // @Test
+ @Video
+ fun highlightCode(remoteRobot: RemoteRobot): Unit = with(remoteRobot) {
+ welcomeFrame {
+ createNewProjectLink.click()
+ dialog("New Project") {
+ findText("Java").click()
+ checkBox("Add sample code").select()
+ button("Create").click()
+ }
+ }
+
+ // Wait for the default "Main.java" tab to load
+ // Our "continue_tutorial.java.ft" tab loads first, but then "Main.java" takes focus.
+ // If we don't wait for this, clicking on the GUI may fail because a popup displays
+ // while the `continue_tutorial.java` is loading.
+ waitFor(ofSeconds(20)) {
+ findAll(
+ byXpath("//div[@accessiblename='Main.java' and @class='EditorTabLabel']")
+ ).isNotEmpty()
+ }
+
+ idea {
+ step("Manually open the webview") {
+ // Manually open the webview
+ find(byXpath("//div[@text='Continue']"), ofSeconds((10))).click()
+
+ waitFor(ofSeconds(10)) {
+ browser().isShowing
+ }
+
+ // Arbitrary timeout due to a bug where the webview will refresh
+ // and clear the editor state on first load
+ Thread.sleep(5000)
+ }
+
+ step("Verify we can highlight code and add to webview") {
+ val textToInsert = "Hello world!"
+
+ with(textEditor()) {
+ editor.insertTextAtLine(0, 0, textToInsert)
+ editor.selectText(textToInsert)
+
+ keyboard {
+ hotKey(getMetaKey(), VK_J)
+ }
+ }
+
+ waitFor(ofSeconds(10)) {
+ browser().findElementByContainsText(textToInsert).html.isNotEmpty()
+ }
+ }
+ }
+ }
+}
diff --git a/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/Onboarding.kt b/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/Onboarding.kt
new file mode 100644
index 0000000000..3f667559d1
--- /dev/null
+++ b/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/Onboarding.kt
@@ -0,0 +1,85 @@
+package com.github.continuedev.continueintellijextension.e2e
+
+import com.automation.remarks.junit5.Video
+import com.github.continuedev.continueintellijextension.fixtures.dialog
+import com.github.continuedev.continueintellijextension.fixtures.idea
+import com.github.continuedev.continueintellijextension.fixtures.welcomeFrame
+import com.github.continuedev.continueintellijextension.utils.RemoteRobotExtension
+import com.github.continuedev.continueintellijextension.utils.StepsLogger
+import com.intellij.remoterobot.RemoteRobot
+import com.intellij.remoterobot.fixtures.ComponentFixture
+import com.intellij.remoterobot.search.locators.byXpath
+import com.intellij.remoterobot.steps.CommonSteps
+import com.intellij.remoterobot.stepsProcessing.step
+import com.intellij.remoterobot.utils.waitFor
+import com.intellij.remoterobot.utils.waitForIgnoringError
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import java.time.Duration.ofMinutes
+import java.time.Duration.ofSeconds
+
+@ExtendWith(RemoteRobotExtension::class)
+class Onboarding {
+ init {
+ StepsLogger.init()
+ }
+
+ @BeforeEach
+ fun waitForIde(remoteRobot: RemoteRobot) {
+ waitForIgnoringError(ofMinutes(3)) { remoteRobot.callJs("true") }
+ }
+
+ @AfterEach
+ fun closeProject(remoteRobot: RemoteRobot) = CommonSteps(remoteRobot).closeProject()
+
+
+ // @Test
+ @Video
+ fun onboarding(remoteRobot: RemoteRobot): Unit = with(remoteRobot) {
+ welcomeFrame {
+ createNewProjectLink.click()
+ dialog("New Project") {
+ findText("Java").click()
+ checkBox("Add sample code").select()
+ button("Create").click()
+ }
+ }
+
+ idea {
+ // Wait for the default "Main.java" tab to load
+ // Our "continue_tutorial.java.ft" tab loads first, but then "Main.java" takes focus.
+ // So we need to wait for that to occur, and then focus on "continue_tutorial.java.ft"
+ waitFor(ofSeconds(20)) {
+ findAll(
+ byXpath("//div[@accessiblename='Main.java' and @class='EditorTabLabel']")
+ ).isNotEmpty()
+ }
+
+ // TODO: Need a good way to ensure this is the first test ran in the entire suite
+// step("Verify Continue tutorial file is loaded") {
+// find(byXpath("//div[@visible_text='continue_tutorial.java']"))
+// }
+
+ step("Manually open the webview") {
+ // Manually open the webview
+ find(byXpath("//div[@text='Continue']"), ofSeconds((10))).click()
+
+ waitFor(ofSeconds(10)) {
+ browser().isShowing
+ }
+ }
+
+ step("Verify the onboarding card is present") {
+ waitFor(ofSeconds(30)) {
+ try {
+ browser().findElement("//*[@data-testid='onboarding-card']").html.isNotEmpty()
+ } catch (e: Exception) {
+ false
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/TutorialTest.kt b/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/TutorialTest.kt
deleted file mode 100644
index 8e43def29a..0000000000
--- a/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/TutorialTest.kt
+++ /dev/null
@@ -1,94 +0,0 @@
-package com.github.continuedev.continueintellijextension.e2e
-
-import com.automation.remarks.junit5.Video
-import com.github.continuedev.continueintellijextension.pages.dialog
-import com.github.continuedev.continueintellijextension.pages.idea
-import com.github.continuedev.continueintellijextension.pages.welcomeFrame
-import com.github.continuedev.continueintellijextension.utils.RemoteRobotExtension
-import com.github.continuedev.continueintellijextension.utils.StepsLogger
-import com.github.continuedev.continueintellijextension.utils.getMetaKey
-import com.intellij.remoterobot.RemoteRobot
-import com.intellij.remoterobot.fixtures.ComponentFixture
-import com.intellij.remoterobot.fixtures.JCefBrowserFixture
-import com.intellij.remoterobot.search.locators.Locator
-import com.intellij.remoterobot.search.locators.byXpath
-import com.intellij.remoterobot.steps.CommonSteps
-import com.intellij.remoterobot.utils.keyboard
-import com.intellij.remoterobot.utils.waitFor
-import com.intellij.remoterobot.utils.waitForIgnoringError
-import org.junit.jupiter.api.AfterEach
-import org.junit.jupiter.api.BeforeEach
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.extension.ExtendWith
-import java.awt.event.KeyEvent.*
-import java.time.Duration.ofMinutes
-import java.time.Duration.ofSeconds
-
-@ExtendWith(RemoteRobotExtension::class)
-class TutorialTest {
- init {
- StepsLogger.init()
- }
-
- @BeforeEach
- fun waitForIde(remoteRobot: RemoteRobot) {
- waitForIgnoringError(ofMinutes(3)) { remoteRobot.callJs("true") }
- }
-
- @AfterEach
- fun closeProject(remoteRobot: RemoteRobot) = CommonSteps(remoteRobot).closeProject()
-
- @Test
- @Video
- fun completeTutorial(remoteRobot: RemoteRobot) = with(remoteRobot) {
- welcomeFrame {
- createNewProjectLink.click()
- dialog("New Project") {
- findText("Java").click()
- checkBox("Add sample code").select()
- button("Create").click()
- }
- }
-
- // Wait for the default "Main.java" tab to load
- // Our "continue_tutorial.java" tab loads first, but then "Main.java" takes focus.
- // So we need to wait for that to occur, and then focus on "continue_tutorial.java"
- waitFor(ofSeconds(20)) {
- findAll(
- byXpath("//div[@accessiblename='Main.java' and @class='EditorTabLabel']")
- ).isNotEmpty()
- }
-
- val tutorialEditorTabLocator: Locator =
- byXpath("//div[@accessiblename='continue_tutorial.java' and @class='EditorTabLabel']")
- val tutorialEditorTab: ComponentFixture =
- remoteRobot.find(ComponentFixture::class.java, tutorialEditorTabLocator)
- tutorialEditorTab.click()
-
- // Manually open the webview
- find(byXpath("//div[@text='Continue']")).click()
-
- // Arbitrary sleep while we wait for the webview to load
- Thread.sleep(10000)
-
- val textToInsert = "Hello world!"
-
- idea {
- with(textEditor()) {
- editor.insertTextAtLine(0, 0, textToInsert)
- editor.selectText(textToInsert)
- keyboard {
- hotKey(getMetaKey(), VK_J)
- }
- }
- }
-
- // TODO: locator needs to be OS aware
- // https://github.com/JetBrains/intellij-ui-test-robot/blob/139a05eb99e9a49f13605626b81ad9864be23c96/remote-fixtures/src/main/kotlin/com/intellij/remoterobot/fixtures/CommonContainerFixture.kt#L203
- val jcefBrowser = find(JCefBrowserFixture.macLocator)
- assert(jcefBrowser.getDom().isNotEmpty()) { "JCEF browser not found or empty" }
-
- val codeSnippetText = jcefBrowser.findElementByContainsText(textToInsert)
- assert(codeSnippetText.html.isNotEmpty()) { "Failed to find code snippet in webview" }
- }
-}
\ No newline at end of file
diff --git a/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/test-continue/config.json b/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/test-continue/config.json
new file mode 100644
index 0000000000..0160335f51
--- /dev/null
+++ b/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/e2e/test-continue/config.json
@@ -0,0 +1,43 @@
+{
+ "ui": {
+ "displayRawMarkdown": false
+ },
+ "models": [
+ {
+ "title": "TEST LLM",
+ "provider": "test",
+ "model": "this field is not used"
+ },
+ {
+ "title": "Mock",
+ "provider": "mock",
+ "model": "this field is not used"
+ }
+ ],
+ "analytics": {
+ "provider": "continue-proxy"
+ },
+ "tabAutocompleteModel": {
+ "title": "TEST LLM",
+ "provider": "test",
+ "model": "this field is not used"
+ },
+ "tabAutocompleteOptions": {
+ "useCache": false
+ },
+ "contextProviders": [
+ {
+ "name": "docs"
+ },
+ {
+ "name": "diff"
+ },
+ {
+ "name": "url"
+ },
+ {
+ "name": "folder"
+ }
+ ],
+ "docs": []
+}
diff --git a/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/pages/DialogFixture.kt b/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/fixtures/DialogFixture.kt
similarity index 95%
rename from extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/pages/DialogFixture.kt
rename to extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/fixtures/DialogFixture.kt
index 8bb5798e34..d9643a96b9 100644
--- a/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/pages/DialogFixture.kt
+++ b/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/fixtures/DialogFixture.kt
@@ -1,4 +1,4 @@
-package com.github.continuedev.continueintellijextension.pages
+package com.github.continuedev.continueintellijextension.fixtures
/*
* Source: https://github.com/JetBrains/intellij-ui-test-robot/blob/139a05eb99e9a49f13605626b81ad9864be23c96/ui-test-example/src/test/kotlin/org/intellij/examples/simple/plugin/pages/DialogFixture.kt
diff --git a/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/pages/IdeaFrame.kt b/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/fixtures/IdeaFrame.kt
similarity index 98%
rename from extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/pages/IdeaFrame.kt
rename to extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/fixtures/IdeaFrame.kt
index b554325853..141677c153 100644
--- a/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/pages/IdeaFrame.kt
+++ b/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/fixtures/IdeaFrame.kt
@@ -1,4 +1,4 @@
-package com.github.continuedev.continueintellijextension.pages
+package com.github.continuedev.continueintellijextension.fixtures
/*
* Source: https://github.com/JetBrains/intellij-ui-test-robot/blob/139a05eb99e9a49f13605626b81ad9864be23c96/ui-test-example/src/test/kotlin/org/intellij/examples/simple/plugin/pages/IdeaFrame.kt
diff --git a/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/pages/WelcomeFrame.kt b/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/fixtures/WelcomeFrame.kt
similarity index 94%
rename from extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/pages/WelcomeFrame.kt
rename to extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/fixtures/WelcomeFrame.kt
index ab59f72ab7..70029fdaf9 100644
--- a/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/pages/WelcomeFrame.kt
+++ b/extensions/intellij/src/test/kotlin/com/github/continuedev/continueintellijextension/fixtures/WelcomeFrame.kt
@@ -1,4 +1,4 @@
-package com.github.continuedev.continueintellijextension.pages
+package com.github.continuedev.continueintellijextension.fixtures
/*
* Source: https://github.com/JetBrains/intellij-ui-test-robot/blob/139a05eb99e9a49f13605626b81ad9864be23c96/ui-test-example/src/test/kotlin/org/intellij/examples/simple/plugin/pages/WelcomeFrame.kt
diff --git a/gui/src/components/OnboardingCard/OnboardingCard.tsx b/gui/src/components/OnboardingCard/OnboardingCard.tsx
index bce9c5a98e..78caa4b5b2 100644
--- a/gui/src/components/OnboardingCard/OnboardingCard.tsx
+++ b/gui/src/components/OnboardingCard/OnboardingCard.tsx
@@ -41,7 +41,10 @@ export function OnboardingCard() {
}
return (
-
+
-
+
{props.title ?? "Confirmation"}