152 lines
4.6 KiB
Dart
152 lines
4.6 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:jinzhi_flutter_app/features/mall/application/mall_tab_config.dart';
|
|
import 'package:jinzhi_flutter_app/models/pb/jinzhi/v1/ads.pb.dart' as pb;
|
|
|
|
void main() {
|
|
test('builds the resident mall URL with Jinzhi attribution and theme', () {
|
|
const config = MallTabConfig(
|
|
enabled: true,
|
|
url: 'https://mall.example.com/home?campaign=gold',
|
|
adId: 'ad-1',
|
|
trackingId: 'tracking-1',
|
|
);
|
|
|
|
final uri = config.attributedUri(clickId: 'click-1', isDark: true)!;
|
|
|
|
expect(uri.queryParameters['campaign'], 'gold');
|
|
expect(uri.queryParameters['source_app'], 'jinzhi');
|
|
expect(uri.queryParameters['source_entry'], 'mall_tab');
|
|
expect(uri.queryParameters['ad_id'], 'ad-1');
|
|
expect(uri.queryParameters['tracking_id'], 'tracking-1');
|
|
expect(uri.queryParameters['click_id'], 'click-1');
|
|
expect(uri.queryParameters['isNight'], '1');
|
|
});
|
|
|
|
test('retains server open-mode metadata', () {
|
|
const resident = MallTabConfig(
|
|
enabled: true,
|
|
url: 'https://mall.example.com',
|
|
);
|
|
const nativeApp = MallTabConfig(
|
|
enabled: true,
|
|
url: 'https://mall.example.com',
|
|
openMode: 'native_app',
|
|
);
|
|
const external = MallTabConfig(
|
|
enabled: true,
|
|
url: 'https://mall.example.com',
|
|
openMode: 'external',
|
|
);
|
|
|
|
expect(resident.opensInApp, isTrue);
|
|
expect(nativeApp.opensInApp, isFalse);
|
|
expect(external.opensInApp, isFalse);
|
|
});
|
|
|
|
test('adds retail quote context to the mall URL for H5', () {
|
|
const config = MallTabConfig(
|
|
enabled: true,
|
|
url: 'https://mall.example.com/home',
|
|
);
|
|
|
|
final uri = config.attributedUri(
|
|
clickId: 'quote-click',
|
|
entry: MallEntryRequest.quoteRetailGold,
|
|
)!;
|
|
|
|
expect(uri.queryParameters['source_entry'], 'market_quote');
|
|
expect(uri.queryParameters['hook_type'], 'quote_cta');
|
|
expect(uri.queryParameters['entry_scene'], 'retail');
|
|
expect(uri.queryParameters['entry_metal'], 'au');
|
|
expect(uri.queryParameters['placement'], 'mall_tab');
|
|
});
|
|
|
|
test('shows the first-install promo only for a configured mall entry', () {
|
|
const configured = MallTabConfig(
|
|
enabled: true,
|
|
url: 'https://mall.example.com',
|
|
entryPromoEnabled: true,
|
|
entryBadgeText: '新人礼',
|
|
entryTipTitle: '新人礼:¥360 铂金订购券',
|
|
entryTipBody: '点击这里进商城',
|
|
);
|
|
const disabled = MallTabConfig(
|
|
enabled: true,
|
|
url: 'https://mall.example.com',
|
|
entryPromoEnabled: false,
|
|
entryTipTitle: '新人礼',
|
|
);
|
|
|
|
expect(configured.showsEntryBadge, isTrue);
|
|
expect(configured.showsEntryTip, isTrue);
|
|
expect(disabled.showsEntryBadge, isFalse);
|
|
expect(disabled.showsEntryTip, isFalse);
|
|
});
|
|
|
|
test('parses the server-provided mall entry promotion fields', () {
|
|
final creative = <int>[
|
|
..._stringField(9, 'https://mall.example.com'),
|
|
..._boolField(16, true),
|
|
..._stringField(17, '新人礼'),
|
|
..._stringField(18, '新人礼:¥360 铂金订购券'),
|
|
..._stringField(19, '点击这里进商城'),
|
|
];
|
|
final config = parseMallTabConfigResponse(<int>[
|
|
..._boolField(1, true),
|
|
..._bytesField(2, creative),
|
|
]);
|
|
|
|
expect(config.showsEntryBadge, isTrue);
|
|
expect(config.entryBadgeText, '新人礼');
|
|
expect(config.entryTipTitle, '新人礼:¥360 铂金订购券');
|
|
expect(config.entryTipBody, '点击这里进商城');
|
|
});
|
|
|
|
test('parses generated mall promotion and open-mode fields', () {
|
|
final response = pb.GetAdReply(
|
|
enabled: true,
|
|
ad: pb.AdCreative(
|
|
adId: 'ad-1',
|
|
title: '会员商城',
|
|
h5Url: 'https://mall.example.com',
|
|
trackingId: 'tracking-1',
|
|
openMode: pb.AdOpenMode.AD_OPEN_MODE_NATIVE_APP,
|
|
mallPromotion: pb.MallPromotion(quoteCtaEnabled: true),
|
|
),
|
|
);
|
|
|
|
final config = parseMallTabConfigResponse(response.writeToBuffer());
|
|
|
|
expect(config.isVisible, isTrue);
|
|
expect(config.openMode, 'native_app');
|
|
expect(config.quoteCtaEnabled, isTrue);
|
|
expect(config.allowedHosts, {'mall.example.com'});
|
|
});
|
|
}
|
|
|
|
List<int> _stringField(int tag, String value) =>
|
|
_bytesField(tag, utf8.encode(value));
|
|
|
|
List<int> _bytesField(int tag, List<int> value) => <int>[
|
|
..._varint((tag << 3) | 2),
|
|
..._varint(value.length),
|
|
...value,
|
|
];
|
|
|
|
List<int> _boolField(int tag, bool value) => <int>[
|
|
..._varint(tag << 3),
|
|
value ? 1 : 0,
|
|
];
|
|
|
|
List<int> _varint(int value) {
|
|
final bytes = <int>[];
|
|
while (value > 127) {
|
|
bytes.add((value & 127) | 128);
|
|
value >>= 7;
|
|
}
|
|
bytes.add(value);
|
|
return bytes;
|
|
}
|