Skip to content

Conversation

@mwbrooks
Copy link
Member

@mwbrooks mwbrooks commented Apr 10, 2025

Summary

This pull request is part of the series that updates our tests to use slackcontext.MockContext(...) instead of context.Background().

The motivation is to continue to have consistent and reliable unit tests. Right now, many of our test use empty context such as context.Background(), which can cause unexpected errors if a function brings to use values from the context. Now that we can mock "guaranteed" context values, this PR combs through to replace .Background() references.

You might want a fresh cup of coffee ☕ to sip while scrolling through this one!

Requirements

@mwbrooks mwbrooks added code health M-T: Test improvements and anything that improves code health semver:patch Use on pull requests to describe the release version increment labels Apr 10, 2025
@mwbrooks mwbrooks added this to the Next Release milestone Apr 10, 2025
@mwbrooks mwbrooks self-assigned this Apr 10, 2025
@codecov
Copy link

codecov bot commented Apr 10, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 62.94%. Comparing base (034ae57) to head (82f4cd6).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #28      +/-   ##
==========================================
- Coverage   62.94%   62.94%   -0.01%     
==========================================
  Files         210      210              
  Lines       22127    22127              
==========================================
- Hits        13928    13927       -1     
+ Misses       7115     7114       -1     
- Partials     1084     1086       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Member Author

@mwbrooks mwbrooks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments to (hopefully) make reviewing this a little more productive and pleasant 😃


// Create mocks
ctx := slackcontext.MockContext(t.Context())
clientsMock := shared.NewClientsMock()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: This is the standard, repetitive change that you'll see. We are swapping context.Background() for slackcontext.MockContext(t.Context). 👯

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting up ctx with other mocks is an awesome change!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the testing context is a neat update also! I haven't explore enough of that package, but I imagine more useful methods might be used elsewhere too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like using the t.Context() as well. A few benefits are:

  1. It makes it easy to search for context.Background() and context.TODO() to prevent those from slipping into production code.
  2. t.Context() is a cancel context and it's cancelled just before the test cleanup. So, any goroutines running and listening for <- ctx.Done() will have a chance to shutdown.

