feat: 优化账号注销流程
This commit is contained in:
@@ -267,6 +267,40 @@ final class StoreAccountDeregistrationViewModelTests: XCTestCase {
|
||||
XCTAssertFalse(model.canContinue)
|
||||
}
|
||||
|
||||
/// 验证码与原因在任何查询和提交意图之前校验;空白及超长原因不能触发网络请求。
|
||||
func testSubmitRejectsMissingOrOversizedRequiredInputWithoutSideEffects() async throws {
|
||||
let cases = [
|
||||
(code: "", reason: "正常原因", message: "请输入收到的短信验证码"),
|
||||
(code: "654321", reason: "", message: "请输入注销原因"),
|
||||
(code: "654321", reason: " \n", message: "请输入注销原因"),
|
||||
(code: "654321", reason: String(repeating: "原", count: 51), message: "注销原因不能超过 50 个字")
|
||||
]
|
||||
for item in cases {
|
||||
let service = try DeregistrationServiceStub()
|
||||
service.current = try StoreAccountDeregistrationFixtures.ready()
|
||||
let suite = "DeregistrationRequiredReason.\(UUID().uuidString)"
|
||||
let defaults = try XCTUnwrap(UserDefaults(suiteName: suite))
|
||||
defer { defaults.removePersistentDomain(forName: suite) }
|
||||
let store = StoreAccountDeregistrationSubmissionStore(
|
||||
storeUserID: "101", environment: .testing, defaults: defaults
|
||||
)
|
||||
let model = StoreAccountDeregistrationViewModel(storeUserID: 101, submissionStore: store)
|
||||
await model.refresh(api: service)
|
||||
model.beginVerification()
|
||||
let statusCount = service.statusCount
|
||||
let eligibilityCount = service.eligibilityCount
|
||||
|
||||
await model.submit(smsCode: item.code, reason: item.reason, api: service)
|
||||
|
||||
XCTAssertEqual(model.errorMessage, item.message)
|
||||
XCTAssertTrue(service.mutations.isEmpty)
|
||||
XCTAssertEqual(service.statusCount, statusCount)
|
||||
XCTAssertEqual(service.eligibilityCount, eligibilityCount)
|
||||
XCTAssertFalse(model.submissionAttempted)
|
||||
XCTAssertFalse(store.hasUnresolvedSubmission)
|
||||
}
|
||||
}
|
||||
|
||||
/// 申请响应丢失可能已被服务端受理,不能直接重试或显示失败后可重新申请。
|
||||
func testLostApplyResponsePreventsAutomaticRetry() async throws {
|
||||
let service = try DeregistrationServiceStub()
|
||||
@@ -285,8 +319,8 @@ final class StoreAccountDeregistrationViewModelTests: XCTestCase {
|
||||
XCTAssertEqual(model.step, .unresolvedRequest)
|
||||
}
|
||||
|
||||
/// 服务端明确拒绝验证码时允许重新核验,但不能保留之前的提交权限。
|
||||
func testServerRejectionRequiresFreshEligibility() async throws {
|
||||
/// 服务端明确拒绝验证码时保留已核验条件并停留在手机验证,不要求重新确认资产。
|
||||
func testVerificationCodeRejectionStaysInVerification() async throws {
|
||||
let service = try DeregistrationServiceStub()
|
||||
service.current = try StoreAccountDeregistrationFixtures.ready()
|
||||
service.applyError = APIError.serverCode(100001, "验证码错误")
|
||||
@@ -295,10 +329,10 @@ final class StoreAccountDeregistrationViewModelTests: XCTestCase {
|
||||
model.beginVerification()
|
||||
await model.submit(smsCode: "907182", reason: "不再使用", api: service)
|
||||
XCTAssertFalse(model.submissionAttempted)
|
||||
XCTAssertFalse(model.canContinue)
|
||||
XCTAssertEqual(model.errorMessage, "验证码错误")
|
||||
await model.refresh(api: service)
|
||||
XCTAssertTrue(model.canContinue)
|
||||
XCTAssertEqual(model.step, .verification)
|
||||
XCTAssertNotNil(model.eligibility)
|
||||
XCTAssertEqual(model.errorMessage, "验证码错误")
|
||||
}
|
||||
|
||||
/// 展示全部真实阻断项,初始加载不会调用任何修改接口。
|
||||
@@ -471,15 +505,19 @@ private final class DeregistrationServiceStub: StoreAccountDeregistrationServing
|
||||
var readError: Error?
|
||||
var applyError: Error?
|
||||
var mutations: [String] = []
|
||||
var eligibilityCount = 0
|
||||
var statusCount = 0
|
||||
var lastCode: String?
|
||||
var lastReason: String?
|
||||
|
||||
init() throws { current = try StoreAccountDeregistrationFixtures.eligibility() }
|
||||
func eligibility() async throws -> StoreAccountDeregistrationEligibility {
|
||||
eligibilityCount += 1
|
||||
if let readError { throw readError }
|
||||
return current
|
||||
}
|
||||
func status() async throws -> StoreAccountDeregistrationStatus {
|
||||
statusCount += 1
|
||||
if let readError { throw readError }
|
||||
return currentStatus
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user