Open crab-apple opened 1 month ago
you can check tm.FinalOutput()
after the wait, i believe.
you can check
tm.FinalOutput()
after the wait, i believe.
But it doesn't return the full output, as it has already been partially or totally consumed by the wait, right? Unless I'm doing something wrong. Here is an example:
Given this model, which always returns "Hello" as the view:
type Model struct {
}
func InitialModel() Model {
return Model{}
}
func (m Model) Init() tea.Cmd {
return nil
}
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
}
func (m Model) View() string {
return "Hello"
}
I can assert the output with WaitFor:
func TestCheckIntermediate(t *testing.T) {
tm := teatest.NewTestModel(t, InitialModel())
teatest.WaitFor(t, tm.Output(), func(bts []byte) bool {
return bytes.Contains(bts, []byte("Hello"))
})
}
And I can assert the final output:
func TestCheckFinal(t *testing.T) {
tm := teatest.NewTestModel(t, InitialModel())
assert.NoError(t, tm.Quit())
final, err := io.ReadAll(tm.FinalOutput(t))
assert.NoError(t, err)
assert.True(t, bytes.Contains(final, []byte("Hello")), "Final output should contain 'Hello'")
}
But if I wait and then also check the final output, then the test fails:
func TestCheckIntermediateAndFinal(t *testing.T) {
tm := teatest.NewTestModel(t, InitialModel())
teatest.WaitFor(t, tm.Output(), func(bts []byte) bool {
return bytes.Contains(bts, []byte("Hello"))
})
assert.NoError(t, tm.Quit())
final, err := io.ReadAll(tm.FinalOutput(t))
assert.NoError(t, err)
assert.True(t, bytes.Contains(final, []byte("Hello")), "Final output should contain 'Hello'.")
}
You want the final render of the model, right?
If so, you can do something like:
func TestCheckIntermediateAndFinal(t *testing.T) {
tm := teatest.NewTestModel(t, Model{})
teatest.WaitFor(t, tm.Output(), func(bts []byte) bool {
return bytes.Contains(bts, []byte("Hello"))
})
if err := tm.Quit(); err != nil {
t.Fatal(err)
}
final := tm.FinalModel(t).View()
if final != "Hello" {
t.Errorf("expected model to be 'Hello', was '%s'", final)
}
}
the View()
method should not have any side effect (i.e. change the model), so you can do it like this :)
Right, that makes sense.
I feel it makes more sense even, as my tests are interested in the view itself, rather than the output stream. The output stream could contain content of previous views that have been since painted over (in my limited understanding of how this works).
Which kind of begs the question: when waiting for a given state, wouldn't I be interested in the view as well, and not in the raw output? Would it make sense to have a method like this?
teatest.WaitForView(t, tm, func(view string) bool {
return strings.Contains(view, "Hello")
})
I'm not sure if I'm looking at this the right way. Here's what I'm trying to achieve:
Say I have a program that starts by making some asynchronous request to an external system (with a
tea.Cmd
).In my tests I use a fake instead of the real system. My fake returns a result with a delay of a few milliseconds.
Now I want to test that, when the command is complete, my program displays "foo" and it doesn't display "bar". Testing that it displays "foo" is easy with
WaitFor
.But how do I test that the program doesn't display "bar"?
One approach would be to wait until the program displays "foo", and then get the
FinalOutput
and assert that it doesn't contain "bar". This approach has two issues:WaitFor
I've consumed part of the output, soFinalOutput
will not actually give me the final "display".WaitFor
without consuming the output, the condition "contains 'foo'" still doesn't give me any guarantee that I'm looking at the final state. The program could be in the middle of writing out the output.Before switching to teatest, I was using a homemade solution for testing where I didn't have problem 1 above but I still had problem 2. Essentially I haven't found a way to wait until the program has reached a "stable" state, for lack of a better term. I suppose that would be a state where there are no commands still pending to return a result, and the program has completely processed all the pending messages.
Am I missing something?