Skip to content

feat(jtk): add init command and config test#48

Merged
rianjs merged 2 commits intomainfrom
feat/39-jtk-init-config-test
Jan 31, 2026
Merged

feat(jtk): add init command and config test#48
rianjs merged 2 commits intomainfrom
feat/39-jtk-init-config-test

Conversation

@rianjs
Copy link
Copy Markdown
Contributor

@rianjs rianjs commented Jan 31, 2026

Summary

  • Add jtk init command for interactive guided setup wizard
    • Prompts for URL, email, and API token
    • Verifies connection before saving (--no-verify to skip)
    • Supports non-interactive mode via flags
    • Detects existing config and prompts for overwrite
  • Add jtk config test command for connectivity verification
    • Tests authentication and API access
    • Provides clear pass/fail status with troubleshooting suggestions

Ports init wizard and config test from jira-ticket-cli PR #59.

Closes #39

Test plan

  • make build passes
  • make test passes
  • make lint passes
  • Manual testing of jtk init
  • Manual testing of jtk config test

🤖 Generated with Claude Code

Port init wizard and config test from jira-ticket-cli PR #59:
- `jtk init`: interactive setup wizard with --url/--email/--token flags
- `jtk config test`: verify API connectivity with troubleshooting hints

Closes #39

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@rianjs
Copy link
Copy Markdown
Contributor Author

rianjs commented Jan 31, 2026

TDD Quality Assessment for PR #48

Summary

This PR adds jtk init and jtk config test commands with accompanying tests. The tests follow established patterns in the codebase (httptest, injectable stdin/stdout, testify assertions), but there are notable gaps in coverage.


What's Good

1. Consistent Testing Patterns

  • Uses httptest.NewServer for API mocking (matches api/users_test.go style)
  • Injectable stdin via root.Options.Stdin for prompts
  • Uses bytes.Buffer for stdout/stderr capture
  • Table-driven tests for promptYesNo and promptRequired
  • Proper use of t.Setenv() and t.TempDir() for isolation

2. Core Paths Covered

  • initcmd_test.go: Non-interactive with verification, non-interactive with --no-verify, auth failure
  • configcmd_test.go: Success, auth failure, no URL configured
  • Helper function tests for promptYesNo and promptRequired

What's Missing

1. Interactive Mode Tests (Critical Gap)
The runInit function has significant interactive logic that isn't tested:

  • No test for prompting URL when url == ""
  • No test for prompting email when email == ""
  • No test for prompting token when token == ""
  • These require multi-line stdin input (e.g., "https://test.atlassian.net\nuser@example.com\ntoken123\n")

2. Existing Config Overwrite Flow

  • Tests provide "y\n" for overwrite prompt "just in case", but there's no explicit test for:
    • User answering "n" to overwrite (should cancel setup)
    • The "Existing configuration found" warning path

3. promptRequired Edge Case

  • No test for empty input retry loop (when user enters empty string first, then valid input)
  • The implementation loops until non-empty input, but tests only cover valid input on first try

4. URL Normalization

  • runInit calls sharedurl.NormalizeURL(url) but no test verifies this behavior
  • E.g., test that mycompany.atlassian.net becomes https://mycompany.atlassian.net

5. config test Additional Scenarios

  • No test for client creation failure (opts.APIClient() returns error)
  • No test for different HTTP error codes (403 Forbidden, 500 Server Error)

6. Output Verification

  • Tests check for presence of strings but don't verify the full output format
  • No verification of troubleshooting suggestions on failure

Suggested Additional Tests

// initcmd_test.go

func TestRunInit_InteractiveMode(t *testing.T) {
    // Test full interactive flow with all prompts
    server := setupMockServer(t)
    opts := newTestRootOptions()
    opts.Stdin = strings.NewReader("y\nhttps://test.atlassian.net\nuser@example.com\ntoken123\n")
    
    err := runInit(opts, "", "", "", false)
    require.NoError(t, err)
    // Assert prompts appeared, connection verified, config saved
}

func TestRunInit_ExistingConfig_DeclineOverwrite(t *testing.T) {
    // Setup existing config, answer "n" to overwrite
    // Should return nil and output "Setup cancelled"
}

func TestPromptRequired_EmptyThenValid(t *testing.T) {
    // First empty, then valid - tests retry loop
    reader := bufio.NewReader(strings.NewReader("\nhello\n"))
    got, err := promptRequired(reader, "Test")
    require.NoError(t, err)
    assert.Equal(t, "hello", got)
}

// configcmd_test.go

func TestNewTestCmd_ClientCreationFailure(t *testing.T) {
    // Test path where opts.APIClient() returns an error
}

func TestNewTestCmd_ServerError(t *testing.T) {
    // 500 response should show error and troubleshooting hints
}

Assessment Summary

Criteria Score Notes
Core happy paths Non-interactive + verification works
Error handling ⚠️ Auth failure tested, but not all error paths
Edge cases Interactive mode, retry loops, overwrite decline untested
Pattern consistency Follows codebase conventions
Test isolation Proper use of t.Setenv, t.TempDir

Overall: Good foundation, but interactive mode and edge cases need coverage before this represents thorough TDD.

The tests cover ~60% of the functionality. The untested 40% is primarily the interactive prompting flow, which is a significant part of the user experience for jtk init.

@rianjs rianjs merged commit e5a9280 into main Jan 31, 2026
7 checks passed
@rianjs rianjs deleted the feat/39-jtk-init-config-test branch January 31, 2026 11:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(jtk): port init and config test commands

1 participant