wails/v3/internal/commands/task_wrapper_test.go
Lea Anthony 4097aa363b
feat(v3): add -tags flag to wails3 build command (#4968)
Allow users to pass custom build tags via `wails3 build -tags gtk4`
instead of requiring Taskfile modifications. Tags are forwarded as
EXTRA_TAGS to platform Taskfiles and appended to the go build command
alongside the existing production tag.

Works for both native and Docker cross-compilation builds.

Closes #4957

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 18:48:34 +11:00

440 lines
12 KiB
Go

package commands
import (
"os"
"runtime"
"testing"
"github.com/stretchr/testify/assert"
"github.com/wailsapp/wails/v3/internal/flags"
)
func TestWrapTask(t *testing.T) {
// Get current platform info for expected values
currentOS := runtime.GOOS
currentArch := runtime.GOARCH
tests := []struct {
name string
command string
otherArgs []string
envGOOS string
envGOARCH string
expectedTaskName string
expectedArgs []string
expectedOsArgs []string
}{
{
name: "Build with parameters uses current platform",
command: "build",
otherArgs: []string{"CONFIG=debug"},
expectedTaskName: currentOS + ":build",
expectedArgs: []string{"CONFIG=debug", "ARCH=" + currentArch},
expectedOsArgs: []string{"wails3", "task", currentOS + ":build", "CONFIG=debug", "ARCH=" + currentArch},
},
{
name: "Package with parameters uses current platform",
command: "package",
otherArgs: []string{"VERSION=1.0.0", "OUTPUT=app.pkg"},
expectedTaskName: currentOS + ":package",
expectedArgs: []string{"VERSION=1.0.0", "OUTPUT=app.pkg", "ARCH=" + currentArch},
expectedOsArgs: []string{"wails3", "task", currentOS + ":package", "VERSION=1.0.0", "OUTPUT=app.pkg", "ARCH=" + currentArch},
},
{
name: "Build without parameters",
command: "build",
otherArgs: []string{},
expectedTaskName: currentOS + ":build",
expectedArgs: []string{"ARCH=" + currentArch},
expectedOsArgs: []string{"wails3", "task", currentOS + ":build", "ARCH=" + currentArch},
},
{
name: "GOOS override changes task prefix",
command: "build",
otherArgs: []string{"GOOS=darwin", "CONFIG=release"},
expectedTaskName: "darwin:build",
expectedArgs: []string{"CONFIG=release", "ARCH=" + currentArch},
expectedOsArgs: []string{"wails3", "task", "darwin:build", "CONFIG=release", "ARCH=" + currentArch},
},
{
name: "GOARCH override changes ARCH arg",
command: "build",
otherArgs: []string{"GOARCH=arm64"},
expectedTaskName: currentOS + ":build",
expectedArgs: []string{"ARCH=arm64"},
expectedOsArgs: []string{"wails3", "task", currentOS + ":build", "ARCH=arm64"},
},
{
name: "Both GOOS and GOARCH override",
command: "package",
otherArgs: []string{"GOOS=windows", "GOARCH=386", "VERSION=2.0"},
expectedTaskName: "windows:package",
expectedArgs: []string{"VERSION=2.0", "ARCH=386"},
expectedOsArgs: []string{"wails3", "task", "windows:package", "VERSION=2.0", "ARCH=386"},
},
{
name: "Environment GOOS is used when no arg override",
command: "build",
otherArgs: []string{"CONFIG=debug"},
envGOOS: "darwin",
expectedTaskName: "darwin:build",
expectedArgs: []string{"CONFIG=debug", "ARCH=" + currentArch},
expectedOsArgs: []string{"wails3", "task", "darwin:build", "CONFIG=debug", "ARCH=" + currentArch},
},
{
name: "Arg GOOS overrides environment GOOS",
command: "build",
otherArgs: []string{"GOOS=linux"},
envGOOS: "darwin",
expectedTaskName: "linux:build",
expectedArgs: []string{"ARCH=" + currentArch},
expectedOsArgs: []string{"wails3", "task", "linux:build", "ARCH=" + currentArch},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Save and restore os.Args
originalArgs := os.Args
defer func() { os.Args = originalArgs }()
// Save and restore environment variables
originalGOOS := os.Getenv("GOOS")
originalGOARCH := os.Getenv("GOARCH")
defer func() {
if originalGOOS == "" {
os.Unsetenv("GOOS")
} else {
os.Setenv("GOOS", originalGOOS)
}
if originalGOARCH == "" {
os.Unsetenv("GOARCH")
} else {
os.Setenv("GOARCH", originalGOARCH)
}
}()
// Set test environment
if tt.envGOOS != "" {
os.Setenv("GOOS", tt.envGOOS)
} else {
os.Unsetenv("GOOS")
}
if tt.envGOARCH != "" {
os.Setenv("GOARCH", tt.envGOARCH)
} else {
os.Unsetenv("GOARCH")
}
// Mock RunTask to capture the arguments
originalRunTask := runTaskFunc
var capturedOptions *RunTaskOptions
var capturedOtherArgs []string
runTaskFunc = func(options *RunTaskOptions, otherArgs []string) error {
capturedOptions = options
capturedOtherArgs = otherArgs
return nil
}
defer func() { runTaskFunc = originalRunTask }()
// Execute wrapTask
err := wrapTask(tt.command, tt.otherArgs)
assert.NoError(t, err)
// Verify os.Args was set correctly
assert.Equal(t, tt.expectedOsArgs, os.Args)
// Verify RunTask was called with correct parameters
assert.Equal(t, tt.expectedTaskName, capturedOptions.Name)
assert.Equal(t, tt.expectedArgs, capturedOtherArgs)
})
}
}
func TestBuildCommand(t *testing.T) {
currentOS := runtime.GOOS
currentArch := runtime.GOARCH
// Save original RunTask
originalRunTask := runTaskFunc
defer func() { runTaskFunc = originalRunTask }()
// Mock RunTask to capture the arguments
var capturedOptions *RunTaskOptions
var capturedOtherArgs []string
runTaskFunc = func(options *RunTaskOptions, otherArgs []string) error {
capturedOptions = options
capturedOtherArgs = otherArgs
return nil
}
// Save original os.Args and environment
originalArgs := os.Args
defer func() { os.Args = originalArgs }()
originalGOOS := os.Getenv("GOOS")
originalGOARCH := os.Getenv("GOARCH")
defer func() {
if originalGOOS == "" {
os.Unsetenv("GOOS")
} else {
os.Setenv("GOOS", originalGOOS)
}
if originalGOARCH == "" {
os.Unsetenv("GOARCH")
} else {
os.Setenv("GOARCH", originalGOARCH)
}
}()
os.Unsetenv("GOOS")
os.Unsetenv("GOARCH")
// Test Build command
buildFlags := &flags.Build{}
otherArgs := []string{"CONFIG=release"}
err := Build(buildFlags, otherArgs)
assert.NoError(t, err)
assert.Equal(t, currentOS+":build", capturedOptions.Name)
assert.Equal(t, []string{"CONFIG=release", "ARCH=" + currentArch}, capturedOtherArgs)
}
func TestBuildCommandWithTags(t *testing.T) {
currentOS := runtime.GOOS
currentArch := runtime.GOARCH
// Save original RunTask
originalRunTask := runTaskFunc
defer func() { runTaskFunc = originalRunTask }()
// Mock RunTask to capture the arguments
var capturedOptions *RunTaskOptions
var capturedOtherArgs []string
runTaskFunc = func(options *RunTaskOptions, otherArgs []string) error {
capturedOptions = options
capturedOtherArgs = otherArgs
return nil
}
// Save original os.Args and environment
originalArgs := os.Args
defer func() { os.Args = originalArgs }()
originalGOOS := os.Getenv("GOOS")
originalGOARCH := os.Getenv("GOARCH")
defer func() {
if originalGOOS == "" {
os.Unsetenv("GOOS")
} else {
os.Setenv("GOOS", originalGOOS)
}
if originalGOARCH == "" {
os.Unsetenv("GOARCH")
} else {
os.Setenv("GOARCH", originalGOARCH)
}
}()
os.Unsetenv("GOOS")
os.Unsetenv("GOARCH")
// Test Build command with tags
buildFlags := &flags.Build{}
buildFlags.Tags = "gtk4"
otherArgs := []string{"CONFIG=release"}
err := Build(buildFlags, otherArgs)
assert.NoError(t, err)
assert.Equal(t, currentOS+":build", capturedOptions.Name)
assert.Equal(t, []string{"CONFIG=release", "EXTRA_TAGS=gtk4", "ARCH=" + currentArch}, capturedOtherArgs)
}
func TestBuildCommandWithMultipleTags(t *testing.T) {
currentOS := runtime.GOOS
currentArch := runtime.GOARCH
// Save original RunTask
originalRunTask := runTaskFunc
defer func() { runTaskFunc = originalRunTask }()
// Mock RunTask to capture the arguments
var capturedOptions *RunTaskOptions
var capturedOtherArgs []string
runTaskFunc = func(options *RunTaskOptions, otherArgs []string) error {
capturedOptions = options
capturedOtherArgs = otherArgs
return nil
}
// Save original os.Args and environment
originalArgs := os.Args
defer func() { os.Args = originalArgs }()
originalGOOS := os.Getenv("GOOS")
originalGOARCH := os.Getenv("GOARCH")
defer func() {
if originalGOOS == "" {
os.Unsetenv("GOOS")
} else {
os.Setenv("GOOS", originalGOOS)
}
if originalGOARCH == "" {
os.Unsetenv("GOARCH")
} else {
os.Setenv("GOARCH", originalGOARCH)
}
}()
os.Unsetenv("GOOS")
os.Unsetenv("GOARCH")
// Test Build command with multiple comma-separated tags
buildFlags := &flags.Build{}
buildFlags.Tags = "gtk4,server"
err := Build(buildFlags, nil)
assert.NoError(t, err)
assert.Equal(t, currentOS+":build", capturedOptions.Name)
assert.Equal(t, []string{"EXTRA_TAGS=gtk4,server", "ARCH=" + currentArch}, capturedOtherArgs)
}
func TestBuildCommandWithoutTags(t *testing.T) {
currentOS := runtime.GOOS
currentArch := runtime.GOARCH
// Save original RunTask
originalRunTask := runTaskFunc
defer func() { runTaskFunc = originalRunTask }()
// Mock RunTask to capture the arguments
var capturedOptions *RunTaskOptions
var capturedOtherArgs []string
runTaskFunc = func(options *RunTaskOptions, otherArgs []string) error {
capturedOptions = options
capturedOtherArgs = otherArgs
return nil
}
// Save original os.Args and environment
originalArgs := os.Args
defer func() { os.Args = originalArgs }()
originalGOOS := os.Getenv("GOOS")
originalGOARCH := os.Getenv("GOARCH")
defer func() {
if originalGOOS == "" {
os.Unsetenv("GOOS")
} else {
os.Setenv("GOOS", originalGOOS)
}
if originalGOARCH == "" {
os.Unsetenv("GOARCH")
} else {
os.Setenv("GOARCH", originalGOARCH)
}
}()
os.Unsetenv("GOOS")
os.Unsetenv("GOARCH")
// Test Build command without tags - no EXTRA_TAGS should be present
buildFlags := &flags.Build{}
err := Build(buildFlags, nil)
assert.NoError(t, err)
assert.Equal(t, currentOS+":build", capturedOptions.Name)
assert.Equal(t, []string{"ARCH=" + currentArch}, capturedOtherArgs)
}
func TestPackageCommand(t *testing.T) {
currentOS := runtime.GOOS
currentArch := runtime.GOARCH
// Save original RunTask
originalRunTask := runTaskFunc
defer func() { runTaskFunc = originalRunTask }()
// Mock RunTask to capture the arguments
var capturedOptions *RunTaskOptions
var capturedOtherArgs []string
runTaskFunc = func(options *RunTaskOptions, otherArgs []string) error {
capturedOptions = options
capturedOtherArgs = otherArgs
return nil
}
// Save original os.Args and environment
originalArgs := os.Args
defer func() { os.Args = originalArgs }()
originalGOOS := os.Getenv("GOOS")
originalGOARCH := os.Getenv("GOARCH")
defer func() {
if originalGOOS == "" {
os.Unsetenv("GOOS")
} else {
os.Setenv("GOOS", originalGOOS)
}
if originalGOARCH == "" {
os.Unsetenv("GOARCH")
} else {
os.Setenv("GOARCH", originalGOARCH)
}
}()
os.Unsetenv("GOOS")
os.Unsetenv("GOARCH")
// Test Package command
packageFlags := &flags.Package{}
otherArgs := []string{"VERSION=2.0.0", "OUTPUT=myapp.dmg"}
err := Package(packageFlags, otherArgs)
assert.NoError(t, err)
assert.Equal(t, currentOS+":package", capturedOptions.Name)
assert.Equal(t, []string{"VERSION=2.0.0", "OUTPUT=myapp.dmg", "ARCH=" + currentArch}, capturedOtherArgs)
}
func TestSignWrapperCommand(t *testing.T) {
currentOS := runtime.GOOS
currentArch := runtime.GOARCH
// Save original RunTask
originalRunTask := runTaskFunc
defer func() { runTaskFunc = originalRunTask }()
// Mock RunTask to capture the arguments
var capturedOptions *RunTaskOptions
var capturedOtherArgs []string
runTaskFunc = func(options *RunTaskOptions, otherArgs []string) error {
capturedOptions = options
capturedOtherArgs = otherArgs
return nil
}
// Save original os.Args and environment
originalArgs := os.Args
defer func() { os.Args = originalArgs }()
originalGOOS := os.Getenv("GOOS")
originalGOARCH := os.Getenv("GOARCH")
defer func() {
if originalGOOS == "" {
os.Unsetenv("GOOS")
} else {
os.Setenv("GOOS", originalGOOS)
}
if originalGOARCH == "" {
os.Unsetenv("GOARCH")
} else {
os.Setenv("GOARCH", originalGOARCH)
}
}()
os.Unsetenv("GOOS")
os.Unsetenv("GOARCH")
// Test SignWrapper command
signFlags := &flags.SignWrapper{}
otherArgs := []string{"IDENTITY=Developer ID"}
err := SignWrapper(signFlags, otherArgs)
assert.NoError(t, err)
assert.Equal(t, currentOS+":sign", capturedOptions.Name)
assert.Equal(t, []string{"IDENTITY=Developer ID", "ARCH=" + currentArch}, capturedOtherArgs)
}