mirror of
https://github.com/divkit/divkit.git
synced 2026-05-07 20:02:32 +00:00
fix card variables case for div submit action
commit_hash:dc29ad2dd629fbe6e9466245569034abe343db18
This commit is contained in:
@@ -20945,6 +20945,7 @@
|
||||
"test_data/regression_test_data/state_binding.json":"divkit/public/test_data/regression_test_data/state_binding.json",
|
||||
"test_data/regression_test_data/states_default_state.json":"divkit/public/test_data/regression_test_data/states_default_state.json",
|
||||
"test_data/regression_test_data/stored_value.json":"divkit/public/test_data/regression_test_data/stored_value.json",
|
||||
"test_data/regression_test_data/submit_action.json":"divkit/public/test_data/regression_test_data/submit_action.json",
|
||||
"test_data/regression_test_data/svg_scale.json":"divkit/public/test_data/regression_test_data/svg_scale.json",
|
||||
"test_data/regression_test_data/tabs-item-actions.json":"divkit/public/test_data/regression_test_data/tabs-item-actions.json",
|
||||
"test_data/regression_test_data/tabs_disabled_switch_tabs_by_swipe.json":"divkit/public/test_data/regression_test_data/tabs_disabled_switch_tabs_by_swipe.json",
|
||||
|
||||
@@ -19,20 +19,14 @@ final class SubmitActionHandler {
|
||||
return
|
||||
}
|
||||
|
||||
let containers = context.variablesStorage.getVariables(
|
||||
guard let containerVariables = context.variablesStorage.getOnlyElementVariables(
|
||||
cardId: context.cardId,
|
||||
elementId: containerId
|
||||
)
|
||||
guard let container = containers.first else {
|
||||
DivKitLogger.error("Element with id \(containerId) not found")
|
||||
return
|
||||
}
|
||||
guard containers.count == 1 else {
|
||||
DivKitLogger.error("Found multiple elements that respond to id: \(containerId)")
|
||||
) else {
|
||||
return
|
||||
}
|
||||
|
||||
let containerData = container.map(
|
||||
let containerData = containerVariables.map(
|
||||
key: { $0.rawValue },
|
||||
value: { $0.toString() }
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Foundation
|
||||
import LayoutKit
|
||||
import VGSL
|
||||
|
||||
/// Stores variables.
|
||||
@@ -9,6 +10,7 @@ public final class DivVariableStorage {
|
||||
public let changedVariables: Set<DivVariableName>
|
||||
}
|
||||
|
||||
let initialPath: UIElementPath?
|
||||
private let outerStorage: DivVariableStorage?
|
||||
|
||||
private var _values = DivVariables()
|
||||
@@ -40,8 +42,18 @@ public final class DivVariableStorage {
|
||||
/// - outerStorage: Storage that provides outer scope variables. Outer scope variables are
|
||||
/// accessible via current storage (see `getValue` and `update` methods). Outer scope variables
|
||||
/// can be shadowed.
|
||||
public init(outerStorage: DivVariableStorage? = nil) {
|
||||
public convenience init(
|
||||
outerStorage: DivVariableStorage? = nil
|
||||
) {
|
||||
self.init(outerStorage: outerStorage, initialPath: nil)
|
||||
}
|
||||
|
||||
init(
|
||||
outerStorage: DivVariableStorage?,
|
||||
initialPath: UIElementPath?
|
||||
) {
|
||||
self.outerStorage = outerStorage
|
||||
self.initialPath = initialPath
|
||||
|
||||
if let outerStorage {
|
||||
changeEvents = Signal.merge(outerStorage.changeEvents, changeEventsPipe.signal)
|
||||
|
||||
@@ -43,7 +43,7 @@ public final class DivVariablesStorage {
|
||||
}
|
||||
|
||||
public init(outerStorage: DivVariableStorage?) {
|
||||
globalStorage = DivVariableStorage(outerStorage: outerStorage)
|
||||
globalStorage = DivVariableStorage(outerStorage: outerStorage, initialPath: nil)
|
||||
|
||||
let globalStorageEvents: Signal<ChangeEvent> = globalStorage.changeEvents.compactMap {
|
||||
ChangeEvent(.global($0.changedVariables))
|
||||
@@ -51,11 +51,26 @@ public final class DivVariablesStorage {
|
||||
changeEvents = Signal.merge(globalStorageEvents, changeEventsPipe.signal)
|
||||
}
|
||||
|
||||
func getVariables(cardId: DivCardID, elementId: String) -> [DivVariables] {
|
||||
func getOnlyElementVariables(cardId: DivCardID, elementId: String) -> DivVariables? {
|
||||
lock.withLock {
|
||||
localStorages.filter {
|
||||
let storages = localStorages.filter {
|
||||
$0.key.leaf == elementId && $0.key.cardId == cardId
|
||||
}.map(\.value.values)
|
||||
}.map(\.value)
|
||||
|
||||
guard let storage = storages.first else {
|
||||
DivKitLogger.error("Element with id \(elementId) not found")
|
||||
return nil
|
||||
}
|
||||
guard storages.count == 1 else {
|
||||
DivKitLogger.error("Found multiple elements that respond to id: \(elementId)")
|
||||
return nil
|
||||
}
|
||||
|
||||
guard storage.initialPath?.leaf == elementId else {
|
||||
return [:]
|
||||
}
|
||||
|
||||
return storage.values
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +117,7 @@ public final class DivVariablesStorage {
|
||||
// optimization that allows to access the local storage for one operation
|
||||
localStorages[path] = nearestStorage
|
||||
} else {
|
||||
let localStorage = DivVariableStorage(outerStorage: nearestStorage)
|
||||
let localStorage = DivVariableStorage(outerStorage: nearestStorage, initialPath: path)
|
||||
localStorage.replaceAll(variables, notifyObservers: false)
|
||||
localStorages[path] = localStorage
|
||||
}
|
||||
@@ -120,7 +135,7 @@ public final class DivVariablesStorage {
|
||||
if let localStorage = localStorages[path] {
|
||||
return localStorage
|
||||
}
|
||||
let localStorage = DivVariableStorage(outerStorage: globalStorage)
|
||||
let localStorage = DivVariableStorage(outerStorage: globalStorage, initialPath: path)
|
||||
localStorages[path] = localStorage
|
||||
return localStorage
|
||||
}
|
||||
|
||||
@@ -38,6 +38,10 @@ final class SubmitActionHandlerTests: XCTestCase {
|
||||
}
|
||||
|
||||
func test_Submit_ContainerWithoutVariables() {
|
||||
variablesStorage.initializeIfNeeded(
|
||||
path: cardId.path,
|
||||
variables: ["some_var": .string("some_value")]
|
||||
)
|
||||
variablesStorage.initializeIfNeeded(
|
||||
path: cardId.path + containerId,
|
||||
variables: [:]
|
||||
@@ -45,6 +49,7 @@ final class SubmitActionHandlerTests: XCTestCase {
|
||||
|
||||
handler.handleSubmit()
|
||||
|
||||
XCTAssertNotNil(submitter.lastRequest)
|
||||
XCTAssertTrue(submitter.lastData?.isEmpty == true)
|
||||
}
|
||||
|
||||
@@ -56,6 +61,7 @@ final class SubmitActionHandlerTests: XCTestCase {
|
||||
|
||||
handler.handleSubmit(containerId: "wrong_id")
|
||||
|
||||
XCTAssertNil(submitter.lastRequest)
|
||||
XCTAssertNil(submitter.lastData)
|
||||
}
|
||||
|
||||
|
||||
@@ -454,6 +454,68 @@ final class DivVariablesStorageTest: XCTestCase {
|
||||
XCTAssertNil(storage.getVariableValue(path: cardId.path + "element_id", name: "string_var"))
|
||||
}
|
||||
|
||||
func test_getOnlyElementVariables_nonEmptyElementVariables() {
|
||||
let cardVariables: DivVariables = [
|
||||
"some_card_var": .string("value"),
|
||||
]
|
||||
let elementVariables = variables
|
||||
let elementId = "element_id"
|
||||
storage.set(cardId: cardId, variables: cardVariables)
|
||||
storage.initializeIfNeeded(
|
||||
path: cardId.path + "some_container" + 0 + elementId,
|
||||
variables: elementVariables
|
||||
)
|
||||
|
||||
let result = storage.getOnlyElementVariables(cardId: cardId, elementId: elementId)
|
||||
|
||||
XCTAssertEqual(result, variables)
|
||||
}
|
||||
|
||||
func test_getOnlyElementVariables_noVariablesDeclaredAtPath() {
|
||||
let cardVariables = variables
|
||||
let elementVariables = DivVariables()
|
||||
let elementId = "element_id"
|
||||
storage.set(cardId: cardId, variables: cardVariables)
|
||||
storage.initializeIfNeeded(
|
||||
path: cardId.path + "some_container" + 0 + elementId,
|
||||
variables: elementVariables
|
||||
)
|
||||
|
||||
let result = storage.getOnlyElementVariables(cardId: cardId, elementId: elementId)
|
||||
|
||||
XCTAssertEqual(result, [:])
|
||||
}
|
||||
|
||||
func test_getOnlyElementVariables_multipleElementsWithSameId() {
|
||||
let elementId = "element_id"
|
||||
storage.set(cardId: cardId, variables: variables)
|
||||
storage.initializeIfNeeded(
|
||||
path: cardId.path + "some_container" + 0 + elementId,
|
||||
variables: variables
|
||||
)
|
||||
storage.initializeIfNeeded(
|
||||
path: cardId.path + "other_container" + 0 + elementId,
|
||||
variables: variables
|
||||
)
|
||||
|
||||
let result = storage.getOnlyElementVariables(cardId: cardId, elementId: elementId)
|
||||
|
||||
XCTAssertEqual(result, nil)
|
||||
}
|
||||
|
||||
func test_getOnlyElementVariables_noSuchElement() {
|
||||
let elementId = "non_existing_element_id"
|
||||
storage.set(cardId: cardId, variables: variables)
|
||||
storage.initializeIfNeeded(
|
||||
path: cardId.path + "some_container" + 0 + "other_id",
|
||||
variables: variables
|
||||
)
|
||||
|
||||
let result = storage.getVariableValue(cardId: cardId, name: .init(rawValue: elementId))
|
||||
|
||||
XCTAssertEqual(result, nil)
|
||||
}
|
||||
|
||||
private func getVariable<T>(_ name: DivVariableName) -> T? {
|
||||
storage.getVariableValue(cardId: cardId, name: name)
|
||||
}
|
||||
|
||||
@@ -3786,6 +3786,30 @@
|
||||
"Only last tap doesn't affect input focus"
|
||||
],
|
||||
"file": "input_capture_focus.json"
|
||||
},
|
||||
{
|
||||
"title": "Submit action test",
|
||||
"case_id": 221,
|
||||
"platforms": [
|
||||
"android",
|
||||
"ios",
|
||||
"web"
|
||||
],
|
||||
"tags": [
|
||||
"DivAction",
|
||||
"TypedActions"
|
||||
],
|
||||
"steps": [
|
||||
"Tap the 'Submit Form' button",
|
||||
"Enter a different URL in the API endpoint field",
|
||||
"Tap the 'Submit Form' button"
|
||||
],
|
||||
"expected_results": [
|
||||
"Form data is submitted to the specified endpoint",
|
||||
"Status changes to 'Form submitted successfully' on successful submission",
|
||||
"Status changes to 'Form submission failed' on failed submission"
|
||||
],
|
||||
"file": "submit_action.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
{
|
||||
"description": "Submit action test",
|
||||
"platforms": [
|
||||
"android",
|
||||
"ios",
|
||||
"web"
|
||||
],
|
||||
"card": {
|
||||
"log_id": "submit_action_test",
|
||||
"variables": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "submit_status",
|
||||
"value": "Not submitted"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "request_url",
|
||||
"value": "https://httpbin.org/post"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "progress",
|
||||
"value": false
|
||||
}
|
||||
],
|
||||
"states": [
|
||||
{
|
||||
"state_id": 0,
|
||||
"div": {
|
||||
"type": "container",
|
||||
"orientation": "vertical",
|
||||
"width": {
|
||||
"type": "match_parent"
|
||||
},
|
||||
"height": {
|
||||
"type": "wrap_content"
|
||||
},
|
||||
"paddings": {
|
||||
"top": 16,
|
||||
"bottom": 16,
|
||||
"left": 16,
|
||||
"right": 16
|
||||
},
|
||||
"background": [
|
||||
{
|
||||
"type": "solid",
|
||||
"color": "#FFFFFF"
|
||||
}
|
||||
],
|
||||
"items": [
|
||||
{
|
||||
"type": "text",
|
||||
"font_size": 24,
|
||||
"font_weight": "bold",
|
||||
"text": "Submit Form Test",
|
||||
"paddings": {
|
||||
"bottom": 16
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"font_size": 16,
|
||||
"font_weight": "bold",
|
||||
"text": "API Endpoint URL:",
|
||||
"paddings": {
|
||||
"bottom": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "input",
|
||||
"font_size": 16,
|
||||
"hint_text": "Enter API URL",
|
||||
"hint_color": "#AAAAAA",
|
||||
"text_color": "#000000",
|
||||
"text_variable": "request_url",
|
||||
"width": {
|
||||
"type": "match_parent"
|
||||
},
|
||||
"height": {
|
||||
"type": "wrap_content"
|
||||
},
|
||||
"paddings": {
|
||||
"top": 8,
|
||||
"bottom": 8,
|
||||
"left": 12,
|
||||
"right": 12
|
||||
},
|
||||
"margins": {
|
||||
"bottom": 16
|
||||
},
|
||||
"border": {
|
||||
"corner_radius": 8,
|
||||
"stroke": {
|
||||
"color": "#CCCCCC",
|
||||
"width": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "container",
|
||||
"orientation": "vertical",
|
||||
"width": {
|
||||
"type": "match_parent"
|
||||
},
|
||||
"height": {
|
||||
"type": "wrap_content"
|
||||
},
|
||||
"border": {
|
||||
"corner_radius": 8,
|
||||
"stroke": {
|
||||
"color": "#EEEEEE",
|
||||
"width": 1
|
||||
}
|
||||
},
|
||||
"paddings": {
|
||||
"top": 16,
|
||||
"bottom": 16,
|
||||
"left": 16,
|
||||
"right": 16
|
||||
},
|
||||
"margins": {
|
||||
"bottom": 16
|
||||
},
|
||||
"id": "form_container",
|
||||
"variables": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "name",
|
||||
"value": "John Doe"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "email",
|
||||
"value": "john.doe@example.com"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"name": "form_data",
|
||||
"value": {
|
||||
"name": "John Doe",
|
||||
"email": "john.doe@example.com"
|
||||
}
|
||||
}
|
||||
],
|
||||
"items": [
|
||||
{
|
||||
"type": "text",
|
||||
"font_size": 16,
|
||||
"font_weight": "bold",
|
||||
"text": "Name:",
|
||||
"paddings": {
|
||||
"bottom": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"font_size": 16,
|
||||
"text": "@{name}",
|
||||
"paddings": {
|
||||
"bottom": 16
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"font_size": 16,
|
||||
"font_weight": "bold",
|
||||
"text": "Email:",
|
||||
"paddings": {
|
||||
"bottom": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"font_size": 16,
|
||||
"text": "@{email}",
|
||||
"paddings": {
|
||||
"bottom": 16
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"font_size": 16,
|
||||
"font_weight": "bold",
|
||||
"text_color": "#FFFFFF",
|
||||
"text": "Submit Form",
|
||||
"paddings": {
|
||||
"top": 12,
|
||||
"bottom": 12,
|
||||
"left": 24,
|
||||
"right": 24
|
||||
},
|
||||
"background": [
|
||||
{
|
||||
"type": "solid",
|
||||
"color": "#4285F4"
|
||||
}
|
||||
],
|
||||
"border": {
|
||||
"corner_radius": 8
|
||||
},
|
||||
"width": {
|
||||
"type": "wrap_content"
|
||||
},
|
||||
"height": {
|
||||
"type": "fixed",
|
||||
"value": 44
|
||||
},
|
||||
"margins": {
|
||||
"bottom": 16
|
||||
},
|
||||
"visibility": "@{!progress ? 'visible' : 'invisible'}",
|
||||
"actions": [
|
||||
{
|
||||
"log_id": "set_progress_true",
|
||||
"url": "div-action://set_variable?name=progress&value=true"
|
||||
},
|
||||
{
|
||||
"log_id": "set_status_progress",
|
||||
"url": "div-action://set_variable?name=submit_status&value=progress"
|
||||
},
|
||||
{
|
||||
"log_id": "submit_form",
|
||||
"typed": {
|
||||
"type": "submit",
|
||||
"container_id": "form_container",
|
||||
"request": {
|
||||
"url": "@{request_url}",
|
||||
"method": "post",
|
||||
"headers": []
|
||||
},
|
||||
"on_success_actions": [
|
||||
{
|
||||
"log_id": "submit_success",
|
||||
"url": "div-action://set_variable?name=submit_status&value=Form%20submitted%20successfully"
|
||||
},
|
||||
{
|
||||
"log_id": "set_progress_false",
|
||||
"url": "div-action://set_variable?name=progress&value=false"
|
||||
}
|
||||
],
|
||||
"on_fail_actions": [
|
||||
{
|
||||
"log_id": "submit_fail",
|
||||
"url": "div-action://set_variable?name=submit_status&value=Form%20submission%20failed"
|
||||
},
|
||||
{
|
||||
"log_id": "set_progress_false",
|
||||
"url": "div-action://set_variable?name=progress&value=false"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"font_size": 16,
|
||||
"text": "Status: @{submit_status}",
|
||||
"paddings": {
|
||||
"top": 16
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user