mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-07 09:00:47 +00:00
123 lines
4.1 KiB
Go
123 lines
4.1 KiB
Go
package download
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/GopeedLab/gopeed/pkg/base"
|
|
"github.com/GopeedLab/gopeed/pkg/download/engine"
|
|
wv "github.com/GopeedLab/gopeed/pkg/download/engine/webview"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type eventTestPage struct {
|
|
fakeRuntimeWebViewPage
|
|
wv.EventHub
|
|
}
|
|
|
|
func (p *eventTestPage) Close() error {
|
|
p.Emit(wv.Event{Name: "closed", Data: map[string]any{"reason": "api"}})
|
|
return nil
|
|
}
|
|
|
|
type eventTestOpener struct{ page wv.Page }
|
|
|
|
func (o eventTestOpener) Open(wv.OpenOptions) (wv.Page, error) { return o.page, nil }
|
|
|
|
func TestExtensionHostEnv(t *testing.T) {
|
|
e := engine.NewEngine(nil)
|
|
defer e.Close()
|
|
info := NewExtensionInfo(&Extension{Name: "sample", Author: "test", Version: "1.2.3"})
|
|
if err := injectGopeed(e.Runtime, &Instance{Info: info}, e.Post); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
result, err := e.RunString(`gopeed.host.env.version + "/" + gopeed.info.version + "/" + gopeed.host.env.os + "/" + gopeed.host.env.arch`)
|
|
if err != nil || result != base.Version+"/1.2.3/"+runtime.GOOS+"/"+runtime.GOARCH {
|
|
t.Fatalf("%v %v", result, err)
|
|
}
|
|
result, err = e.RunString(`["hostVersion", "os", "arch"].some(key => key in gopeed.info)`)
|
|
if err != nil || result != false {
|
|
t.Fatalf("host metadata retained in extension info: %v %v", result, err)
|
|
}
|
|
}
|
|
|
|
func TestExtensionWebViewEvents(t *testing.T) {
|
|
e := engine.NewEngine(nil)
|
|
defer e.Close()
|
|
page := &eventTestPage{}
|
|
runtime := wv.NewRuntime(eventTestOpener{page}, true)
|
|
defer runtime.Close()
|
|
if err := injectGopeed(e.Runtime, &Instance{Runtime: &InstanceRuntime{WebView: runtime}}, e.Post); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, err := e.RunString(`var page = gopeed.runtime.webview.open(); var seen = []; var off;
|
|
(async () => {
|
|
const registered = page.on("load", () => { seen.push("load"); return new Promise(() => {}); });
|
|
if (!(registered instanceof Promise)) throw new Error("on must return a Promise");
|
|
off = await registered;
|
|
await page.on("closed", data => seen.push(data.reason));
|
|
for (const args of [["invalid", () => {}], ["load", 1]]) {
|
|
let rejected = false;
|
|
try { await page.on(...args); } catch (_) { rejected = true; }
|
|
if (!rejected) throw new Error("invalid listener accepted");
|
|
}
|
|
})()`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
page.Emit(wv.Event{Name: "load", Data: map[string]any{"url": "https://example.test"}})
|
|
result, err := e.RunString(`off(); off(); seen.join(",")`)
|
|
if err != nil || result != "load" {
|
|
t.Fatalf("%v %v", result, err)
|
|
}
|
|
page.Emit(wv.Event{Name: "load"})
|
|
if _, err = e.RunString(`page.close()`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
result, err = e.RunString(`seen.join(",")`)
|
|
if err != nil || result != "load,api" {
|
|
t.Fatalf("%v %v", result, err)
|
|
}
|
|
}
|
|
|
|
// Navigation must not occupy the Goja loop: a notification can execute page
|
|
// operations even while the original goto promise is still pending.
|
|
type navigationEventTestPage struct {
|
|
eventTestPage
|
|
release chan struct{}
|
|
}
|
|
|
|
func (p *navigationEventTestPage) Goto(url string, _ wv.GotoOptions) error {
|
|
p.Emit(wv.Event{Name: "load", Data: map[string]any{"url": url}})
|
|
select {
|
|
case <-p.release:
|
|
return nil
|
|
case <-time.After(2 * time.Second):
|
|
return fmt.Errorf("event callback blocked by navigation")
|
|
}
|
|
}
|
|
func (p *navigationEventTestPage) Execute(string, ...any) (any, error) {
|
|
close(p.release)
|
|
return nil, nil
|
|
}
|
|
func TestExtensionWebViewEventsDuringNavigation(t *testing.T) {
|
|
e := engine.NewEngine(nil)
|
|
defer e.Close()
|
|
page := &navigationEventTestPage{release: make(chan struct{})}
|
|
runtime := wv.NewRuntime(eventTestOpener{page}, true)
|
|
defer runtime.Close()
|
|
if err := injectGopeed(e.Runtime, &Instance{Runtime: &InstanceRuntime{WebView: runtime}}, e.Post); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
result, err := e.RunString(`(async () => {
|
|
const page = await gopeed.runtime.webview.open();
|
|
await page.on("load", () => page.execute("release"));
|
|
if (await page.addInitScript("globalThis.ready = true") !== undefined) throw new Error("init result must be void");
|
|
if (await page.goto("https://example.test") !== undefined) throw new Error("goto result must be void");
|
|
return true;
|
|
})()`)
|
|
if err != nil || result != true {
|
|
t.Fatalf("%v %v", result, err)
|
|
}
|
|
}
|