Skip to content

Commit b795b11

Browse files
committed
clean up all elems on error
1 parent ce167d7 commit b795b11

2 files changed

Lines changed: 35 additions & 7 deletions

File tree

ui/containerhelper.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,20 @@ func (ui *ContainerHelper) RenderContainer(e *core.Element, w io.Writer, outerHT
4949
var contents []*core.Element
5050
for _, childUI := range ui.Container.JawsContains(e) {
5151
elem := e.Request.NewElement(childUI)
52+
contents = append(contents, elem)
5253
if err = elem.JawsRender(w, nil); err != nil {
53-
e.Request.DeleteElement(elem)
5454
break
5555
}
56-
contents = append(contents, elem)
5756
}
58-
ui.mu.Lock()
59-
ui.contents = contents
60-
ui.mu.Unlock()
57+
if err == nil {
58+
ui.mu.Lock()
59+
ui.contents = contents
60+
ui.mu.Unlock()
61+
} else {
62+
for _, elem := range contents {
63+
e.Request.DeleteElement(elem)
64+
}
65+
}
6166
b = b[:0]
6267
b = append(b, "</"...)
6368
b = append(b, outerHTMLTag...)

ui/containerhelper_test.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ func TestContainerHelperRenderErrorPaths(t *testing.T) {
133133
if !errors.Is(err, renderErr) {
134134
t.Fatalf("want %v got %v", renderErr, err)
135135
}
136-
if len(container.contents) != 1 {
137-
t.Fatalf("want 1 successful child got %d", len(container.contents))
136+
if len(container.contents) != 0 {
137+
t.Fatalf("want 0 successful child got %d", len(container.contents))
138138
}
139139

140140
// panic path from must() during append
@@ -195,6 +195,29 @@ func TestContainerHelperRenderErrorDoesNotLeakFailedChildElement(t *testing.T) {
195195
}
196196
}
197197

198+
func TestRequestWriterUI_ContainerRenderErrorDoesNotLeakSuccessfulChildren(t *testing.T) {
199+
core.NextJid = 0
200+
_, rq := newRequest(t)
201+
var sb strings.Builder
202+
rw := RequestWriter{Request: rq, Writer: &sb}
203+
204+
renderErr := errors.New("render error")
205+
okChild := &testRenderErrorCaptureUI{}
206+
failChild := &testRenderErrorCaptureUI{err: renderErr}
207+
tc := &testContainer{contents: []core.UI{okChild, failChild}}
208+
209+
if err := rw.UI(NewContainer("div", tc)); !errors.Is(err, renderErr) {
210+
t.Fatalf("want %v got %v", renderErr, err)
211+
}
212+
213+
if !okChild.jid.IsValid() {
214+
t.Fatal("expected successful child jid to be captured")
215+
}
216+
if leaked := rq.GetElementByJid(okChild.jid); leaked != nil {
217+
t.Fatalf("expected successful child %v to be removed when parent render fails", okChild.jid)
218+
}
219+
}
220+
198221
type testSelectHandler struct {
199222
*testContainer
200223
*testSetter[string]

0 commit comments

Comments
 (0)