Skip to content

Commit 6632d50

Browse files
committed
refactor(e2e): simplify E2ECli to use E2EDslIntegration directly
- Remove mock PageState - DSL generation doesn't need page state - Use E2EDslIntegration.generateScenarioFromDescription() for direct DSL generation - Add xiuper-e2e dependency to mpp-ui jvmMain - Remove redundant generateDsl and formatAction methods
1 parent 3c67e02 commit 6632d50

File tree

2 files changed

+11
-164
lines changed

2 files changed

+11
-164
lines changed

mpp-ui/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ kotlin {
198198
implementation(project(":mpp-viewer"))
199199
implementation(project(":mpp-viewer-web"))
200200
implementation(project(":xiuper-ui"))
201+
implementation(project(":xiuper-e2e"))
201202
implementation(compose.desktop.currentOs)
202203

203204
// compose.webview for desktop WebView support
Lines changed: 10 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package cc.unitmesh.server.cli
22

3-
import cc.unitmesh.agent.e2etest.planner.PlannerConfig
4-
import cc.unitmesh.agent.e2etest.planner.TestActionPlanner
3+
import cc.unitmesh.e2e.dsl.E2EDslGenerator
4+
import cc.unitmesh.e2e.dsl.E2EDslIntegration
55
import cc.unitmesh.llm.LLMProviderType
66
import cc.unitmesh.llm.LLMService
77
import cc.unitmesh.llm.ModelConfig
@@ -66,18 +66,16 @@ object E2ECli {
6666
println()
6767

6868
val llmService = LLMService.create(modelConfig)
69-
val planner = TestActionPlanner(llmService, PlannerConfig(useDslFormat = true))
69+
val dslIntegration = E2EDslIntegration(llmService)
70+
val dslGenerator = E2EDslGenerator()
7071

71-
println("🧠 Generating E2E test scenario...")
72+
println("🧠 Generating E2E test scenario from description...")
7273
println()
7374

74-
// Create a mock page state for scenario generation
75-
val mockPageState = createMockPageState(targetUrl)
76-
77-
val scenario = planner.generateScenario(
75+
// Generate scenario directly from description - no page state needed
76+
val scenario = dslIntegration.generateScenarioFromDescription(
7877
description = testGoal,
79-
startUrl = targetUrl,
80-
pageState = mockPageState
78+
startUrl = targetUrl
8179
)
8280

8381
val totalTime = System.currentTimeMillis() - startTime
@@ -90,12 +88,12 @@ object E2ECli {
9088
println("=".repeat(80))
9189
println()
9290

93-
val dsl = generateDsl(scenario)
91+
val dsl = dslGenerator.generate(scenario)
9492
println(dsl)
9593

9694
// Save to file if specified
9795
if (outputFile != null) {
98-
java.io.File(outputFile).writeText(dsl)
96+
File(outputFile).writeText(dsl)
9997
println()
10098
println("💾 Saved to: $outputFile")
10199
}
@@ -184,157 +182,5 @@ object E2ECli {
184182
maxTokens = 4096
185183
)
186184
}
187-
188-
/**
189-
* Create a mock page state for scenario generation.
190-
* In a real implementation, this would use Playwright to extract actual page state.
191-
*/
192-
private fun createMockPageState(url: String): cc.unitmesh.agent.e2etest.model.PageState {
193-
val defaultBoundingBox = cc.unitmesh.agent.e2etest.model.BoundingBox(0.0, 0.0, 100.0, 30.0)
194-
195-
fun createFingerprint(selector: String, tagName: String, name: String, role: String) =
196-
cc.unitmesh.agent.e2etest.model.ElementFingerprint(
197-
selector = selector,
198-
tagName = tagName,
199-
textContent = name,
200-
role = role
201-
)
202-
203-
return cc.unitmesh.agent.e2etest.model.PageState(
204-
url = url,
205-
title = "Page at $url",
206-
viewport = cc.unitmesh.agent.e2etest.model.Viewport(1280, 720),
207-
actionableElements = listOf(
208-
// Common elements that might be on a page
209-
cc.unitmesh.agent.e2etest.model.ActionableElement(
210-
tagId = 1,
211-
tagName = "input",
212-
role = "textbox",
213-
name = "username",
214-
selector = "input[name='username']",
215-
isVisible = true,
216-
isEnabled = true,
217-
boundingBox = defaultBoundingBox,
218-
fingerprint = createFingerprint("input[name='username']", "input", "username", "textbox")
219-
),
220-
cc.unitmesh.agent.e2etest.model.ActionableElement(
221-
tagId = 2,
222-
tagName = "input",
223-
role = "textbox",
224-
name = "password",
225-
selector = "input[name='password']",
226-
isVisible = true,
227-
isEnabled = true,
228-
boundingBox = defaultBoundingBox,
229-
fingerprint = createFingerprint("input[name='password']", "input", "password", "textbox")
230-
),
231-
cc.unitmesh.agent.e2etest.model.ActionableElement(
232-
tagId = 3,
233-
tagName = "button",
234-
role = "button",
235-
name = "Login",
236-
selector = "button[type='submit']",
237-
isVisible = true,
238-
isEnabled = true,
239-
boundingBox = defaultBoundingBox,
240-
fingerprint = createFingerprint("button[type='submit']", "button", "Login", "button")
241-
),
242-
cc.unitmesh.agent.e2etest.model.ActionableElement(
243-
tagId = 4,
244-
tagName = "input",
245-
role = "searchbox",
246-
name = "search",
247-
selector = "input[type='search']",
248-
isVisible = true,
249-
isEnabled = true,
250-
boundingBox = defaultBoundingBox,
251-
fingerprint = createFingerprint("input[type='search']", "input", "search", "searchbox")
252-
),
253-
cc.unitmesh.agent.e2etest.model.ActionableElement(
254-
tagId = 5,
255-
tagName = "button",
256-
role = "button",
257-
name = "Search",
258-
selector = "button.search-btn",
259-
isVisible = true,
260-
isEnabled = true,
261-
boundingBox = defaultBoundingBox,
262-
fingerprint = createFingerprint("button.search-btn", "button", "Search", "button")
263-
)
264-
),
265-
capturedAt = System.currentTimeMillis()
266-
)
267-
}
268-
269-
/**
270-
* Generate DSL from a TestScenario
271-
*/
272-
private fun generateDsl(scenario: cc.unitmesh.agent.e2etest.model.TestScenario): String {
273-
return buildString {
274-
appendLine("scenario \"${scenario.name}\" {")
275-
appendLine(" description \"${scenario.description}\"")
276-
appendLine(" url \"${scenario.startUrl}\"")
277-
appendLine()
278-
279-
scenario.steps.forEach { step ->
280-
appendLine(" step \"${step.description}\" {")
281-
appendLine(" ${formatAction(step.action)}")
282-
step.expectedOutcome?.let {
283-
appendLine(" expect \"$it\"")
284-
}
285-
appendLine(" }")
286-
appendLine()
287-
}
288-
289-
appendLine("}")
290-
}
291-
}
292-
293-
private fun formatAction(action: cc.unitmesh.agent.e2etest.model.TestAction): String {
294-
return when (action) {
295-
is cc.unitmesh.agent.e2etest.model.TestAction.Click -> "click #${action.targetId}"
296-
is cc.unitmesh.agent.e2etest.model.TestAction.Type -> "type #${action.targetId} \"${action.text}\""
297-
is cc.unitmesh.agent.e2etest.model.TestAction.Hover -> "hover #${action.targetId}"
298-
is cc.unitmesh.agent.e2etest.model.TestAction.Scroll -> "scroll ${action.direction.name.lowercase()}"
299-
is cc.unitmesh.agent.e2etest.model.TestAction.Wait -> formatWaitAction(action)
300-
is cc.unitmesh.agent.e2etest.model.TestAction.PressKey -> "pressKey \"${action.key}\""
301-
is cc.unitmesh.agent.e2etest.model.TestAction.Navigate -> "navigate \"${action.url}\""
302-
is cc.unitmesh.agent.e2etest.model.TestAction.GoBack -> "goBack"
303-
is cc.unitmesh.agent.e2etest.model.TestAction.GoForward -> "goForward"
304-
is cc.unitmesh.agent.e2etest.model.TestAction.Refresh -> "refresh"
305-
is cc.unitmesh.agent.e2etest.model.TestAction.Assert -> "assert #${action.targetId} ${formatAssertion(action.assertion)}"
306-
is cc.unitmesh.agent.e2etest.model.TestAction.Select -> "select #${action.targetId}"
307-
is cc.unitmesh.agent.e2etest.model.TestAction.UploadFile -> "uploadFile #${action.targetId} \"${action.filePath}\""
308-
is cc.unitmesh.agent.e2etest.model.TestAction.Screenshot -> "screenshot \"${action.name}\""
309-
}
310-
}
311-
312-
private fun formatWaitAction(action: cc.unitmesh.agent.e2etest.model.TestAction.Wait): String {
313-
return when (val condition = action.condition) {
314-
is cc.unitmesh.agent.e2etest.model.WaitCondition.Duration -> "wait duration ${condition.ms}"
315-
is cc.unitmesh.agent.e2etest.model.WaitCondition.ElementVisible -> "wait visible #${condition.targetId}"
316-
is cc.unitmesh.agent.e2etest.model.WaitCondition.ElementHidden -> "wait hidden #${condition.targetId}"
317-
is cc.unitmesh.agent.e2etest.model.WaitCondition.ElementEnabled -> "wait enabled #${condition.targetId}"
318-
is cc.unitmesh.agent.e2etest.model.WaitCondition.TextPresent -> "wait textPresent \"${condition.text}\""
319-
is cc.unitmesh.agent.e2etest.model.WaitCondition.UrlContains -> "wait urlContains \"${condition.substring}\""
320-
is cc.unitmesh.agent.e2etest.model.WaitCondition.PageLoaded -> "wait pageLoaded"
321-
is cc.unitmesh.agent.e2etest.model.WaitCondition.NetworkIdle -> "wait networkIdle"
322-
}
323-
}
324-
325-
private fun formatAssertion(assertion: cc.unitmesh.agent.e2etest.model.AssertionType): String {
326-
return when (assertion) {
327-
is cc.unitmesh.agent.e2etest.model.AssertionType.Visible -> "visible"
328-
is cc.unitmesh.agent.e2etest.model.AssertionType.Hidden -> "hidden"
329-
is cc.unitmesh.agent.e2etest.model.AssertionType.Enabled -> "enabled"
330-
is cc.unitmesh.agent.e2etest.model.AssertionType.Disabled -> "disabled"
331-
is cc.unitmesh.agent.e2etest.model.AssertionType.Checked -> "checked"
332-
is cc.unitmesh.agent.e2etest.model.AssertionType.Unchecked -> "unchecked"
333-
is cc.unitmesh.agent.e2etest.model.AssertionType.TextEquals -> "textEquals \"${assertion.text}\""
334-
is cc.unitmesh.agent.e2etest.model.AssertionType.TextContains -> "textContains \"${assertion.text}\""
335-
is cc.unitmesh.agent.e2etest.model.AssertionType.AttributeEquals -> "attributeEquals \"${assertion.attribute}\" \"${assertion.value}\""
336-
is cc.unitmesh.agent.e2etest.model.AssertionType.HasClass -> "hasClass \"${assertion.className}\""
337-
}
338-
}
339185
}
340186

0 commit comments

Comments
 (0)