ui_render_publication_test.go RawHistoryFolder

1package daemon
2
3import (
4	"testing"
5
6	"github.com/bnema/vev/internal/domain"
7	"github.com/bnema/vev/internal/protocol"
8	"github.com/stretchr/testify/require"
9)
10
11func TestRenderPublicationUsesCapturedIdentityAndRevision(t *testing.T) {
12	for _, scenario := range []string{"unchanged", "rename after capture", "view replaced after capture"} {
13		t.Run(scenario, func(t *testing.T) {
14			d, sess, ac, sends := newManualSessionWithPTYs(t, nil)
15			ac.sendMu.Lock()
16			state, ok := captureRenderState(sess, ac, renderCaptureRequest{reset: true})
17			if !ok {
18				ac.sendMu.Unlock()
19				t.Fatal("capture rejected")
20			}
21			want := state.viewContext()
22			want.Publication = 1
23			require.NoError(t, want.Validate())
24			composed := composeFrame(*state, ac.render.cache)
25			switch scenario {
26			case "rename after capture":
27				sess.mu.Lock()
28				sess.name = "renamed"
29				sess.mu.Unlock()
30			case "view replaced after capture":
31				view := ac.viewSnapshot()
32				view.revision++
33				ac.publishView(view)
34			}
35			require.True(t, d.publishCapturedFrameForTest(sess, ac, state, composed)) // releases sendMu
36			if scenario == "view replaced after capture" {
37				require.Empty(t, drainAllFrames(sends))
38				require.Zero(t, ac.output.viewPublication)
39				require.Zero(t, ac.output.next)
40				return
41			}
42			output := unmarshalTestOutput(t, awaitFrame(t, sends, "Output").Payload)
43			require.Equal(t, &want, output.Context)
44			require.Equal(t, state.view.revision, output.ViewRevision)
45			require.Equal(t, want, ac.output.lastViewContext)
46			require.Equal(t, domain.PaneStableID(sess.tabs[0].focusedPane().stableID), output.Context.FocusedPaneID)
47		})
48	}
49}
50
51func TestRenderPublishesContextWithoutTerminalBytes(t *testing.T) {
52	d, sess, ac, sends := newManualSessionWithPTYs(t, nil)
53	paint := func(reset bool) {
54		t.Helper()
55		ac.sendMu.Lock()
56		state, ok := captureRenderState(sess, ac, renderCaptureRequest{reset: reset})
57		if !ok {
58			ac.sendMu.Unlock()
59			t.Fatal("capture rejected")
60		}
61		composed := composeFrame(*state, ac.render.cache)
62		require.True(t, d.publishCapturedFrameForTest(sess, ac, state, composed))
63	}
64	paint(true)
65	initial := unmarshalTestOutput(t, awaitFrame(t, sends, "Output").Payload)
66	require.NotNil(t, initial.Context)
67	beforeOutstanding := ac.output.outstanding()
68	sess.mu.Lock()
69	sess.name = "renamed"
70	sess.mu.Unlock()
71	// The test's bars contain no session name, so only semantic context changes.
72	paint(false)
73	update := decodeServerMessage(t, awaitFrame(t, sends, "UIViewUpdate")).(protocol.UIViewUpdate)
74	require.Equal(t, initial.Epoch, update.Epoch)
75	require.Equal(t, initial.New, update.State)
76	require.Equal(t, initial.Context.Publication+1, update.Context.Publication)
77	require.Equal(t, "renamed", update.Context.Route.Target.SessionName)
78	require.Equal(t, initial.Context.Route.Target.LifecycleID, update.Context.Route.Target.LifecycleID)
79	position := decodeServerMessage(t, awaitFrame(t, sends, "RoutePosition")).(protocol.RoutePosition)
80	require.Equal(t, update.Context.Route.Target, position.Target)
81	require.Equal(t, beforeOutstanding, ac.output.outstanding(), "metadata does not create an ACK obligation")
82	require.Empty(t, drainAllFrames(sends))
83	paint(false)
84	require.Empty(t, drainAllFrames(sends), "unchanged view without a fence sends nothing")
85	require.Equal(t, update.Context.Publication, ac.output.viewPublication)
86	query, err := ac.output.sideEffect([]byte("query"), 0)
87	require.NoError(t, err)
88	require.Nil(t, query.Context)
89	require.Equal(t, update.Context, ac.output.lastViewContext)
90}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close