- Registered new "opencode" and "opencode/cli" runners in the sandbox initialization. - Updated the `runExecStep` function to use the computer's working directory and set the HOME environment variable. - Refactored attachment processing in the Claude package to delegate to shared functionality, improving code maintainability.
362 lines
8.2 KiB
Go
362 lines
8.2 KiB
Go
package test_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/yaoapp/gou/application"
|
|
"github.com/yaoapp/yao/config"
|
|
"github.com/yaoapp/yao/engine"
|
|
"github.com/yaoapp/yao/sui/core"
|
|
suitest "github.com/yaoapp/yao/sui/test"
|
|
"github.com/yaoapp/yao/test"
|
|
)
|
|
|
|
func prepare(t *testing.T) {
|
|
t.Helper()
|
|
test.Prepare(t, config.Conf)
|
|
_, err := engine.Load(config.Conf, engine.LoadOption{Action: "sui.test"})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func requireAgentSUI(t *testing.T) {
|
|
t.Helper()
|
|
_, has := core.SUIs["agent"]
|
|
if !has {
|
|
t.Skip("no 'agent' SUI loaded")
|
|
}
|
|
}
|
|
|
|
// --- happy path (dashboard page: 4 pass) ---
|
|
|
|
func TestDiscoverPageTests(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
requireAgentSUI(t)
|
|
|
|
opts := &suitest.Options{
|
|
SUIID: "agent",
|
|
Template: "agent",
|
|
Page: "tests.sui-pages/dashboard",
|
|
JSON: true,
|
|
}
|
|
|
|
runner, err := suitest.NewRunner(opts)
|
|
require.NoError(t, err)
|
|
|
|
report, err := runner.Run()
|
|
require.NoError(t, err)
|
|
require.NotNil(t, report)
|
|
|
|
assert.Greater(t, report.Summary.Total, 0)
|
|
assert.Greater(t, len(report.Pages), 0)
|
|
}
|
|
|
|
func TestRunnerExecuteTests(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
requireAgentSUI(t)
|
|
|
|
opts := &suitest.Options{
|
|
SUIID: "agent",
|
|
Template: "agent",
|
|
Page: "tests.sui-pages/dashboard",
|
|
JSON: true,
|
|
}
|
|
|
|
runner, err := suitest.NewRunner(opts)
|
|
require.NoError(t, err)
|
|
|
|
report, err := runner.Run()
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, "sui_backend_test", report.Type)
|
|
assert.False(t, report.Metadata.StartedAt.IsZero())
|
|
assert.False(t, report.Metadata.CompletedAt.IsZero())
|
|
assert.Equal(t, 4, report.Summary.Total)
|
|
assert.Equal(t, 4, report.Summary.Passed)
|
|
assert.Equal(t, 0, report.Summary.Failed)
|
|
assert.False(t, report.HasFailures())
|
|
}
|
|
|
|
func TestRunnerWithRunFilter(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
requireAgentSUI(t)
|
|
|
|
opts := &suitest.Options{
|
|
SUIID: "agent",
|
|
Template: "agent",
|
|
Page: "tests.sui-pages/dashboard",
|
|
Run: "TestGetDashboard",
|
|
JSON: true,
|
|
}
|
|
|
|
runner, err := suitest.NewRunner(opts)
|
|
require.NoError(t, err)
|
|
|
|
report, err := runner.Run()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 1, report.Summary.Total)
|
|
assert.Equal(t, 1, report.Summary.Passed)
|
|
}
|
|
|
|
func TestRunnerFailFast(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
requireAgentSUI(t)
|
|
|
|
opts := &suitest.Options{
|
|
SUIID: "agent",
|
|
Template: "agent",
|
|
Page: "tests.sui-pages/dashboard",
|
|
FailFast: true,
|
|
JSON: true,
|
|
}
|
|
|
|
runner, err := suitest.NewRunner(opts)
|
|
require.NoError(t, err)
|
|
|
|
report, err := runner.Run()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 0, report.Summary.Failed)
|
|
}
|
|
|
|
// --- errors page: covers fail, skip, setAuthorized, reset ---
|
|
|
|
func TestRunnerWithFailAndSkip(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
requireAgentSUI(t)
|
|
|
|
opts := &suitest.Options{
|
|
SUIID: "agent",
|
|
Template: "agent",
|
|
Page: "tests.sui-pages/errors",
|
|
JSON: true,
|
|
}
|
|
|
|
runner, err := suitest.NewRunner(opts)
|
|
require.NoError(t, err)
|
|
|
|
report, err := runner.Run()
|
|
require.NoError(t, err)
|
|
require.NotNil(t, report)
|
|
|
|
assert.Equal(t, 6, report.Summary.Total)
|
|
assert.Equal(t, 2, report.Summary.Failed, "TestAlwaysFail + TestRuntimeError should fail")
|
|
assert.Equal(t, 1, report.Summary.Skipped, "TestAlwaysSkip should be skipped")
|
|
assert.Equal(t, 3, report.Summary.Passed)
|
|
assert.True(t, report.HasFailures())
|
|
|
|
page := report.Pages[0]
|
|
for _, r := range page.Results {
|
|
switch r.Name {
|
|
case "TestAlwaysFail":
|
|
assert.Equal(t, "failed", r.Status)
|
|
assert.NotEmpty(t, r.Error)
|
|
case "TestAlwaysSkip":
|
|
assert.Equal(t, "skipped", r.Status)
|
|
case "TestSetAuthorizedAndReset":
|
|
assert.Equal(t, "passed", r.Status)
|
|
case "TestCallWithRequestRender":
|
|
assert.Equal(t, "passed", r.Status)
|
|
case "TestCallNonExistentMethod":
|
|
assert.Equal(t, "passed", r.Status)
|
|
case "TestRuntimeError":
|
|
assert.Equal(t, "error", r.Status)
|
|
assert.Contains(t, r.Error, "deliberate execution error")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRunnerFailFastStopsOnError(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
requireAgentSUI(t)
|
|
|
|
opts := &suitest.Options{
|
|
SUIID: "agent",
|
|
Template: "agent",
|
|
Page: "tests.sui-pages/errors",
|
|
FailFast: true,
|
|
JSON: true,
|
|
}
|
|
|
|
runner, err := suitest.NewRunner(opts)
|
|
require.NoError(t, err)
|
|
|
|
report, err := runner.Run()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 1, report.Summary.Failed)
|
|
// fail-fast: executed only up to the first failure
|
|
executed := report.Summary.Passed + report.Summary.Failed + report.Summary.Skipped
|
|
assert.Less(t, executed, report.Summary.Total, "fail-fast should stop before running all tests")
|
|
}
|
|
|
|
// --- verbose (non-JSON) output: covers printHeader, printTestResult, printSummary ---
|
|
|
|
func TestRunnerVerboseAllPass(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
requireAgentSUI(t)
|
|
|
|
opts := &suitest.Options{
|
|
SUIID: "agent",
|
|
Template: "agent",
|
|
Page: "tests.sui-pages/dashboard",
|
|
Verbose: true,
|
|
JSON: false,
|
|
}
|
|
|
|
runner, err := suitest.NewRunner(opts)
|
|
require.NoError(t, err)
|
|
|
|
report, err := runner.Run()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 4, report.Summary.Passed)
|
|
}
|
|
|
|
func TestRunnerVerboseWithFailures(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
requireAgentSUI(t)
|
|
|
|
opts := &suitest.Options{
|
|
SUIID: "agent",
|
|
Template: "agent",
|
|
Page: "tests.sui-pages/errors",
|
|
Verbose: true,
|
|
JSON: false,
|
|
}
|
|
|
|
runner, err := suitest.NewRunner(opts)
|
|
require.NoError(t, err)
|
|
|
|
report, err := runner.Run()
|
|
require.NoError(t, err)
|
|
assert.Greater(t, report.Summary.Failed, 0)
|
|
}
|
|
|
|
func TestRunnerVerboseWithData(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
requireAgentSUI(t)
|
|
|
|
opts := &suitest.Options{
|
|
SUIID: "agent",
|
|
Template: "agent",
|
|
Page: "tests.sui-pages/dashboard",
|
|
Data: `{"key":"value"}`,
|
|
Verbose: true,
|
|
JSON: false,
|
|
}
|
|
|
|
runner, err := suitest.NewRunner(opts)
|
|
require.NoError(t, err)
|
|
|
|
report, err := runner.Run()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 4, report.Summary.Passed)
|
|
}
|
|
|
|
// --- error paths ---
|
|
|
|
func TestNewRunnerInvalidSUI(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
|
|
_, err := suitest.NewRunner(&suitest.Options{SUIID: "nonexistent", Template: "default"})
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "not found")
|
|
}
|
|
|
|
func TestNewRunnerInvalidTemplate(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
requireAgentSUI(t)
|
|
|
|
_, err := suitest.NewRunner(&suitest.Options{SUIID: "agent", Template: "nonexistent-tmpl"})
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestRunnerNoMatchingPage(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
requireAgentSUI(t)
|
|
|
|
runner, err := suitest.NewRunner(&suitest.Options{
|
|
SUIID: "agent", Template: "agent", Page: "xyz-no-match", JSON: true,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
report, err := runner.Run()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 0, report.Summary.Total)
|
|
}
|
|
|
|
func TestRunnerNoMatchingRun(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
requireAgentSUI(t)
|
|
|
|
runner, err := suitest.NewRunner(&suitest.Options{
|
|
SUIID: "agent", Template: "agent", Page: "tests.sui-pages/dashboard",
|
|
Run: "NoSuchFunction", JSON: true,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
report, err := runner.Run()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 0, report.Summary.Total)
|
|
}
|
|
|
|
func TestRunnerVerboseNoTestFiles(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
requireAgentSUI(t)
|
|
|
|
runner, err := suitest.NewRunner(&suitest.Options{
|
|
SUIID: "agent", Template: "agent", Page: "xyz-no-match", JSON: false,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
report, err := runner.Run()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 0, report.Summary.Total)
|
|
}
|
|
|
|
// --- types ---
|
|
|
|
func TestLoadPageConfig(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
|
|
cfgFile := "assistants/tests/sui-pages/pages/dashboard/dashboard.config"
|
|
exists, _ := application.App.Exists(cfgFile)
|
|
if !exists {
|
|
t.Skipf("test config %s not found", cfgFile)
|
|
}
|
|
|
|
cfg, err := suitest.LoadPageConfig(cfgFile)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, cfg)
|
|
assert.Equal(t, "Test Dashboard", cfg.Title)
|
|
}
|
|
|
|
func TestLoadPageConfigNotExist(t *testing.T) {
|
|
prepare(t)
|
|
defer test.Clean()
|
|
|
|
cfg, err := suitest.LoadPageConfig("nonexistent/path.config")
|
|
assert.NoError(t, err)
|
|
assert.Nil(t, cfg)
|
|
}
|
|
|
|
func TestReportHasFailures(t *testing.T) {
|
|
r := &suitest.Report{Summary: &suitest.TestSummary{Failed: 1}}
|
|
assert.True(t, r.HasFailures())
|
|
r.Summary.Failed = 0
|
|
assert.False(t, r.HasFailures())
|
|
}
|