diff --git a/lib/flow_runner.ex b/lib/flow_runner.ex index bb36103..be4f1c1 100644 --- a/lib/flow_runner.ex +++ b/lib/flow_runner.ex @@ -108,8 +108,8 @@ defmodule FlowRunner do end @impl FlowRunner.Contract - def evaluate_expression_block(expression, context) do - Expression.V2.Compat.evaluate_block!(expression, context, expression_callbacks_module()) + def evaluate_expression_block(expression, context, opts \\ []) do + Expression.V2.Compat.evaluate_block!(expression, context, expression_callbacks_module(), opts) end defdelegate fetch_resource_by_uuid(container, uuid), to: FlowRunner.Spec.Container diff --git a/lib/flow_runner/spec/blocks/select_one_response.ex b/lib/flow_runner/spec/blocks/select_one_response.ex index 7cf1bb2..a164e28 100644 --- a/lib/flow_runner/spec/blocks/select_one_response.ex +++ b/lib/flow_runner/spec/blocks/select_one_response.ex @@ -111,10 +111,14 @@ defmodule FlowRunner.Spec.Blocks.SelectOneResponse do block.config.choices |> Enum.with_index() |> Enum.find(fn {%{name: _name, test: test, prompt: _prompt}, _index} -> - FlowRunner.evaluate_expression_block(test, %{ - "flow" => flow, - "block" => %{"response" => user_input} - }) + FlowRunner.evaluate_expression_block( + test, + %{ + "flow" => flow, + "block" => %{"response" => user_input} + }, + skip_context_evaluation?: true + ) end) case result do diff --git a/lib/flow_runner/spec/exit.ex b/lib/flow_runner/spec/exit.ex index 9de4178..0e49d4d 100644 --- a/lib/flow_runner/spec/exit.ex +++ b/lib/flow_runner/spec/exit.ex @@ -34,7 +34,7 @@ defmodule FlowRunner.Spec.Exit do def evaluate(exit, context) do test = exit.test || "" - case FlowRunner.evaluate_expression_block(test, context.vars) do + case FlowRunner.evaluate_expression_block(test, context.vars, skip_context_evaluation?: true) do other when not is_boolean(other) -> Logger.info( "Expression '#{exit.test}' returned #{inspect(other)} when expecting a boolean last_block_uuid=#{context.last_block_uuid}" diff --git a/mix.exs b/mix.exs index 3879ec8..d0d8a8d 100644 --- a/mix.exs +++ b/mix.exs @@ -58,7 +58,7 @@ defmodule FlowRunner.MixProject do {:dialyxir, "~> 1.0", only: [:dev], runtime: false}, {:elixir_uuid, "~> 1.2"}, {:excoveralls, "~> 0.10", only: :test}, - {:expression, "~> 2.24"}, + {:expression, "~> 2.33"}, {:ex_doc, ">= 0.0.0", only: :dev, runtime: false}, {:jason, "~> 1.2"}, {:junit_formatter, "~> 3.1", only: [:test]}, diff --git a/mix.lock b/mix.lock index 3c12492..e25e9a7 100644 --- a/mix.lock +++ b/mix.lock @@ -10,11 +10,11 @@ "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, "elixir_uuid": {:hex, :elixir_uuid, "1.2.1", "dce506597acb7e6b0daeaff52ff6a9043f5919a4c3315abb4143f0b00378c097", [:mix], [], "hexpm", "f7eba2ea6c3555cea09706492716b0d87397b88946e6380898c2889d68585752"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "ex_doc": {:hex, :ex_doc, "0.31.1", "8a2355ac42b1cc7b2379da9e40243f2670143721dd50748bf6c3b1184dae2089", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "3178c3a407c557d8343479e1ff117a96fd31bafe52a039079593fb0524ef61b0"}, - "ex_phone_number": {:hex, :ex_phone_number, "0.4.3", "75767db14d8c6b1d40d49a912ca1e104a38b43e225458a8646d51f86cba2d835", [:mix], [{:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: false]}], "hexpm", "c14ad189a16ec410c7114eb7848e2ddf9b2a19ebb4e42c17870d0c68d811d972"}, + "ex_doc": {:hex, :ex_doc, "0.31.2", "8b06d0a5ac69e1a54df35519c951f1f44a7b7ca9a5bb7a260cd8a174d6322ece", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "317346c14febaba9ca40fd97b5b5919f7751fb85d399cc8e7e8872049f37e0af"}, + "ex_phone_number": {:hex, :ex_phone_number, "0.4.4", "8e994abe583496a3308cf56af013dca9b47a0424b0a9940af41cb0d66b848dd3", [:mix], [{:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: false]}], "hexpm", "a59875692ec57b3392959a7740f3e9a5cb08da88bcaee4efd480c770f5bb0f2c"}, "excoveralls": {:hex, :excoveralls, "0.18.0", "b92497e69465dc51bc37a6422226ee690ab437e4c06877e836f1c18daeb35da9", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1109bb911f3cb583401760be49c02cbbd16aed66ea9509fc5479335d284da60b"}, - "expo": {:hex, :expo, "0.5.1", "249e826a897cac48f591deba863b26c16682b43711dd15ee86b92f25eafd96d9", [:mix], [], "hexpm", "68a4233b0658a3d12ee00d27d37d856b1ba48607e7ce20fd376958d0ba6ce92b"}, - "expression": {:hex, :expression, "2.31.3", "816047abca2458d5c860b5611c8463474f7a513a746990b94f1e92f3be101cb7", [:mix], [{:ex_phone_number, "~> 0.4.1", [hex: :ex_phone_number, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:number, "~> 1.0", [hex: :number, repo: "hexpm", optional: false]}, {:timex, "~> 3.7", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "d6b5a47f976b25ff6ea2823ba4ff2e97a47625141a64c4f09d4836674511fd5c"}, + "expo": {:hex, :expo, "0.5.2", "beba786aab8e3c5431813d7a44b828e7b922bfa431d6bfbada0904535342efe2", [:mix], [], "hexpm", "8c9bfa06ca017c9cb4020fabe980bc7fdb1aaec059fd004c2ab3bff03b1c599c"}, + "expression": {:hex, :expression, "2.33.0", "3fd86ec7c16bec057bd3173c604318de0f731e4927b734556f75da5f99971b85", [:mix], [{:ex_phone_number, "~> 0.4.1", [hex: :ex_phone_number, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:number, "~> 1.0", [hex: :number, repo: "hexpm", optional: false]}, {:timex, "~> 3.7", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "d2337e767617b8997ab43f92b08249040c97da72e9b2fd955e2124c1ef5997b3"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, @@ -26,8 +26,8 @@ "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, "junit_formatter": {:hex, :junit_formatter, "3.3.1", "c729befb848f1b9571f317d2fefa648e9d4869befc4b2980daca7c1edc468e40", [:mix], [], "hexpm", "761fc5be4b4c15d8ba91a6dafde0b2c2ae6db9da7b8832a55b5a1deb524da72b"}, "makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.3", "d684f4bac8690e70b06eb52dad65d26de2eefa44cd19d64a8095e1417df7c8fd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "b78dc853d2e670ff6390b605d807263bf606da3c82be37f9d7f68635bd886fc9"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.5", "e0ff5a7c708dda34311f7522a8758e23bfcd7d8d8068dc312b5eb41c6fd76eba", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "94d2e986428585a21516d7d7149781480013c56e30c6a233534bedf38867a59a"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mix_test_watch": {:hex, :mix_test_watch, "1.1.2", "431bdccf20b110f1595fe2a0e3c6cffd96d8f706721def5d04d557bc0898c476", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "8ce79fc69a304eec81ab6c1a05de2eb026a8959f65fb47f933ce8eb56018ba35"}, diff --git a/priv/fixtures/test/buttons_then_routing.flow b/priv/fixtures/test/buttons_then_routing.flow new file mode 100644 index 0000000..352ebef --- /dev/null +++ b/priv/fixtures/test/buttons_then_routing.flow @@ -0,0 +1,330 @@ +{ + "specification_version": "1.0.0-rc3", + "uuid": "2894759f-7aa0-4875-8929-2c5999bee38d", + "name": "Journey 2", + "description": "Default description", + "flows": [ + { + "uuid": "9c0b42bf-ff0b-43f6-8423-2f7b6666efbd", + "name": "stack", + "label": null, + "last_modified": "2024-03-26T13:20:45.012220Z", + "interaction_timeout": 300, + "vendor_metadata": {}, + "supported_modes": [ + "RICH_MESSAGING" + ], + "first_block_id": "ddc1b3d7-f93f-513e-8990-5241821e700d", + "exit_block_id": "", + "languages": [ + { + "id": "d1c09571-c321-4e1d-8d68-efb7607abe26", + "iso_639_3": "eng", + "label": "English", + "variant": null, + "bcp_47": null + } + ], + "blocks": [ + { + "uuid": "37ce2c90-f5f7-5772-8464-b2a1553a78b8", + "name": "text_cf8c95_text", + "label": null, + "semantic_label": null, + "tags": [], + "type": "MobilePrimitives.Message", + "config": { + "prompt": "0413082a-9755-4731-8dd4-d93e8e878d8a" + }, + "exits": [ + { + "uuid": "6e45986e-e6bf-452f-b76c-679355661383", + "name": "text_cf8c95_text", + "destination_block": null, + "semantic_label": "", + "test": "", + "default": true, + "config": {}, + "vendor_metadata": {} + } + ] + }, + { + "uuid": "5827c3fd-5e31-594a-a5a5-e7c92c7210fd", + "name": "text_57cef1_text", + "label": null, + "semantic_label": null, + "tags": [], + "type": "MobilePrimitives.Message", + "config": { + "prompt": "c5606e1b-b0ca-45a1-8e48-5e633eb7f220" + }, + "exits": [ + { + "uuid": "f7caa007-92b4-4713-a83a-98f05cf212bd", + "name": "text_57cef1_text", + "destination_block": null, + "semantic_label": "", + "test": "", + "default": true, + "config": {}, + "vendor_metadata": {} + } + ] + }, + { + "uuid": "3dd88151-96d1-5e76-aad2-13d5f02b77ff", + "name": "reserved_default_card_text", + "label": null, + "semantic_label": null, + "tags": [], + "type": "MobilePrimitives.Message", + "config": { + "prompt": "11d5d8be-43d9-4e7f-baa3-18b972e51d01" + }, + "exits": [ + { + "uuid": "dee36a6f-69ac-481e-aacf-e31e50e4070b", + "name": "reserved_default_card_text", + "destination_block": null, + "semantic_label": "", + "test": "", + "default": true, + "config": {}, + "vendor_metadata": {} + } + ] + }, + { + "uuid": "be115dce-1f85-515c-9494-95bf3f00e87d", + "name": "text_4dd50b_text", + "label": null, + "semantic_label": null, + "tags": [], + "type": "MobilePrimitives.Message", + "config": { + "prompt": "ede492cb-7145-4843-af91-4036456f484a" + }, + "exits": [ + { + "uuid": "688c098a-6da7-4409-935c-8af3130c10fc", + "name": "text_4dd50b_text", + "destination_block": null, + "semantic_label": "", + "test": "", + "default": true, + "config": {}, + "vendor_metadata": {} + } + ] + }, + { + "uuid": "ddc1b3d7-f93f-513e-8990-5241821e700d", + "name": "ref_Buttons_7bef16", + "label": null, + "semantic_label": null, + "tags": [], + "type": "MobilePrimitives.SelectOneResponse", + "config": { + "prompt": "aa9d2ff7-0db2-44f9-8074-aece760795a5", + "choices": [ + { + "name": "True", + "prompt": "48e95d58-a623-46fd-93c7-0a2674111d1c", + "test": "block.response = \"True\"" + }, + { + "name": "2", + "prompt": "ae97bb77-8f80-4b93-b51f-d7b1e96e5eeb", + "test": "block.response = \"2\"" + }, + { + "name": "Button 3", + "prompt": "86271754-00e8-4f9f-bafb-68abdbb74350", + "test": "block.response = \"Button 3\"" + } + ] + }, + "exits": [ + { + "uuid": "bd90534c-7974-466a-a50d-532efd7104ea", + "name": "ref_Buttons_7bef16", + "destination_block": "528d89f0-7b69-5b93-9376-a6c41ac3ac22", + "semantic_label": "", + "test": "", + "default": true, + "config": {}, + "vendor_metadata": {} + } + ] + }, + { + "uuid": "528d89f0-7b69-5b93-9376-a6c41ac3ac22", + "name": "Routing for Buttons_7bef16", + "label": null, + "semantic_label": null, + "tags": [], + "type": "Core.Case", + "config": {}, + "exits": [ + { + "uuid": "dff8ba17-d73d-4607-91de-dca8b2ed8630", + "name": "Exit for Text_4dd50b", + "destination_block": "be115dce-1f85-515c-9494-95bf3f00e87d", + "semantic_label": null, + "test": "ref_Buttons_7bef16 == \"True\"", + "default": false, + "config": {}, + "vendor_metadata": {} + }, + { + "uuid": "dd605033-ef05-4edd-9170-1adb1a8c45a5", + "name": "Exit for Text_cf8c95", + "destination_block": "37ce2c90-f5f7-5772-8464-b2a1553a78b8", + "semantic_label": null, + "test": "ref_Buttons_7bef16 == \"2\"", + "default": false, + "config": {}, + "vendor_metadata": {} + }, + { + "uuid": "9eb3c26d-fb83-4784-99da-003e156279b3", + "name": "Exit for Text_57cef1", + "destination_block": "5827c3fd-5e31-594a-a5a5-e7c92c7210fd", + "semantic_label": null, + "test": "ref_Buttons_7bef16 == \"Button 3\"", + "default": false, + "config": {}, + "vendor_metadata": {} + }, + { + "uuid": "6c20dd20-92b4-4e53-b651-9d9c2a484fc2", + "name": "Routing for Buttons_7bef16", + "destination_block": null, + "semantic_label": "", + "test": "", + "default": true, + "config": {}, + "vendor_metadata": {} + } + ] + } + ] + } + ], + "resources": [ + { + "uuid": "0413082a-9755-4731-8dd4-d93e8e878d8a", + "values": [ + { + "language_id": "d1c09571-c321-4e1d-8d68-efb7607abe26", + "content_type": "TEXT", + "mime_type": "text/plain", + "modes": [ + "RICH_MESSAGING" + ], + "value": "You clicked button 2" + } + ] + }, + { + "uuid": "c5606e1b-b0ca-45a1-8e48-5e633eb7f220", + "values": [ + { + "language_id": "d1c09571-c321-4e1d-8d68-efb7607abe26", + "content_type": "TEXT", + "mime_type": "text/plain", + "modes": [ + "RICH_MESSAGING" + ], + "value": "You clicked button 3" + } + ] + }, + { + "uuid": "11d5d8be-43d9-4e7f-baa3-18b972e51d01", + "values": [ + { + "language_id": "d1c09571-c321-4e1d-8d68-efb7607abe26", + "content_type": "TEXT", + "mime_type": "text/plain", + "modes": [ + "RICH_MESSAGING" + ], + "value": "The button is not linked with any card. Please link a card to proceed." + } + ] + }, + { + "uuid": "ede492cb-7145-4843-af91-4036456f484a", + "values": [ + { + "language_id": "d1c09571-c321-4e1d-8d68-efb7607abe26", + "content_type": "TEXT", + "mime_type": "text/plain", + "modes": [ + "RICH_MESSAGING" + ], + "value": "You clicked button 1" + } + ] + }, + { + "uuid": "aa9d2ff7-0db2-44f9-8074-aece760795a5", + "values": [ + { + "language_id": "d1c09571-c321-4e1d-8d68-efb7607abe26", + "content_type": "TEXT", + "mime_type": "text/plain", + "modes": [ + "RICH_MESSAGING" + ], + "value": "Boolean buttons test" + } + ] + }, + { + "uuid": "48e95d58-a623-46fd-93c7-0a2674111d1c", + "values": [ + { + "language_id": "d1c09571-c321-4e1d-8d68-efb7607abe26", + "content_type": "TEXT", + "mime_type": "text/plain", + "modes": [ + "RICH_MESSAGING" + ], + "value": "True" + } + ] + }, + { + "uuid": "ae97bb77-8f80-4b93-b51f-d7b1e96e5eeb", + "values": [ + { + "language_id": "d1c09571-c321-4e1d-8d68-efb7607abe26", + "content_type": "TEXT", + "mime_type": "text/plain", + "modes": [ + "RICH_MESSAGING" + ], + "value": "2" + } + ] + }, + { + "uuid": "86271754-00e8-4f9f-bafb-68abdbb74350", + "values": [ + { + "language_id": "d1c09571-c321-4e1d-8d68-efb7607abe26", + "content_type": "TEXT", + "mime_type": "text/plain", + "modes": [ + "RICH_MESSAGING" + ], + "value": "Button 3" + } + ] + } + ], + "vendor_metadata": {} +} \ No newline at end of file diff --git a/test/flow_runner/spec/blocks/select_one_response_test.exs b/test/flow_runner/spec/blocks/select_one_response_test.exs new file mode 100644 index 0000000..9881018 --- /dev/null +++ b/test/flow_runner/spec/blocks/select_one_response_test.exs @@ -0,0 +1,153 @@ +defmodule FlowRunner.Spec.Blocks.SelectOneResponseTest do + use ExUnit.Case + import FlowRunner.Test.Utils + alias FlowRunner.Spec.Blocks.SelectOneResponse + + setup :with_flow_loader! + + @tag flow: "test/buttons_then_routing.flow" + test "evaluate_outgoing/5 selects the correct outgoing link when the user input is a string resembling a boolean", + %{container: container} do + [flow] = container.flows + + block = %FlowRunner.Spec.Block{ + uuid: "ddc1b3d7-f93f-513e-8990-5241821e700d", + name: "ref_Buttons_7bef16", + label: nil, + semantic_label: nil, + tags: [], + type: "MobilePrimitives.SelectOneResponse", + config: %{ + prompt: "aa9d2ff7-0db2-44f9-8074-aece760795a5", + choices: [ + %{ + name: "True", + prompt: "48e95d58-a623-46fd-93c7-0a2674111d1c", + test: "block.response = \"True\"" + }, + %{ + name: "2", + prompt: "ae97bb77-8f80-4b93-b51f-d7b1e96e5eeb", + test: "block.response = \"2\"" + }, + %{ + name: "Button 3", + prompt: "86271754-00e8-4f9f-bafb-68abdbb74350", + test: "block.response = \"Button 3\"" + } + ] + }, + exits: [ + %FlowRunner.Spec.Exit{ + uuid: "bd90534c-7974-466a-a50d-532efd7104ea", + name: "ref_Buttons_7bef16", + destination_block: "528d89f0-7b69-5b93-9376-a6c41ac3ac22", + semantic_label: "", + test: "", + default: true, + config: %{}, + vendor_metadata: %{} + } + ] + } + + context = %FlowRunner.Context{ + language: "eng", + mode: "RICH_MESSAGING", + log: [], + waiting_for_user_input: true, + current_flow_uuid: "9c0b42bf-ff0b-43f6-8423-2f7b6666efbd", + last_block_uuid: "ddc1b3d7-f93f-513e-8990-5241821e700d", + vars: %{ + "flow" => %{ + "__value__" => "9c0b42bf-ff0b-43f6-8423-2f7b6666efbd", + "uuid" => "9c0b42bf-ff0b-43f6-8423-2f7b6666efbd" + } + }, + private: %{}, + finished: false, + waiting_for_child_flow: false, + child_flow_uuid: nil, + parent_flow_uuid: nil, + parent_state_uuid: nil + } + + user_input = "True" + + assert {:ok, %{"__value__" => "True", "index" => 0, "label" => "True", "name" => "True"}} = + SelectOneResponse.evaluate_outgoing(container, flow, block, context, user_input) + end + + @tag flow: "test/buttons_then_routing.flow" + test "evaluate_outgoing/5 selects the correct outgoing link when the user input is a string resembling a number", + %{container: container} do + [flow] = container.flows + + block = %FlowRunner.Spec.Block{ + uuid: "ddc1b3d7-f93f-513e-8990-5241821e700d", + name: "ref_Buttons_7bef16", + label: nil, + semantic_label: nil, + tags: [], + type: "MobilePrimitives.SelectOneResponse", + config: %{ + prompt: "aa9d2ff7-0db2-44f9-8074-aece760795a5", + choices: [ + %{ + name: "True", + prompt: "48e95d58-a623-46fd-93c7-0a2674111d1c", + test: "block.response = \"True\"" + }, + %{ + name: "2", + prompt: "ae97bb77-8f80-4b93-b51f-d7b1e96e5eeb", + test: "block.response = \"2\"" + }, + %{ + name: "Button 3", + prompt: "86271754-00e8-4f9f-bafb-68abdbb74350", + test: "block.response = \"Button 3\"" + } + ] + }, + exits: [ + %FlowRunner.Spec.Exit{ + uuid: "bd90534c-7974-466a-a50d-532efd7104ea", + name: "ref_Buttons_7bef16", + destination_block: "528d89f0-7b69-5b93-9376-a6c41ac3ac22", + semantic_label: "", + test: "", + default: true, + config: %{}, + vendor_metadata: %{} + } + ] + } + + context = %FlowRunner.Context{ + language: "eng", + mode: "RICH_MESSAGING", + log: [], + waiting_for_user_input: true, + current_flow_uuid: "9c0b42bf-ff0b-43f6-8423-2f7b6666efbd", + last_block_uuid: "ddc1b3d7-f93f-513e-8990-5241821e700d", + vars: %{ + "flow" => %{ + "__value__" => "9c0b42bf-ff0b-43f6-8423-2f7b6666efbd", + "uuid" => "9c0b42bf-ff0b-43f6-8423-2f7b6666efbd" + } + }, + private: %{}, + finished: false, + waiting_for_child_flow: false, + child_flow_uuid: nil, + parent_flow_uuid: nil, + parent_state_uuid: nil + } + + user_input = "2" + + assert {:ok, %{"__value__" => "2", "index" => 1, "label" => "2", "name" => "2"}} = + SelectOneResponse.evaluate_outgoing(container, flow, block, context, user_input) + end +end diff --git a/test/flow_runner/spec/exit_test.exs b/test/flow_runner/spec/exit_test.exs new file mode 100644 index 0000000..e8750b9 --- /dev/null +++ b/test/flow_runner/spec/exit_test.exs @@ -0,0 +1,45 @@ +defmodule FlowRunner.Spec.ExitTest do + use ExUnit.Case + alias FlowRunner.Spec.Exit + + test "Exit matching a string containing a numeric value" do + assert Exit.evaluate( + %Exit{ + uuid: "dd605033-ef05-4edd-9170-1adb1a8c45a5", + name: "Exit for Text_cf8c95", + destination_block: "37ce2c90-f5f7-5772-8464-b2a1553a78b8", + semantic_label: nil, + test: "ref_Buttons_7bef16 == \"2\"", + default: false, + config: %{}, + vendor_metadata: %{} + }, + %{vars: %{"ref_Buttons_7bef16" => "2"}} + ) + end + + test "Exit matching a string containing a boolean-ish value" do + assert Exit.evaluate( + %Exit{ + uuid: "dff8ba17-d73d-4607-91de-dca8b2ed8630", + name: "Exit for Text_4dd50b", + destination_block: "be115dce-1f85-515c-9494-95bf3f00e87d", + semantic_label: nil, + test: "ref_Buttons_7bef16 == \"True\"", + default: false, + config: %{}, + vendor_metadata: %{} + }, + %{ + vars: %{ + "ref_Buttons_7bef16" => %{ + "__value__" => "True", + "index" => 0, + "label" => "True", + "name" => "True" + } + } + } + ) + end +end diff --git a/test/flow_runner_test.exs b/test/flow_runner_test.exs index 064ab30..452298a 100644 --- a/test/flow_runner_test.exs +++ b/test/flow_runner_test.exs @@ -516,4 +516,62 @@ defmodule FlowRunnerTest do assert {:end, _container, _flow, _block, _context} = FlowRunner.next_block(container, context) end + + describe "The `skip_context_evaluation?` flag works as expected when evaluating Expression blocks" do + test "string values in context that resemble booleans should not be parsed as booleans" do + # Right now the Expression package always tries to parse boolean-ish strings into actual booleans, + # which breaks the evaluation of comparisons like the following one (which returns `false` instead of `true`): + assert false == + FlowRunner.evaluate_expression_block( + "block.response = \"True\"", + %{ + "block" => %{"response" => "True"} + } + ) + + # When evaluating Block exits we don't want Expression to transform the context. + # The `skip_context_evaluation?` flag should prevent that: + assert true == + FlowRunner.evaluate_expression_block( + "block.response = \"True\"", + %{ + "block" => %{"response" => "True"} + }, + skip_context_evaluation?: true + ) + end + + test "string values in context that resemble numbers should not be parsed as numbers" do + # Right now the Expression package always tries to parse number-ish strings into actual numbers, + # which breaks the evaluation of comparisons like the following one (which returns `false` instead of `true`): + assert false == + FlowRunner.evaluate_expression_block( + "ref_Buttons_7bef16 == \"2\"", + %{ + "ref_Buttons_7bef16" => %{ + "__value__" => "2", + "index" => 1, + "label" => "2", + "name" => "2" + } + } + ) + + # When evaluating Block exits we don't want Expression to transform the context. + # The `skip_context_evaluation?` flag should prevent that: + assert true == + FlowRunner.evaluate_expression_block( + "ref_Buttons_7bef16 == \"2\"", + %{ + "ref_Buttons_7bef16" => %{ + "__value__" => "2", + "index" => 1, + "label" => "2", + "name" => "2" + } + }, + skip_context_evaluation?: true + ) + end + end end