fix(msn): correct API response parsing for profile, financials, insights, screener, history

- financials: fix incomeStatement serde rename (was incomeStatements, API sends singular)
- financials: flatten nested sub-objects (income/revenue/expense/cash) in parse_statement_section
- insights: rewrite RawInsight to match actual API shape ({insights:[{insightName,insightStatement,category}]})
- insights: group insight items into highlights (non-risk) and risks by category
- screener: build Quote directly in parse_screener_results, skip stocks with no price
- profile: use short_name fallback when long_name is null, hide empty fields
- history: map Finance/Charts 404 to Unsupported with clear IDX-specific message
- tests: update MSN history/technical tests to use mock provider
This commit is contained in:
Ciphercat 2026-03-06 20:08:03 +00:00
commit 2207c928b2
5 changed files with 251 additions and 38 deletions

View file

@ -107,23 +107,27 @@ fn technical_with_mock_provider_json_contains_fields() {
}
#[test]
fn msn_history_is_no_longer_unsupported() {
test_bin("msn-history-supported")
fn msn_history_with_mock_returns_data() {
// MSN chart parsing works with fixture data; real IDX stocks 404 on Finance/Charts
// which surfaces as Unsupported (not the old blanket UNSUPPORTED message).
test_bin("msn-history-mock")
.env("IDX_PROVIDER", "msn")
.args(["stocks", "history", "BBCA", "--period", "1mo"])
.env("IDX_USE_MOCK_PROVIDER", "1")
.args(["stocks", "history", "BBCA", "--period", "3mo"])
.assert()
.failure()
.stderr(predicate::str::contains("MSN provider does not currently support").not());
.success();
}
#[test]
fn msn_technical_json_is_no_longer_unsupported() {
test_bin("msn-technical-supported")
fn msn_technical_with_mock_returns_data() {
// Technical analysis works via MSN chart fixture data (mock); real IDX stocks
// return Unsupported from Finance/Charts (404 on XIDX).
test_bin("msn-technical-mock")
.env("IDX_PROVIDER", "msn")
.env("IDX_USE_MOCK_PROVIDER", "1")
.args(["-o", "json", "stocks", "technical", "BBCA"])
.assert()
.failure()
.stderr(predicate::str::contains("\"code\": \"UNSUPPORTED\"").not());
.success();
}
#[test]