- Core: Schema (Codable), Store, EventBus, RPC, Engine, I18n - Controls: Text, Title1-6, Label, Input, Textarea, Number, Date, Button, Select VBox, HBox, ScrollPanel, DynamicColumn, Tabular, Form, InlineForm, TabView, Menu, PopupWindow, Html, Image, UrlWidget - Renderer: BricksView (main entry), ControlRenderer (recursive dispatch) - 30+ widget types, 9 bind actiontypes - Form validation (required/minlength/maxlength/min/max/email/number/pattern) - i18n with multi-language JSON files - 18 tests covering schema parsing, store, i18n, events
196 lines
6.9 KiB
Swift
196 lines
6.9 KiB
Swift
import XCTest
|
|
@testable import SwiftBricks
|
|
|
|
final class SwiftBricksTests: XCTestCase {
|
|
|
|
// MARK: - Schema解析
|
|
|
|
func testParseSimpleSchema() throws {
|
|
let json = """
|
|
{
|
|
"widgettype": "Text",
|
|
"options": {
|
|
"text": "Hello World",
|
|
"i18n": false
|
|
}
|
|
}
|
|
"""
|
|
let data = json.data(using: .utf8)!
|
|
let schema = try JSONDecoder().decode(ControlSchema.self, from: data)
|
|
XCTAssertEqual(schema.widgettype, "Text")
|
|
XCTAssertEqual(schema.options.text, "Hello World")
|
|
XCTAssertEqual(schema.options.i18n, false)
|
|
}
|
|
|
|
func testParseVBoxWithSubwidgets() throws {
|
|
let json = """
|
|
{
|
|
"widgettype": "VBox",
|
|
"options": { "spacing": 10, "css": "card" },
|
|
"subwidgets": [
|
|
{ "widgettype": "Title2", "options": { "text": "标题" } },
|
|
{ "widgettype": "Text", "options": { "otext": "描述文本" } },
|
|
{ "widgettype": "Button", "id": "btn1", "options": { "label": "点击" },
|
|
"binds": [{ "wid": "self", "event": "click", "actiontype": "urlwidget",
|
|
"target": "content", "options": { "url": "/api/page.ui" } }] }
|
|
]
|
|
}
|
|
"""
|
|
let data = json.data(using: .utf8)!
|
|
let schema = try JSONDecoder().decode(ControlSchema.self, from: data)
|
|
XCTAssertEqual(schema.widgettype, "VBox")
|
|
XCTAssertEqual(schema.options.spacing, 10)
|
|
XCTAssertEqual(schema.subwidgets?.count, 3)
|
|
XCTAssertEqual(schema.subwidgets?[0].widgettype, "Title2")
|
|
XCTAssertEqual(schema.subwidgets?[2].binds?.count, 1)
|
|
XCTAssertEqual(schema.subwidgets?[2].binds?[0].actiontype, "urlwidget")
|
|
}
|
|
|
|
func testParseFormSchema() throws {
|
|
let json = """
|
|
{
|
|
"widgettype": "Form",
|
|
"options": {
|
|
"title": "用户信息",
|
|
"submit_url": "/api/submit.dspy",
|
|
"fields": [
|
|
{ "name": "username", "label": "用户名", "uitype": "str", "required": true,
|
|
"rules": [{ "type": "required", "message": "不能为空" }] },
|
|
{ "name": "role", "label": "角色", "uitype": "code",
|
|
"codes": [{"value": "admin", "text": "管理员"}, {"value": "user", "text": "普通用户"}] }
|
|
]
|
|
}
|
|
}
|
|
"""
|
|
let data = json.data(using: .utf8)!
|
|
let schema = try JSONDecoder().decode(ControlSchema.self, from: data)
|
|
XCTAssertEqual(schema.widgettype, "Form")
|
|
XCTAssertEqual(schema.options.fields?.count, 2)
|
|
XCTAssertEqual(schema.options.fields?[0].rules?.count, 1)
|
|
XCTAssertEqual(schema.options.fields?[1].codes?.count, 2)
|
|
}
|
|
|
|
func testParseTabularSchema() throws {
|
|
let json = """
|
|
{
|
|
"widgettype": "Tabular",
|
|
"options": {
|
|
"data_url": "/api/list.dspy",
|
|
"page_rows": 10,
|
|
"row_options": {
|
|
"fields": [
|
|
{ "name": "id", "label": "ID", "uitype": "str" },
|
|
{ "name": "name", "label": "名称", "uitype": "str" }
|
|
],
|
|
"browserfields": {
|
|
"exclouded": ["id"]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
let data = json.data(using: .utf8)!
|
|
let schema = try JSONDecoder().decode(ControlSchema.self, from: data)
|
|
XCTAssertEqual(schema.widgettype, "Tabular")
|
|
XCTAssertEqual(schema.options.page_rows, 10)
|
|
XCTAssertEqual(schema.options.row_options?.fields?.count, 2)
|
|
XCTAssertEqual(schema.options.row_options?.browserfields?.exclouded, ["id"])
|
|
}
|
|
|
|
// MARK: - ActionType验证
|
|
|
|
func testValidActionTypes() {
|
|
XCTAssertEqual(ActionType.allCases.count, 9)
|
|
XCTAssertNotNil(ActionType(rawValue: "urlwidget"))
|
|
XCTAssertNotNil(ActionType(rawValue: "urldata"))
|
|
XCTAssertNotNil(ActionType(rawValue: "method"))
|
|
XCTAssertNotNil(ActionType(rawValue: "event"))
|
|
XCTAssertNil(ActionType(rawValue: "fetch")) // 无效
|
|
XCTAssertNil(ActionType(rawValue: "ajax")) // 无效
|
|
}
|
|
|
|
// MARK: - WidgetType验证
|
|
|
|
func testWidgetTypeCategories() {
|
|
XCTAssertTrue(WidgetType.vbox.isLayout)
|
|
XCTAssertTrue(WidgetType.hbox.isLayout)
|
|
XCTAssertTrue(WidgetType.text.isText)
|
|
XCTAssertTrue(WidgetType.title2.isText)
|
|
XCTAssertTrue(WidgetType.input.isInput)
|
|
XCTAssertFalse(WidgetType.button.isLayout)
|
|
}
|
|
|
|
// MARK: - Store
|
|
|
|
@MainActor
|
|
func testStoreFormValues() {
|
|
let store = BricksStore()
|
|
store.setFormField(formId: "form1", field: "name", value: "Alice")
|
|
store.setFormField(formId: "form1", field: "email", value: "alice@test.com")
|
|
|
|
XCTAssertEqual(store.getFormField(formId: "form1", field: "name"), "Alice")
|
|
XCTAssertEqual(store.getFormField(formId: "form1", field: "email"), "alice@test.com")
|
|
|
|
let all = store.getFormValues(formId: "form1")
|
|
XCTAssertEqual(all.count, 2)
|
|
|
|
store.clearForm(formId: "form1")
|
|
XCTAssertEqual(store.getFormField(formId: "form1", field: "name"), "")
|
|
}
|
|
|
|
@MainActor
|
|
func testStoreTableData() {
|
|
let store = BricksStore()
|
|
let rows: [[String: Any]] = [
|
|
["id": "1", "name": "Alice"],
|
|
["id": "2", "name": "Bob"]
|
|
]
|
|
store.setTableData(id: "tbl1", rows: rows)
|
|
store.selectRow(tabularId: "tbl1", index: 1)
|
|
|
|
XCTAssertEqual(store.getTableData(id: "tbl1").count, 2)
|
|
XCTAssertEqual(store.getSelectedRow(tabularId: "tbl1"), 1)
|
|
let selected = store.getSelectedRowData(tabularId: "tbl1")
|
|
XCTAssertEqual(selected?["name"] as? String, "Bob")
|
|
}
|
|
|
|
// MARK: - I18n
|
|
|
|
@MainActor
|
|
func testI18nTranslation() {
|
|
let i18n = BricksI18n(locale: "en")
|
|
i18n.loadMessages([
|
|
"你好": "Hello",
|
|
"提交": "Submit"
|
|
])
|
|
|
|
XCTAssertEqual(i18n.t("你好"), "Hello")
|
|
XCTAssertEqual(i18n.t("提交"), "Submit")
|
|
XCTAssertEqual(i18n.t("未知"), "未知") // 未翻译返回原文
|
|
}
|
|
|
|
// MARK: - EventBus
|
|
|
|
@MainActor
|
|
func testEventBus() async {
|
|
let bus = BricksEventBus()
|
|
var received = false
|
|
|
|
bus.on("test.click") { _ in
|
|
received = true
|
|
}
|
|
|
|
await bus.dispatch("test.click")
|
|
XCTAssertTrue(received)
|
|
}
|
|
|
|
// MARK: - Engine模板替换
|
|
|
|
@MainActor
|
|
func testTemplateResolve() {
|
|
let engine = BricksEngine()
|
|
let result = engine.resolveTemplate("/api/detail.dspy?id=${id}$", params: ["id": "12345"])
|
|
XCTAssertEqual(result, "/api/detail.dspy?id=12345")
|
|
}
|
|
}
|