diff --git a/waiter.go b/waiter.go index fbcb39f..685de06 100644 --- a/waiter.go +++ b/waiter.go @@ -175,7 +175,9 @@ func (w *waiter) reject(err error) { func newWaiter() *waiter { w := &waiter{ - errChan: make(chan error, 1), + // receive both event timeout err and callback err + // but just return event timeout err + errChan: make(chan error, 2), } return w } diff --git a/waiter_test.go b/waiter_test.go index 0afed58..4c2033d 100644 --- a/waiter_test.go +++ b/waiter_test.go @@ -1,6 +1,7 @@ package playwright import ( + "errors" "fmt" "testing" "time" @@ -136,3 +137,54 @@ func TestWaiterReturnErrorWhenMisuse(t *testing.T) { _, err = waiter.Wait() require.ErrorContains(t, err, "call RejectOnEvent before WaitForEvent") } + +func TestWaiterDeadlockForErrChanCapIs1AndCallbackErr(t *testing.T) { + timeout := 500.0 + emitter := &eventEmitter{} + w := &waiter{ + // just receive event timeout err or callback err + errChan: make(chan error, 1), + } + + overCh := make(chan struct{}) + errUnReachable := errors.New("unreachable") + err := errUnReachable + + go func() { + _, err = w.WithTimeout(timeout).WaitForEvent(emitter, "", nil).RunAndWait(func() error { + time.Sleep(1 * time.Second) + close(overCh) + //block for this err, for waiter.errChan has cache event timeout err + return errors.New("mock timeout error") + }) + panic("unreachable") + }() + + <-overCh + time.Sleep(2 * time.Second) + require.ErrorIs(t, err, errUnReachable) +} + +func TestWaiterHasNotDeadlockForErrChanCapBiggerThan1AndCallbackErr(t *testing.T) { + timeout := 500.0 + emitter := &eventEmitter{} + w := newWaiter().WithTimeout(timeout) + errMockTimeout := errors.New("mock timeout error") + + var err error + overCh := make(chan struct{}) + go func() { + time.Sleep(2 * time.Second) + require.Error(t, err) + require.NotErrorIs(t, err, errMockTimeout) + require.ErrorIs(t, err, ErrTimeout) + close(overCh) + }() + + _, err = w.WaitForEvent(emitter, "", nil).RunAndWait(func() error { + time.Sleep(1 * time.Second) + return errMockTimeout + }) + + <-overCh +}