test: establish automated test infrastructure for GrowingAnalytics core modules - #45
Merged
Conversation
- UserIdentifier._reset(): replace `{}` with `JSON.parse('{}') as object`
to satisfy arkts-no-untyped-obj-literals for `object`-typed field
- EventTimerTest: fix durationFrom 24h boundary tests to use startTime>0
so they actually exercise the duration guard, not the startTime guard
- InMemoryEventStore: replace `new TextEncoder()` (not a global in ArkTS)
with `Util.sizeOfEventString()` for byte counting
- LocalUnit.test.ets: remove unused `{ describe, it, expect }` import
- UtilTest: define top-level interfaces (CustomEventData, PageEventData,
VisitEventData, AppClosedEventData, V3*EventData, ValidateSize*Event)
and replace all `Record<string, object>` inline literals
- EventPersistenceTest: add top-level interfaces for all inline event
objects passed to Util.validateEventSize / toSerializeByMeasurementProtocol*
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- NiceTryTest: change Record<string,object> to Record<string,string>
so niceTry<string> type T unifies correctly with string fallback
- EventTimerTest/SessionTest: replace `as GrowingContext` with
`as unknown as GrowingContext` for bare object literals (required
for non-overlapping class type casts in ArkTS strict mode)
- EventTimerTest: expand shorthand `{ trackerId }` to `{ trackerId: trackerId }`
- TestBuilders/NetworkTest: expand shorthand `config` to `config: config`
(shorthand property initializer has no precedent in production ArkTS code)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All test files now pass UnitTestBuild compilation with zero errors: - Replace `as unknown as T` with `as ESObject as T` throughout - Define named interfaces for all inline object type declarations (NetworkTestOptions, FakeContextOptions, MinimalContext variants) - Move nested helper functions (makeBase, makePageEvent) to module level - Cast all JSON.parse() results to ESObject - Replace Record<string,string> with AttributesType (TypeScript-sourced index-signature type that accepts object literals in ArkTS) - Replace non-existent assertNotContain() with .includes() + assertFalse() - Simplify FakeNetwork.responses to number[] and introduce FakeRcpResponse class to avoid untyped rcp.Response construction - Expand shorthand object properties to explicit key: value form Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In the full local-test build mode (-p isLocalTest=true -p unitTestMode=true -p ohos-test-coverage=true), JSON.parse() returns unknown even when cast to ESObject, triggering arkts-no-any-unknown errors. Root cause: this stricter pipeline treats ESObject like any/unknown. Fix: introduce JsonParser.ts (TypeScript, not ArkTS), which wraps JSON.parse() internally and exposes typed getString/getNumber/hasKey accessors. The unknown type is contained inside the .ts file and never leaks into .ets consumers. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- rename all XxxTest.ets to Xxx.test.ets (e.g. UtilTest.ets → Util.test.ets) - declare all test suites directly in List.test.ets instead of delegating to localUnitTest() - reset LocalUnit.test.ets to boilerplate placeholder (same style as Autotrack.test.ets) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
replace all describe() names containing Chinese characters, spaces, hyphens, parentheses, or slashes with ASCII-only ClassName_featureName format to satisfy hypium's constraint (only letters, digits, underscores, and periods, starting with a letter) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ardless of null value xcontent 为 null 时条件判断提前退出,导致 null 值字段被保留在序列化结果中。 改为无条件 delete,与 timezoneOffset 处理方式一致。 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
hypium 中 beforeEach 仅对其所在 describe 块内的 it 生效, 定义在 describe 外部时不会在嵌套 describe 的用例间执行。 将 beforeEach 移入各 describe 块内,确保每个用例前正确重置静态状态。 涉及文件:Session.test.ets、EventTimer.test.ets、EventSender.test.ets Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…tability Decouple the send-cycle scheduling logic from platform IO (EventDatabase, Network, Plugins) via a SendCycleIO callback interface, enabling unit tests without HarmonyOS runtime dependencies. Remove unused interface abstractions (IEventStore, INetwork, IStorage) and their test doubles in favor of the lighter callback-injection approach. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…usages ArkTS strict mode requires explicit return types on arrow functions (arkts-no-implicit-return-types). Also add missing afterRemove callback to all test SendCycleIO object literals. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SDK 的 toSerializeByMeasurementProtocolV3 仅在 xcontent 有实际值时移除, xcontent 为 null 时 JSON.stringify 会保留该字段,测试断言应与此一致。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…eset EventSender 构造时注册了 emitter.once(EMIT_EVENT_DATABASE_FLUSH) 回调, 当 GrowingContext._reset() 后 contexts Map 被清空,该回调仍然存活。 触发时 GrowingContext.getContext() 返回 undefined,原代码通过 as GrowingContext 强转掩盖了类型,导致后续 context.config 访问崩溃。 改为在 isUploading 锁之后、try 块之前做显式 null 检查, context 不存在时静默 return,isUploading 保持 false 不影响后续调用。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
新增三个核心模块的本地单元测试,补齐数据准确性关键路径的覆盖: GeneralProps(35 用例) - set/remove/clear/dynamic 四类操作及组合场景 - 动态属性优先级高于静态属性(同名覆盖) - getGeneralProps 返回副本,外部修改不影响内部状态 GrowingContext(20 用例) - contexts Map 的增删查及重复 set 覆盖语义 - defaultContext 设置、MAIN_TRACKER_ID 固定为 __GrowingAnalyticsCore - hasSimilarContext 按 trackerId / accountId+dataSourceId 双维度去重 - SaaS 模式 EventSender 数量(PV + CSTM = 2 个) UserIdentifier(25 用例) - initUser / initMultiUser 在 Preferences 未初始化时返回空字符串 - setLoginUserId:>1000 字符静默忽略、幂等性、清空、idMapping 控制 - A→B 用户切换触发 Session.refreshSession(sessionId 变化可观测) - CDP 模式:空→有触发 generateVisit;A→B 走 refreshSession - 使用 dataCollectionEnabled=false 阻断 AnalyticsCore.writeEventToDisk 同时为 GeneralProps 和 GrowingContext 补充 _reset() 测试隔离方法, 与 Session、EventTimer 保持一致的测试基础设施规范。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…wElementEvent - EventBuilder: sequenceId 自增与隔离、timestamp 回退、appState、 sessionId、userId/userKey、location 过滤、attributes 合并、 config 字段透传、sdkVersion - Event.toSerialize(): 三路模式分发(SaaS→V2 / CDP→V3 / NewSaaS→JSON.stringify) - PageEvent: lastPage 状态机(trackerId 隔离)、SaaS/NewSaaS referralPage 链路、 CDP 不写 lastPage;新增 PageEvent._reset() 供测试隔离 - CustomEvent / AppClosedEvent: SaaS 模式 lastPage 注入(path / pageShowTimestamp) - ViewElementEvent: CDP pageShowTimestamp、ViewClick textValue 过滤、 index > 0 过滤 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- DeviceInfo.isNotIgnoreField():SaaS/CDP 模式忽略 ignoreField 始终返回 true; NewSaaS 模式下单字段、多字段组合掩码、IgnoreFieldsAll 的过滤行为 - Queue<T>:基础入队/出队、dequeue 清空并返回快照、超出 limitSize 时 丢弃最旧条目、limitSize ≤ 0 回退默认值 50 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
… in SendCycleIO sendEvents now returns SendResult (statusCode + request) and runSendCycle passes request as a parameter to afterRemove, eliminating the mutable closure coupling between callbacks and ensuring onEventsDidSend is never silently skipped. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
YoloMao
force-pushed
the
test/tdd-infrastructure
branch
from
April 9, 2026 07:14
514fb66 to
8523758
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
为 GrowingAnalytics SDK 建立本地单元测试基础设施,覆盖核心模块的纯逻辑路径,可在 DevEco Studio 中无设备直接运行。
测试覆盖
interfaces/GrowingConfig.test.etsutils/Util.test.etsutils/NiceTry.test.etsevent/EventPersistence.test.etsevent/EventSendCycle.test.etscore/Network.test.etscore/Session.test.etscore/EventTimer.test.etscore/GeneralProps.test.etscore/Context.test.etscore/UserIdentifier.test.etscore/DeviceInfo.test.etsisNotIgnoreField():SaaS/CDP 忽略 ignoreField 始终返回 true;NewSaaS 单字段、多字段组合、IgnoreFieldsAll 过滤行为event/EventBuilder.test.etsevent/EventBuilder.test.etstoSerialize()三路模式分发:SaaS→V2 / CDP→V3 / NewSaaS→JSON.stringifyevent/PageEvent.test.etsevent/CustomEvent.test.etsevent/CustomEvent.test.etsevent/ViewElementEvent.test.etsmobileDebugger/Queue.test.ets测试辅助设施
JsonParser(.ts文件):封装JSON.parse()的any类型处理,向.ets测试文件暴露类型安全的访问接口,规避arkts-no-any-unknown限制TestBuilders:buildFakeContext()/makeFakePersistence()工厂函数,快速构建测试用 GrowingContext 和 EventPersistence 实例生产代码变更
EventSender null 防御(fix)
sendEvent()原先通过as GrowingContext强转掩盖了GrowingContext.getContext()可能返回undefined的情况,导致 context 被清理后回调仍触发时访问context.config崩溃。改为在加锁前做显式 null 检查,context 不存在时静默返回,isUploading保持false,不影响后续调用。EventSender 重构
将
sendEvent()中的上报调度决策逻辑提取为独立的纯函数runSendCycle(io: SendCycleIO),通过SendCycleIO接口注入 IO 依赖(fetchEvents / sendEvents / removeEvents / afterRemove / countRemaining),使调度逻辑可脱离平台 API 独立测试。原sendEvent()方法改为构造SendCycleIO实例后委托调用,行为不变。测试隔离支持
为
Session、EventTimer、UserIdentifier、EventBuilder、GeneralProps、GrowingContext、PageEvent七个静态单例类添加_reset()方法,用于测试用例间重置静态状态,避免测试污染。_reset符号已加入consumer-rules.txt混淆白名单。依赖与配置
oh-package.json5添加devDependencies:@ohos/hypium@1.0.21、@ohos/hamock@1.0.2测试运行
在 DevEco Studio 中通过 Run Configurations 选择 GrowingAnalyticsTest 运行,无需连接设备。
命令行编译验证:
🤖 Generated with Claude Code