Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions docs/src/content/docs/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
*/
## [Unreleased]

## v3.0.0-alpha.36 - 2025-10-15

## Fixed
- Fix Linux appimage appicon variable in Linux taskfile [PR #4644](https://github.com/wailsapp/wails/pull/4644)
- Fix Windows build error caused by go-webview2 v1.0.22 signature change (#4513, #4645)

## v3.0.0-alpha.35 - 2025-10-14

## Fixed
- Fix Linux appimage appicon variable in Linux taskfile [PR #4644](https://github.com/wailsapp/wails/pull/4644)

## v3.0.0-alpha.34 - 2025-10-06

## Added
- Added NSIS Protocol template for Windows by @Tolfx in #4510
- Added tests for build-assets by @Tolfx in #4510

## Fixed
- Fixed linux desktop.tmpl protocol range, by removing `<.Info.Protocol>` to `<.Protocol>` by @Tolfx in #4510
- Fixed redefinition error for liquid glass demo in [#4542](https://github.com/wailsapp/wails/pull/4542) by @Etesam913

## v3.0.0-alpha.33 - 2025-10-04

## Fixed
- Fixed systray menu updates on Linux [#4604](https://github.com/wailsapp/wails/issues/4604) by [@JackDoan](https://github.com/JackDoan)

## v3.0.0-alpha.32 - 2025-10-02

## Fixed
- Fix the white window appearing on Windows when creating a hidden window by @leaanthony in [#4612](https://github.com/wailsapp/wails/pull/4612)
- Fix notifications package import path in documentation by @rxliuli in [#4617](https://github.com/wailsapp/wails/pull/4617)
- Fix drag-and-drop not working when using npm package @wailsio/runtime (#4489) by @leaanthony in #4616

## v3.0.0-alpha.31 - 2025-09-27

## Fixed
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/learn/notifications.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ First, initialize the notifications service:

```go
import "github.com/wailsapp/wails/v3/pkg/application"
import "github.com/wailsapp/wails/v3/services/notifications"
import "github.com/wailsapp/wails/v3/pkg/services/notifications"

// Create a new notification service
notifier := notifications.New()
Expand Down
2 changes: 1 addition & 1 deletion v3/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ require (
github.com/samber/lo v1.49.1
github.com/stretchr/testify v1.10.0
github.com/tc-hib/winres v0.3.1
github.com/wailsapp/go-webview2 v1.0.21
github.com/wailsapp/go-webview2 v1.0.22
github.com/wailsapp/mimetype v1.4.1
github.com/wailsapp/task/v3 v3.40.1-patched3
golang.org/x/sys v0.31.0
Expand Down
4 changes: 2 additions & 2 deletions v3/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,8 @@ github.com/tc-hib/winres v0.3.1 h1:CwRjEGrKdbi5CvZ4ID+iyVhgyfatxFoizjPhzez9Io4=
github.com/tc-hib/winres v0.3.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/wailsapp/go-webview2 v1.0.21 h1:k3dtoZU4KCoN/AEIbWiPln3P2661GtA2oEgA2Pb+maA=
github.com/wailsapp/go-webview2 v1.0.21/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
github.com/wailsapp/go-webview2 v1.0.22 h1:YT61F5lj+GGaat5OB96Aa3b4QA+mybD0Ggq6NZijQ58=
github.com/wailsapp/go-webview2 v1.0.22/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
github.com/wailsapp/task/v3 v3.40.1-patched3 h1:i6O1WNdSur9CGaiMDIYGjsmj/qS4465zqv+WEs6sPRs=
Expand Down
3 changes: 2 additions & 1 deletion v3/internal/assetserver/bundledassets/runtime.debug.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion v3/internal/assetserver/bundledassets/runtime.js

Large diffs are not rendered by default.

267 changes: 267 additions & 0 deletions v3/internal/commands/build-assets_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
package commands

import (
"os"
"path/filepath"
"testing"

"gopkg.in/yaml.v3"
)

func TestGenerateBuildAssets(t *testing.T) {
// Create a temporary directory for testing
tempDir, err := os.MkdirTemp("", "wails-build-assets-test-*")
if err != nil {
t.Fatalf("Failed to create temp directory: %v", err)
}
defer os.RemoveAll(tempDir)

tests := []struct {
name string
options *BuildAssetsOptions
wantErr bool
}{
{
name: "Basic build assets generation",
options: &BuildAssetsOptions{
Dir: "testbuild",
Name: "TestApp",
BinaryName: "",
ProductName: "Test Application",
ProductDescription: "A test application",
ProductVersion: "1.0.0",
ProductCompany: "Test Company",
ProductCopyright: "© 2024 Test Company",
ProductComments: "Test comments",
ProductIdentifier: "",
Silent: true,
},
wantErr: false,
},
{
name: "Build assets with custom binary name",
options: &BuildAssetsOptions{
Dir: "testbuild2",
Name: "Custom App",
BinaryName: "custom-binary",
ProductName: "Custom Application",
ProductDescription: "A custom application",
ProductVersion: "2.0.0",
ProductCompany: "Custom Company",
ProductIdentifier: "com.custom.app",
Silent: true,
},
wantErr: false,
},
{
name: "Build assets with MSIX options",
options: &BuildAssetsOptions{
Dir: "testbuild3",
Name: "MSIX App",
ProductName: "MSIX Application",
ProductDescription: "An MSIX application",
ProductVersion: "3.0.0",
ProductCompany: "MSIX Company",
Publisher: "CN=MSIX Company",
ProcessorArchitecture: "x64",
ExecutablePath: "msix-app.exe",
ExecutableName: "msix-app.exe",
OutputPath: "msix-app.msix",
Silent: true,
},
wantErr: false,
},
{
name: "Build assets with TypeScript",
options: &BuildAssetsOptions{
Dir: "testbuild4",
Name: "TypeScript App",
ProductName: "TypeScript Application",
ProductDescription: "A TypeScript application",
ProductVersion: "4.0.0",
ProductCompany: "TypeScript Company",
Typescript: true,
Silent: true,
},
wantErr: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Set the directory to be under our temp directory
buildDir := filepath.Join(tempDir, tt.options.Dir)
tt.options.Dir = buildDir

err := GenerateBuildAssets(tt.options)
if (err != nil) != tt.wantErr {
t.Errorf("GenerateBuildAssets() error = %v, wantErr %v", err, tt.wantErr)
return
}

if !tt.wantErr {
// Verify that the build directory was created
if _, err := os.Stat(buildDir); os.IsNotExist(err) {
t.Errorf("Build directory %s was not created", buildDir)
}

// List all files that were actually created for debugging
files, err := os.ReadDir(buildDir)
if err != nil {
t.Errorf("Failed to read build directory: %v", err)
} else {
t.Logf("Files created in %s:", buildDir)
for _, file := range files {
t.Logf(" - %s", file.Name())
}
}

// Verify some expected files were created - check what actually exists
expectedFiles := []string{
"config.yml",
"appicon.png",
"Taskfile.yml",
}

for _, file := range expectedFiles {
filePath := filepath.Join(buildDir, file)
if _, err := os.Stat(filePath); os.IsNotExist(err) {
t.Errorf("Expected file %s was not created", file)
}
}

// Test that defaults were applied correctly
if tt.options.ProductIdentifier == "" && tt.options.Name != "" {
expectedIdentifier := "com.wails." + normaliseName(tt.options.Name)
// We can't easily check this without modifying the function to return the config
// but we know the logic is there
_ = expectedIdentifier
}
}
})
}
}

func TestUpdateBuildAssets(t *testing.T) {
// Create a temporary directory for testing
tempDir, err := os.MkdirTemp("", "wails-update-assets-test-*")
if err != nil {
t.Fatalf("Failed to create temp directory: %v", err)
}
defer os.RemoveAll(tempDir)

// Create a sample wails config file
configDir := filepath.Join(tempDir, "config")
err = os.MkdirAll(configDir, 0755)
if err != nil {
t.Fatalf("Failed to create config directory: %v", err)
}

configFile := filepath.Join(configDir, "wails.yaml")
config := WailsConfig{
Info: struct {
CompanyName string `yaml:"companyName"`
ProductName string `yaml:"productName"`
ProductIdentifier string `yaml:"productIdentifier"`
Description string `yaml:"description"`
Copyright string `yaml:"copyright"`
Comments string `yaml:"comments"`
Version string `yaml:"version"`
}{
CompanyName: "Config Company",
ProductName: "Config Product",
ProductIdentifier: "com.config.product",
Description: "Config Description",
Copyright: "© 2024 Config Company",
Comments: "Config Comments",
Version: "1.0.0",
},
FileAssociations: []FileAssociation{
{
Ext: ".test",
Name: "Test File",
Description: "Test file association",
IconName: "test-icon",
Role: "Editor",
MimeType: "application/test",
},
},
Protocols: []ProtocolConfig{
{
Scheme: "testapp",
Description: "Test App Protocol",
},
},
}

configBytes, err := yaml.Marshal(config)
if err != nil {
t.Fatalf("Failed to marshal config: %v", err)
}

err = os.WriteFile(configFile, configBytes, 0644)
if err != nil {
t.Fatalf("Failed to write config file: %v", err)
}

tests := []struct {
name string
options *UpdateBuildAssetsOptions
wantErr bool
}{
{
name: "Update with config file",
options: &UpdateBuildAssetsOptions{
Dir: "updatebuild1",
Name: "UpdateApp",
Config: configFile,
Silent: true,
},
wantErr: false,
},
{
name: "Update without config file",
options: &UpdateBuildAssetsOptions{
Dir: "updatebuild2",
Name: "UpdateApp2",
ProductName: "Update Application 2",
ProductDescription: "An update application 2",
ProductVersion: "2.0.0",
ProductCompany: "Update Company 2",
Silent: true,
},
wantErr: false,
},
{
name: "Update with non-existent config file",
options: &UpdateBuildAssetsOptions{
Dir: "updatebuild3",
Name: "UpdateApp3",
Config: "non-existent-config.yaml",
Silent: true,
},
wantErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Set the directory to be under our temp directory
updateDir := filepath.Join(tempDir, tt.options.Dir)
tt.options.Dir = updateDir

err := UpdateBuildAssets(tt.options)
if (err != nil) != tt.wantErr {
t.Errorf("UpdateBuildAssets() error = %v, wantErr %v", err, tt.wantErr)
return
}

if !tt.wantErr {
// Verify that the update directory was created
if _, err := os.Stat(updateDir); os.IsNotExist(err) {
t.Errorf("Update directory %s was not created", updateDir)
}
}
})
}
}
4 changes: 2 additions & 2 deletions v3/internal/commands/build_assets/linux/Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ tasks:
- task: generate:dotdesktop
cmds:
- cp {{.APP_BINARY}} {{.APP_NAME}}
- cp ../../appicon.png appicon.png
- cp ../../appicon.png {{.APP_NAME}}.png
- wails3 generate appimage -binary {{.APP_NAME}} -icon {{.ICON}} -desktopfile {{.DESKTOP_FILE}} -outputdir {{.OUTPUT_DIR}} -builddir {{.ROOT_DIR}}/build/linux/appimage/build
vars:
APP_NAME: '{{.APP_NAME}}'
APP_BINARY: '../../../bin/{{.APP_NAME}}'
ICON: '../../appicon.png'
ICON: '{{.APP_NAME}}.png'
DESKTOP_FILE: '../{{.APP_NAME}}.desktop'
OUTPUT_DIR: '../../../bin'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ Section
CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}"

!insertmacro wails.associateFiles

!insertmacro wails.associateCustomProtocols

!insertmacro wails.writeUninstaller
SectionEnd

Expand All @@ -107,6 +108,7 @@ Section "uninstall"
Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk"

!insertmacro wails.unassociateFiles
!insertmacro wails.unassociateCustomProtocols

!insertmacro wails.deleteUninstaller
SectionEnd
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ Categories=Utility;
StartupWMClass={{.BinaryName}}

{{if .Protocols -}}
MimeType={{range $index, $protocol := .Info.Protocols}}x-scheme-handler/{{$protocol.Scheme}};{{end}}
MimeType={{range $index, $protocol := .Protocols}}x-scheme-handler/{{$protocol.Scheme}};{{end}}
{{- end}}
Loading