mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
test(verifier): pin the three lastAction states on both hosts
The web page is handed the same applied field the goja object exposes, so a property cannot read one thing on native and another on web.
This commit is contained in:
1 parent
7833c5fa53
commit
157cf63520
2 files changed
+82
-1
No files matched your search
@@ -3,6 +3,7 @@ package runner
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -71,7 +72,47 @@ func TestRunner_WebInstallsLastActionInThePage(t *testing.T) {
|
|||||||
// Every later step carries what the runner actually applied. The shape is
|
// Every later step carries what the runner actually applied. The shape is
|
||||||
// the goja host's (internal/verifier/marshal.go lastActionFields), pinned
|
// the goja host's (internal/verifier/marshal.go lastActionFields), pinned
|
||||||
// against it by TestLastAction_WebJSONMatchesTheGojaObject.
|
// against it by TestLastAction_WebJSONMatchesTheGojaObject.
|
||||||
const want = `{"kind":"Tap","on":"id:TxnSubmit"}`
|
const want = `{"kind":"Tap","applied":true,"on":"id:TxnSubmit"}`
|
||||||
|
if web.installed[1] != want {
|
||||||
|
t.Errorf("step 2 installed %s, want %s", web.installed[1], want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// failingTapWebDriver dispatches the tap and then fails the call, the shape an
|
||||||
|
// RPC deadline takes: the page has the click, the runner has an error.
|
||||||
|
type failingTapWebDriver struct {
|
||||||
|
*tappingWebDriver
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *failingTapWebDriver) Tap(context.Context, int, int) error {
|
||||||
|
return errors.New("rpc error: code = DeadlineExceeded desc = context deadline exceeded")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The web leg of the same three states the goja host reports. "applied":null is
|
||||||
|
// not "no action": a property gated on the last action still sees the tap and
|
||||||
|
// decides for itself, which it cannot do if the page is handed a bare null.
|
||||||
|
func TestRunner_WebInstallsAnUnconfirmedActionWithItsFateUnknown(t *testing.T) {
|
||||||
|
state := newHarnessWithSpec(t, lastActionSpec)
|
||||||
|
web := &failingTapWebDriver{tappingWebDriver: &tappingWebDriver{Driver: state.mock}}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
if _, err := Run(ctx, Options{
|
||||||
|
Duration: time.Hour,
|
||||||
|
IdleTimeout: 20 * time.Millisecond,
|
||||||
|
MaxSteps: 2,
|
||||||
|
Driver: web,
|
||||||
|
Verifier: state.verifier,
|
||||||
|
TraceWriter: state.writer,
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatalf("Run: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(web.installed) < 2 {
|
||||||
|
t.Fatalf("the page was handed lastAction %d time(s); the web path never installed it",
|
||||||
|
len(web.installed))
|
||||||
|
}
|
||||||
|
const want = `{"kind":"Tap","applied":null,"on":"id:TxnSubmit"}`
|
||||||
if web.installed[1] != want {
|
if web.installed[1] != want {
|
||||||
t.Errorf("step 2 installed %s, want %s", web.installed[1], want)
|
t.Errorf("step 2 installed %s, want %s", web.installed[1], want)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ func TestLastAction_WebJSONMatchesTheGojaObject(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{"nil", nil},
|
{"nil", nil},
|
||||||
{"Tap", &Action{Kind: ActionKindTap, On: "id:TxnSubmit", X: 12, Y: 34}},
|
{"Tap", &Action{Kind: ActionKindTap, On: "id:TxnSubmit", X: 12, Y: 34}},
|
||||||
|
{"TapApplied", &Action{Kind: ActionKindTap, On: "id:TxnSubmit", Applied: true}},
|
||||||
{"TapWithoutSelector", &Action{Kind: ActionKindTap, X: 12, Y: 34}},
|
{"TapWithoutSelector", &Action{Kind: ActionKindTap, X: 12, Y: 34}},
|
||||||
{"DoubleTap", &Action{Kind: ActionKindDoubleTap, On: `desc:say "hi" <b>`}},
|
{"DoubleTap", &Action{Kind: ActionKindDoubleTap, On: `desc:say "hi" <b>`}},
|
||||||
{"InputText", &Action{Kind: ActionKindInputText, On: "id:field", Text: "50"}},
|
{"InputText", &Action{Kind: ActionKindInputText, On: "id:field", Text: "50"}},
|
||||||
@@ -193,3 +194,42 @@ func TestLastAction_WebJSONMatchesTheGojaObject(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A spec has to be able to tell three things apart: no action ran, an action
|
||||||
|
// ran, and an action was dispatched whose fate the runner cannot vouch for.
|
||||||
|
// The third used to be reported as the first, which is how a property that
|
||||||
|
// reasons "an effect landed with no action to cause it" convicts an app over
|
||||||
|
// an RPC deadline.
|
||||||
|
func TestLastAction_SeparatesNoActionFromAnActionOfUnknownFate(t *testing.T) {
|
||||||
|
verifier := newVerifier(t)
|
||||||
|
mustLoad(t, verifier, `
|
||||||
|
globalThis.fate = __sanderling__.extract(state =>
|
||||||
|
state.lastAction === null ? "no action"
|
||||||
|
: state.lastAction.applied === true ? "applied"
|
||||||
|
: state.lastAction.applied === null ? "unknown"
|
||||||
|
: "unreadable");
|
||||||
|
`)
|
||||||
|
|
||||||
|
for _, testCase := range []struct {
|
||||||
|
name string
|
||||||
|
action *Action
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"nothing ran", nil, "no action"},
|
||||||
|
{"dispatch confirmed", &Action{Kind: ActionKindTap, On: "id:TxnSubmit", Applied: true}, "applied"},
|
||||||
|
{"dispatch unconfirmed", &Action{Kind: ActionKindTap, On: "id:TxnSubmit"}, "unknown"},
|
||||||
|
} {
|
||||||
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
|
if err := verifier.PushSnapshot(SnapshotInput{
|
||||||
|
Snapshots: Snapshots{},
|
||||||
|
LastAction: testCase.action,
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
handle := verifier.runtime.GlobalObject().Get("fate").ToObject(verifier.runtime)
|
||||||
|
if got := handle.Get("current").String(); got != testCase.want {
|
||||||
|
t.Errorf("the spec read %q, want %q", got, testCase.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user