"Successfully uninstall": {
Setup: func(t *testing.T, ctx context.Context, clientsMock *shared.ClientsMock, clients *shared.ClientFactory) {
prepareCommonUninstallMocks(clients, clientsMock)
prepareCommonUninstallMocks(ctx, clients, clientsMock)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: This was missed in the PR that updated .Setup: func(t, ctx, ...) to accept the mocked context.

Comment on lines 137 to 138

func TestCollaboratorsCommand_PrintSuccess(t *testing.T) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: I'm a little baffled where this test came from 🤔 I didn't write it, so I assume I updated it. But I cannot find the original copy of it! Either way, it tests printSuccess and I think we want to keep it. I'm assuming it was introduced by a rebase (kinda regretting doing a rebase instead of a merge).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does seem to happen with branches rebased but a quick thanks for making reviews much more pleasant with this 🙏

I do think we can delete these tests to make later updates a bit more clear. IIRC #16 added tests that cover these cases instead of a separate unit here- 🔍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohhhh, great memory! I'll remove this test then!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit f1d5fa8 removes this test. I've confirmed that we still have test coverage after it's been removed. Thanks @zimeg!


for name, tt := range tests {
t.Run(name, func(t *testing.T) {
ctx := slackcontext.MockContext(t.Context())
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: It's generally best to declare the ctx at the top of the function, so that the same context is used throughout.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edit: I should've read on! I agree so much that this is a good change.


t.Run(tt.name, func(t *testing.T) {
ctx, clientsMock := prepareMocks(tt.triggersListResponse, tt.globResponse, tt.triggersCreateResponse, nil /*trigger create error*/)
ctx, clientsMock := prepareMocks(t, tt.triggersListResponse, tt.globResponse, tt.triggersCreateResponse, nil /*trigger create error*/)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: We need t *testing.T in order to called slackcontext.MockContext(t.Context())


func Test_ManifestValidate_GetManifestLocal_Error(t *testing.T) {
ctx, clients, _, log, appMock, authMock := setupCommonMocks()
ctx, clients, _, log, appMock, authMock := setupCommonMocks(t)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: It's not obvious that this change adds a t *testing.T argument to setupCommonMocks(t). Same reason as before, so that we can call slackcontext.MockContext(t.Context()).

//

func TestPrompt_AppSelectPrompt_SelectedAuthExpired_UserReAuthenticates(t *testing.T) {

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vent: Personal pet-peeve is newlines at the top of a function block in Golang 😆

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

➕ I find these make jumping around sections sometimes a hassle- Thanks for reducing our linecounts with this change!

@mwbrooks mwbrooks marked this pull request as ready for review April 10, 2025 21:52
@mwbrooks mwbrooks requested a review from a team as a code owner April 10, 2025 21:52
Copy link
Member

@zimeg zimeg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mwbrooks

Now that we can mock "guaranteed" context values, this PR combs through to replace .Background() references.

How great! And thanks for keeping these changes in one PR. The review was energized without chaos. It's so much appreciated.

I left one note on added tests that I think can be removed in these changes, but these changes add a lot of reason to the tests that exist already!

🧪 ✨ 👾

Comment on lines 137 to 138

func TestCollaboratorsCommand_PrintSuccess(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does seem to happen with branches rebased but a quick thanks for making reviews much more pleasant with this 🙏

I do think we can delete these tests to make later updates a bit more clear. IIRC #16 added tests that cover these cases instead of a separate unit here- 🔍


// Create mocks
ctx := slackcontext.MockContext(t.Context())
clientsMock := shared.NewClientsMock()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting up ctx with other mocks is an awesome change!


// Create mocks
ctx := slackcontext.MockContext(t.Context())
clientsMock := shared.NewClientsMock()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the testing context is a neat update also! I haven't explore enough of that package, but I imagine more useful methods might be used elsewhere too.

clientsMock := shared.NewClientsMock()
clientsMock.AddDefaultMocks()
clients := shared.NewClientFactory(clientsMock.MockClientFactory())
ctx := context.Background()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 Creating the ctx before other mocks is a nice change.


for name, tt := range tests {
t.Run(name, func(t *testing.T) {
ctx := slackcontext.MockContext(t.Context())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edit: I should've read on! I agree so much that this is a good change.

Comment on lines -549 to +550
prepareMocks func(*app.AppMock, *shared.ClientsMock)
prepareMocks func(*testing.T, context.Context, *shared.ClientsMock, *app.AppMock)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Love to see these patterns!

Comment on lines -234 to +235
func setupCommonMocks() (ctx context.Context, clients *shared.ClientFactory, clientsMock *shared.ClientsMock, log *logger.Logger, mockApp types.App, mockAuth types.SlackAuth) {
func setupCommonMocks(t *testing.T) (ctx context.Context, clients *shared.ClientFactory, clientsMock *shared.ClientsMock, log *logger.Logger, mockApp types.App, mockAuth types.SlackAuth) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📚 No blocker but sometimes arguments and returns of this amount on a single line are no fun to parse as the reader.

No need to change it and this is opinion too! Also I've tried using linters to tackle this with linters that max a line length but handling cases where this is needed is not always convenient TBH.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, that's a fair point @zimeg! If we can use our linter to enforce a max line length before declaring the function as multi-line, then I think that's best!

"github.com/slackapi/slack-cli/internal/logger"
"github.com/slackapi/slack-cli/internal/shared"
"github.com/slackapi/slack-cli/internal/shared/types"
"github.com/slackapi/slack-cli/internal/slackcontext"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Other import updates also remove context and I was wondering if we're using that package in other ways here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edit: Ahhhh of course! It's in the setup of common mocks 👁️‍🗨️

//

func TestPrompt_AppSelectPrompt_SelectedAuthExpired_UserReAuthenticates(t *testing.T) {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

➕ I find these make jumping around sections sometimes a hassle- Thanks for reducing our linecounts with this change!

@mwbrooks mwbrooks merged commit 4e527aa into main Apr 11, 2025
6 checks passed
@mwbrooks mwbrooks deleted the mbrooks-slackcontext-tabletestcommand-expectedasserts-background branch April 11, 2025 16:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

code health M-T: Test improvements and anything that improves code health semver:patch Use on pull requests to describe the release version increment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants